How to set kSecAttrIsExtractable when calling SecKeyCreateRandomKey?

My code called SecKeyCreateRandomKey() to generate a RSA private key. I want this generated key cannot be exportable. So I set kSecAttrIsExtractable to @NO. But I am still able to export the private key.


What should I set to make the newly generated private key not exportable or extractable?


My sample code:


NSDictionary* attributes =

@{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,

(id)kSecAttrKeySizeInBits: @2048,

(id)kSecUseKeychain: (__bridge id)keychainRef,

(id)kSecPrivateKeyAttrs:

@{ (id)kSecAttrIsPermanent: @YES,

(id)kSecAttrIsExtractable: @NO,

(id)kSecAttrCanDerive: @NO,

},

};


CFErrorRef error = NULL;

SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes,

if(privateKey) {

CFDataRef exportPrivateKeyData = NULL;

OSStatus result = SecItemExport(privateKey, kSecFormatUnknown, 0, NULL, &exportPrivateKeyData);

Note: SecItemExport() return errSecSuccess (0) and the exportPrivateKeyData contains data. I was hoping the SecItemExport() will fail since kSecAttrIsExtractable was set to @NO when generating the private key.

Replies

But I am still able to export the private key.

Is this macOS or iOS?

Share and Enjoy

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

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

macOS 10.13.6.

Hmmm, interesting. In my experience macOS (specifically, the file-based keychain) is pretty enthusiastic about making keys non-extractable, so I’m surprised this doesn’t happen by default (that is, even without you setting `kSecAttrIsExtractable).

For a quick experiment, can you trying doing this with the now-deprecated

SecKeyGeneratePair
?

Share and Enjoy

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

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

Thanks. I tried

SecKeyGeneratePair and but it behaves the same. kSecAttrIsExtractable value is ignored.


Here are my sample code:


NSDictionary* attributes =

@{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,

(id)kSecAttrKeySizeInBits: @2048,

(id)kSecUseKeychain: (__bridge id)keychainRef,

(id)kSecPrivateKeyAttrs:

@{ (id)kSecAttrIsPermanent: @YES,

(id)kSecAttrIsExtractable: @NO,

(id)kSecAttrCanDerive: @NO,

},

};

SecKeyRef privateKey = NULL;

SecKeyRef publicKey = NULL;

OSStatus result = SecKeyGeneratePair((__bridge CFDictionaryRef)attributes, &publicKey, &privateKey);

if(privateKey) {

CFDataRef exportPrivateKeyData = NULL;

result = SecItemExport(privateKey, kSecFormatUnknown, 0, NULL, &exportPrivateKeyData);

if(exportPrivateKeyData) CFRelease(exportPrivateKeyData);

}


if(publicKey) CFRelease(publicKey);

if(privateKey) CFRelease(privateKey);


I am able to export private key out in the above sample code. Also, I am able to export the private key out in P12 using App Keychain Access.


My Xcode version is 9.2(9C40b).

I am testing my code in Mac mini.

Thanks for that info. Alas, I’m out of good suggestions right now. My recommendation is that you open a DTS tech support incident and discuss this with our Security framework specialist.

Share and Enjoy

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

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

Thanks a lots. I do not need to submit a TSI. I have found the solution.


Set the kSecAttrIsExtractable: @NO at the same level as kSecAttrKeyType in the attributes dictionary, instead of inside kSecPrivateKeyAttrs.


New sample code:


NSDictionary* attributes =

@{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,

(id)kSecAttrKeySizeInBits: @2048,

(id)kSecAttrIsExtractable: @NO,

(id)kSecUseKeychain: (__bridge id)keychainRef,

(id)kSecPrivateKeyAttrs:

@{ (id)kSecAttrIsPermanent: @YES,

(id)kSecAttrCanDerive: @NO,

},

};


CFErrorRef error = NULL;

SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);


if(privateKey) {

CFDataRef exportPrivateKeyData = NULL;

result = SecItemExport(privateKey, kSecFormatUnknown, 0, NULL, &exportPrivateKeyData);

if(exportPrivateKeyData) CFRelease(exportPrivateKeyData);

...


In this case, I am unable to expect the private key as expected. SecItemExport() returns errSecDataNotAvailable.

I have found the solution.

Cool. Thanks for letting us know!

Share and Enjoy

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

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