Próbuję dodać klucz publiczny RSA do pęku kluczy mojego iPhone'a za pomocą metody SecKeyWrapper CryptoExercise addPeerPublicKey:keyBits:
. Logika tej metody polega na tym, że najpierw próbuje dodać klucz do pęku kluczy, a jeśli już istnieje, to próbuje odzyskać ten klucz z pęku kluczy dzwoniąc pod numer SecKeyItemCopyMatching()
.SecItemCopyMatching zwraca wartość zerową bez żadnego błędu
To jest dokładnie to, co dzieje się w moim przypadku: klucz jest już w pęku kluczy, więc połączenie z SecKeyItemAdd() returns errSecDuplicateItem
.
Następnie próbuje odzyskać istniejący klucz, ale SecKeyItemCopyMatching() returns 0
(wskazując, że nie wystąpił błąd), ale drugi parametr (peerKeyRef
) pozostaje desesperately nil.
Jak to jest możliwe? Co jest z tym nie tak?
Oto kod [SecKeyWrapper addPeerPublicKey:keyBits:]
z CryptoExercise próbki dla odniesienia:
- (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's 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's 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;
}
Nie sądzę, że to istotne dla twojego problemu, ale wygląda na to, że zapytanie, które przekazujesz do 'SecItemCopyMatching' zawiera zarówno" kSecReturnRef', jak i 'kSecReturnPersistentRef' ustawione na true. To sprawi, że wartość zostanie zwrócona w 'peerKeyRef' a' CFDictionaryRef' zamiast 'SecKeyRef', której twój kod wydaje się oczekiwać. – bdash
Zauważyłem, że, ale ponieważ tak jest napisane w oryginalnej próbce Apple, zostawiłem to tak, dopóki nie stwarza problemu. Próbowałem usunąć starą wartość i uzyskano ten sam wynik: brak wyniku. – Sebastien