6 Replies
      Latest reply on Jun 25, 2019 7:24 AM by Userfromcharlotte
      Userfromcharlotte Level 1 Level 1 (0 points)

        I'm trying to generate RSA private-public(kSecAttrKeyTypeRSA) keypair with access control.

        Below code works fine when i just set "kSecAccessControlTouchIDCurrentSet" in access control flags. Private-Public Keys are generated and when i'm trying to access Private Key, I'm getting the TouchID/ FaceID prompt when i call "SecItemCopyMatching". This works fine.

         

        But if i set "kSecAccessControlPrivateKeyUsage" or "kSecAccessControlTouchIDCurrentSet | kSecAccessControlPrivateKeyUsage", SecKeyGeneratePair returns "-25293".

         

        I am not using the SecureEnclave option as I want to generate RSA keys.

         

        Can you please let me know the importance of  "kSecAccessControlPrivateKeyUsage" while setting access control and when should it be used .?

        Does it not work for RSA keys ?

         

        SecAccessControlRef sacRef;
            CFErrorRef err = NULL;
                //Gets our Security Access Control ref for user presence policy (requires user AuthN)
        sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                                     kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,kSecAccessControlTouchIDCurrentSet | kSecAccessControlPrivateKeyUsage,
                                                     &err);
        CurrentSet | kSecAccessControlPrivateKeyUsage,
           NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
        
        
            NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
            NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];
        
                // Set top level dictionary for the keypair.
            [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
            [keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:2048] forKey:(__bridge id)kSecAttrKeySizeInBits];
            [keyPairAttr setObject:(__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
        
                // Set the private key dictionary.
            [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
            [privateKeyAttr setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
            [privateKeyAttr setObject:(__bridge_transfer id)sacRef forKey:(__bridge id)kSecAttrAccessControl];
        
                // Set the public key dictionary.
            [publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
            [publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
        
            // Set attributes to top level dictionary.
            [keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
            [keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
            
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                OSStatus sanityCheck = noErr;
                SecKeyRef publicKey = NULL;
                SecKeyRef privateKey = NULL;
                
            sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
        • Re: SecKeyGeneratePair returns -25293 with kSecAccessControlPrivateKeyUsage and  kSecAttrKeyTypeRSA
          eskimo Apple Staff Apple Staff (12,425 points)

          Two things:

          • You’re on iOS, right?  Most (all?) of what you discuss is available on macOS as well, so I just want to be clear.

          • I’m going to recommend that you switch to SecKeyCreateRandomKey.  It has a bunch of advantages of SecKeyGeneratePair, not least of which is that it only generates one key (you can get the public key from that private key via SecKeyCopyPublicKey) and thus the whole access control story is a lot simpler.

          Share and Enjoy

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

            • Re: SecKeyGeneratePair returns -25293 with kSecAccessControlPrivateKeyUsage and  kSecAttrKeyTypeRSA
              Userfromcharlotte Level 1 Level 1 (0 points)

              Hello Eskimo,

               

              1.It's for iOS.

              2. I did try out using SecKeyCreateRandomKey. But that gives the same -25293 status if i try with the combination of using "kSecAccessControlPrivateKeyUsage" in accessControlFlags. But if i remove setting this accessControl flag, code works fine and generates private key.

               

              Again, I'm trying to generate RSA keys (so keytype is kSecAttrKeyTypeRSA). So, i can't be using the option of kSecAttrTokenIDSecureEnclave.

              1. My question was to know the significance of "kSecAccessControlPrivateKeyUsage" in access control flags and should it be set only when we use SecureEnclave as clearly it isn't working for RSA keys? Didn't find any documentation on it.

               

              2.With just setting access control flag with kSecAccessControlTouchIDCurrentSet, I'm able to generate private key and when i try to access the key through SecItemCopyMatching, I'm seeing the TouchID/ FaceID prompt.

              So, what additional advantage/ security does setting access control as below (kSecAccessControlTouchIDCurrentSet | kSecAccessControlPrivateKeyUsage) gives.?

              sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                                              kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                                              kSecAccessControlTouchIDCurrentSet | kSecAccessControlPrivateKeyUsage, &error);
              
              

               

              3. You recommended using SecKeyCreateRandomKey over "SecKeyGeneratePair". I get that, using it is a lot simpler than SecGeneratePair. In my usecase, I already have code for SecGeneratePair and I'm just trying to protect the keys with accessControl so that user will be prompted with Biometrics when we try to access the key.

              Based on documentation for "SecKeyGeneratePair", it just talks about "kSecAttrIsPermanent" which isn't respected on MacOS. As i want to store the key in keychain, i believe the behavior is same on iOS, macOS, tvOS and watchOS.

              Apart from this, what other advantages does using SecKeyCreateRandomKey provides ? Is SecKeyGeneratePair any weaker with respect to Security ?

               

               NOTE: The function always saves keys in the keychain on macOS and as such attribute
                  kSecAttrIsPermanent is ignored. The function respects attribute kSecAttrIsPermanent
                  on iOS, tvOS and watchOS.
                • Re: SecKeyGeneratePair returns -25293 with kSecAccessControlPrivateKeyUsage and  kSecAttrKeyTypeRSA
                  eskimo Apple Staff Apple Staff (12,425 points)

                  Is SecKeyGeneratePair any weaker with respect to Security ?

                  No.  It’s just a better, easier to understand API.

                  If you temporarily switch the key type to EC, does kSecAccessControlPrivateKeyUsage then work as you expect?

                  Share and Enjoy

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

                    • Re: SecKeyGeneratePair returns -25293 with kSecAccessControlPrivateKeyUsage and  kSecAttrKeyTypeRSA
                      Userfromcharlotte Level 1 Level 1 (0 points)

                      Hi Eskimo,

                       

                      Just updating the keyType to kSecAttrKeyTypeEC or kSecAttrKeyTypeECSECPrimeRandom still gives the error (-25293).

                      But if I update both keyType and kSecAttrTokenID (kSecAttrTokenIDSecureEnclave), code works fine. Below is the snippet

                       

                       sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                                                      kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                                                      kSecAccessControlTouchIDCurrentSet | kSecAccessControlPrivateKeyUsage, &error);
                          
                              // Create parameters dictionary for key generation.
                          NSDictionary *parameters = @{
                                                       //(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
                                                       (id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave,
                                                       (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
                                                       (id)kSecAttrKeySizeInBits: @256,
                                                       (id)kSecAttrLabel: @"my-se-key",
                                                       (id)kSecPrivateKeyAttrs: @{
                                                               (id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,
                                                               (id)kSecAttrIsPermanent: @YES,
                                                               }
                                                       };
                      

                      I believe "kSecAccessControlPrivateKeyUsage" only works with setting TokenID set as "kSecAttrTokenIDSecureEnclave".

                       

                      So, in my use case of RSA keyPair, I'm generating the keypair which are stored in keychain and when i try to access the key, i get the TouchID/ FaceID prompt since I'm using the access control flag "kSecAccessControlTouchIDCurrentSet".

                       

                      What actually is "kSecAccessControlPrivateKeyUsage"  for ? and even if it works only with Secure enclave, why should we set that value ?