SecKeyGeneratePair returns -25293 with kSecAccessControlPrivateKeyUsage and kSecAttrKeyTypeRSA

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);

Replies

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"

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.

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"

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 ?

What actually is

kSecAccessControlPrivateKeyUsage
for?

Well, that’s a good question (-: It turns out that its documentation is quite good: It configures the access control object to be appropriate for a digital signature private key rather than decryption private key.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you, Eskimo.! So, kSecAccessControlPrivateKeyUsage is supposed to be used only for Secure Enclave items. I some how missed this and was thinking to use it for RSA key which can't be used in secure enclave at all.