SecItemCopyMatching() not able to retrieve public key data on OS X

I am trying to generate an RSA key pair and retrieve the key bytes on OSX. I tried using the technique illustrated by the CryptoExercise sample code for iOS. Everything seems to work, except I always get back only 96 bytes when I try to retrieve the key bytes, regardless of the key size. Here is the code I am using:


CFMutableDictionaryRef query;

query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

CFDictionarySetValue(query,kSecClass,kSecClassKey);

CFDictionarySetValue(query,kSecAttrKeyType,kSecAttrKeyTypeRSA);

CFDictionarySetValue(query,kSecAttrApplicationTag,publicTag);

CFDictionarySetValue(query,kSecReturnData,kCFBooleanTrue);

CFDictionarySetValue(query,kSecReturnAttributes,kCFBooleanTrue);

CFDictionaryRef attr;

status = SecItemCopyMatching(query, (CFTypeRef *)&attr);


The dictionary attributes show the correct property for the key, but the "v_Data" has only 96 bytes. Likewise, if I omit the kSecReturnAttributes and just request kSecReturnData. The same code works correctly on iOS, returning the key length + 12 bytes (DER format).


Any trick to make this work on OSX? I guess I can use OpenSSL, which I need anyway for Linux server side. But I was hoping to have iOS compatible code running on OSX for development.

Accepted Reply

On OS X you must export the key using one of the keychain export APIs. For example:

- (NSData *)subjectPublicKeyInfoDataForPublicKey:(SecKeyRef)publicKey {
    BOOL                success;
    NSData *            result;
    CFDataRef          exportResult;

    result = nil;

    success = SecItemExport(publicKey, kSecFormatOpenSSL, 0, NULL, &exportResult) == errSecSuccess;
    if (success) {
        result = CFBridgingRelease(exportResult);
    }

    return result;
}

Share and Enjoy

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

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

Replies

On OS X you must export the key using one of the keychain export APIs. For example:

- (NSData *)subjectPublicKeyInfoDataForPublicKey:(SecKeyRef)publicKey {
    BOOL                success;
    NSData *            result;
    CFDataRef          exportResult;

    result = nil;

    success = SecItemExport(publicKey, kSecFormatOpenSSL, 0, NULL, &exportResult) == errSecSuccess;
    if (success) {
        result = CFBridgingRelease(exportResult);
    }

    return result;
}

Share and Enjoy

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

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

Thanks, that worked, though I'm afraid I may end up using OpenSSL. Ideally, I wanted to have same code running on Linux + OSX + iOS, or at worst only 2 variants. Also, I had wanted to generate keys with exponent=3, to push more of the work load from encrypt to decrypt side, but it looks like SecKeyGeneratePair() always uses 65537. It would be nice to see asymmetric crypto included in the common crypto library for applications that just want the algorithms not keychain integration.

It would be nice to see asymmetric crypto included in the common crypto library for applications that just want the algorithms not keychain integration.

The best way to get that feedback in front of folks who have the power to effect change is to file an enhancement request for it. Please post your bug number, just for the record.

Also, I had wanted to generate keys with exponent=3, to push more of the work load from encrypt to decrypt side, but it looks like SecKeyGeneratePair() always uses 65537.

Ditto.

Share and Enjoy

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

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