5 Replies
      Latest reply: Feb 16, 2017 1:20 AM by eskimo RSS
      gaussblurinc Level 1 Level 1 (0 points)

        I have a function that get import RSA keys.

         

         

        + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error; {
            NSString *keyClass = (__bridge NSString *)(public ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate);
            NSInteger sizeInBits = data.length;
            NSDictionary *attributes = @{
                (__bridge NSString*)kSecAttrKeyType : type,
                (__bridge NSString*)kSecAttrKeyClass : keyClass,
                (__bridge NSString*)kSecAttrKeySizeInBits : @(sizeInBits)
            };
            
            if (SecKeyCreateWithData != NULL) {
                CFErrorRef createError = NULL;
                SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)attributes, &createError);
                if (error && createError != nil) {
                    *error = (__bridge NSError*)createError;
                }
                return key;
            }
            / 
            else {
                CFTypeRef result = NULL;
                NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding];
                NSDictionary *commonAttributes = @{
                    (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey,
                    (__bridge NSString*)kSecAttrApplicationTag: tagData,
                    (__bridge NSString*)kSecAttrAccessible: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked
                };
                NSDictionary *addItemAttributes = @{
                   (__bridge NSString*)kSecValueData: data,
                   (__bridge NSString*)kSecReturnPersistentRef: @(YES),
                };
                OSStatus addItemStatus = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, addItemAttributes]], &result);
                if (addItemStatus != errSecSuccess && addItemStatus != errSecDuplicateItem) {
                    / 
                    / 
                    return NULL;
                }
                NSDictionary *copyAttributes = @{
                        (__bridge NSString*)kSecReturnRef: @(YES),
                };
                CFTypeRef key = NULL;
                / 
                OSStatus copyItemStatus = errSecSuccess;
                SecItemCopyMatching((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, copyAttributes]], &key);
                if (key == NULL) {
                    / 
                }
                return (SecKeyRef)key;
            }
            return NULL;
        }
        
        

         

        I try to adjust it to get kSecAttrKeyTypeECSECPrimeRandom keys.


        Input data is base64 data:

        -----BEGIN PUBLIC KEY-----
        MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc
        /DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
        -----END PUBLIC KEY-----
        
        

         

        Here data is

        NSString *urlEncodedString = @"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==";
        NSData *data = [[NSData alloc] initWithBase64EncodedString:urlEncodedString options:0];
        
        

         

        For private key:

        -----BEGIN EC PARAMETERS-----
        BggqhkjOPQMBBw==
        -----END EC PARAMETERS-----
        -----BEGIN EC PRIVATE KEY-----
        MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49
        AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9
        MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
        -----END EC PRIVATE KEY-----
        
        

         

        Data is

        NSString *urlEncodedString = @"
        MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==";
        NSData *data = [[NSData alloc] initWithBase64EncodedString:urlEncodedString options:0];
        
        

         

        Function invocation is

         

        NSData *data = [self getKeyFromPemFile];
        BOOL public = public; // YES or NO
        NSString *tag = (__bridge NSString*)kSecAttrKeyTypeECSECPrimeRandom;
        NSError *error = nil;
        NSString *tag = [NSUUID UUID].UUIDString;
        [self addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:tag type:type error:error;
        
        

         

        And error is

        Error Domain=NSOSStatusErrorDomain Code=-50 "EC public key creation from data failed" UserInfo={NSDescription=EC public key creation from data failed}
        
        

         

        ( Error occures on mac/iOS simulator )

        • Re: How to import ec pem-encoded public/private keys?
          eskimo Apple Staff Apple Staff (6,270 points)

          The bad news is that importing and exporting private keys in this way is not supported.  It works, kinda, but that’s more an accident of the implementation than as properly designed API.  I’m not surprised you’re having problems with EC keys.

          The recommended way to import a key on older versions of iOS is via a PKCS#12.

          The good news is that iOS 10 introduced a new API for importing and exporting keys, namely SecKeyCreateWithData and SecKeyCopyExternalRepresentation.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: How to import ec pem-encoded public/private keys?
              gaussblurinc Level 1 Level 1 (0 points)

              I run tests on iOS Simulator ( iOS SDK 10 ).
              Function should ( due to weak linking ) choose condition branch with SecKeyCreateWithData. ( And it choose ).
              However, I still have a problems with improting keys.

               

              What data and what attributes dictionary expect SecKeyCreateWithData for EC key? ( Public or Private )

              Maybe I am incorrect in attributes?

                • Re: How to import ec pem-encoded public/private keys?
                  eskimo Apple Staff Apple Staff (6,270 points)

                  Quoting the header comments for SecKeyCreateWithData:

                  Mandatory attributes are:
                  
                  * kSecAttrKeyType
                  * kSecAttrKeyClass
                  * kSecAttrKeySizeInBits
                  

                  and:

                  The requested data format depend on the type of key
                  (kSecAttrKeyType) being created:
                  
                  * kSecAttrKeyTypeRSA              PKCS#1 format
                  * kSecAttrKeyTypeECSECPrimeRandom  SEC1 format (www.secg.org)
                  

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: How to import ec pem-encoded public/private keys?
                      gaussblurinc Level 1 Level 1 (0 points)

                      Well, I still have problems with SecKeyCreateWithData

                      As I understand correctly, SEC1 format is an internal format for keys. It is a binary wrapper for EC keys.

                      These keys are presented in file format, for example, in PEM file.

                       

                      Next, if I am correctly understand 'errors', it seems that openssl tool doesn't generate pure SEC1. Key should be polished ( headers removed, for example ) before passing to SecKeyCreateWithData.

                      I suppose that somekind of header ( binary format header ) prevents SecKeyCreateWithData from creating correct key.

                      Passing keys 'as is' to SecKeyCreateWithData errored with the same error, so, one sequence of bytes could be a reason why it happens. Header could be a candidate for it. It exists in both keys, for example.

                       

                       

                      However, I generate keys with these commands. ( Which are incompatible 'as is' with SecKeyCreateWithData, they are incorrect without postprocessing (removing somekind of header, for example) ).

                      # generate ecdsa private key.
                      openssl ecparam -genkey -name prime256v1  -out ec256-private.pem
                      # generate ecdsa public key.
                      openssl ec -in ec256-private.pem -pubout -out ec256-public.pem
                      
                      
                      
                      
                        • Re: How to import ec pem-encoded public/private keys?
                          eskimo Apple Staff Apple Staff (6,270 points)

                          The output of your commands is a PEM, a text file as shown below.

                          $ cat ec256-public.pem
                          -----BEGIN PUBLIC KEY-----
                          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0izAMfQ7xhdrx07MziByyh4CbTgb
                          Q0KYt0zSgNyrz1Re78e9m7FYDES95y/f5zZ1HSmq0+h4LJRmcpV0BXethA==
                          -----END PUBLIC KEY-----
                          

                          If you strip the PEM markers (the first and last line), you get Base64-encoded ASN.1 data.  You can decide this as follows:

                          $ base64 -D < ec256-public.b64 > ec256-public.asn1
                          $ dumpasn1 -p ec256-public.asn1
                          SEQUENCE {
                            SEQUENCE {
                              OBJECT IDENTIFIER '1 2 840 10045 2 1'
                              OBJECT IDENTIFIER ansiX9p256r1 (1 2 840 10045 3 1 7)
                              }
                            BIT STRING
                              04 D2 2C C0 31 F4 3B C6 17 6B C7 4E CC CE 20 72
                              CA 1E 02 6D 38 1B 43 42 98 B7 4C D2 80 DC AB CF
                              54 5E EF C7 BD 9B B1 58 0C 44 BD E7 2F DF E7 36
                              75 1D 29 AA D3 E8 78 2C 94 66 72 95 74 05 77 AD
                              84
                            }
                          

                          Note You can get dumpasn1 from here.

                          This is an ASN.1 SubjectPublicKeyInfo structure, where the stuff before the BIT STRING is a header identifying the type of key, and the stuff inside the BIT STRING is the raw key itself.  For more details, read this post.

                          I believe, but haven’t tested, that SecKeyCreateWithData wants the raw key.  One way to test whether that’s the case is to generate an EC key on iOS (using SecKeyGeneratePair) and then export it using SecKeyCopyExternalRepresentation.  If the data looks like the contents of the BIT STRING shown above, you’re on the right track.

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"