SecItemCopyMatching returns nil without any error

I am trying to add an RSA public key to my iPhone keychain using the CryptoExercise SecKeyWrapper addPeerPublicKey:keyBits: . The logic of this method is that it first tries to add the key to the keychain, and if it is already there (sanityCheck==errSecDuplicateItem) , it tries to extract this key from the keychain by calling SecKeyItemCopyMatching() .

This is exactly what happens in my case: the key is already in the keychain, so calling SecKeyItemAdd() returns errSecDuplicateItem .

Then it tries to retrieve the existing key, but SecKeyItemCopyMatching() returns 0 (indicating that there was no error), but the second parameter ( peerKeyRef ) remains deselperately nil.

How is this possible? What is wrong with that?

Here is the [SecKeyWrapper addPeerPublicKey:keyBits:] code from the CryptoExercise example for reference:

 - (SecKeyRef)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKey { OSStatus sanityCheck = noErr; SecKeyRef peerKeyRef = NULL; CFTypeRef persistPeer = NULL; LOGGING_FACILITY( peerName != nil, @"Peer name parameter is nil." ); LOGGING_FACILITY( publicKey != nil, @"Public key parameter is nil." ); NSData *peerTag = [[NSData alloc] initWithBytes:(const void *) [peerName UTF8String] length:[peerName length]]; NSMutableDictionary *peerPublicKeyAttr = [[NSMutableDictionary alloc] init]; [peerPublicKeyAttr setObject:(__bridge id) kSecClassKey forKey:(__bridge id) kSecClass]; [peerPublicKeyAttr setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id) kSecAttrKeyType]; [peerPublicKeyAttr setObject:peerTag forKey:(__bridge id) kSecAttrApplicationTag]; [peerPublicKeyAttr setObject:publicKey forKey:(__bridge id) kSecValueData]; [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecReturnPersistentRef]; sanityCheck = SecItemAdd((__bridge CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *) &persistPeer); // The nice thing about persistent references is that you can write their value out to disk and // then use them later. I don't do that here but it certainly can make sense for other situations // where you don't want to have to keep building up dictionaries of attributes to get a reference. // // Also take a look at SecKeyWrapper methods (CFTypeRef)getPersistentKeyRefWithKeyRef:(SecKeyRef)key // & (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef. LOGGING_FACILITY1( sanityCheck == noErr || sanityCheck == errSecDuplicateItem, @"Problem adding the peer public key to the keychain, OSStatus == %ld.", sanityCheck ); if (persistPeer) { peerKeyRef = [self getKeyRefWithPersistentKeyRef:persistPeer]; } else { [peerPublicKeyAttr removeObjectForKey:(__bridge id) kSecValueData]; [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecReturnRef]; // Let retry a different way. sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *) &peerKeyRef); } LOGGING_FACILITY1( sanityCheck == noErr && peerKeyRef != NULL, @"Problem acquiring reference to the public key, OSStatus == %ld.", sanityCheck ); if (persistPeer) CFRelease(persistPeer); return peerKeyRef; } 
+6
source share
1 answer

I had the same problem and I assume that you are trying to import an RSA key that has not been exported from another iOS device.

The reason, apparently, is the incompatible key format - in detail, iOS expects some ASN1 header to NOT be set. Why functions are returned OK, for me it is only explainable with an error ...

Check out the code http://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/ , this is the right solution and works for me - so thanks Chris Luke

+4
source

Source: https://habr.com/ru/post/949339/


All Articles