SecItemCopyMatching 返回 nil 值而没有任何错误
Posted
技术标签:
【中文标题】SecItemCopyMatching 返回 nil 值而没有任何错误【英文标题】:SecItemCopyMatching returns nil value without any error 【发布时间】:2013-07-12 19:57:31 【问题描述】:我正在尝试使用 CryptoExercise 的 SecKeyWrapper addPeerPublicKey:keyBits:
方法将 RSA 公钥添加到我的 iPhone 钥匙串中。
该方法的逻辑是它首先尝试将密钥添加到钥匙串中,如果它已经存在(sanityCheck==errSecDuplicateItem)
,它会尝试通过调用SecKeyItemCopyMatching()
从钥匙串中检索此密钥。
这正是我的情况:钥匙已经在钥匙串中,所以调用SecKeyItemAdd() returns errSecDuplicateItem
。
然后它尝试检索现有的密钥,但SecKeyItemCopyMatching() returns 0
(表示没有错误)但第二个参数(peerKeyRef
)仍然拼命地为零。
这怎么可能?这有什么问题?
这里是 CryptoExercise 示例中[SecKeyWrapper addPeerPublicKey:keyBits:]
的代码供参考:
- (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;
【问题讨论】:
我认为这与您的问题无关,但您传递给SecItemCopyMatching
的查询似乎包括kSecReturnRef
和kSecReturnPersistentRef
设置为true。这将使peerKeyRef
中返回的值成为CFDictionaryRef
,而不是您的代码所期望的SecKeyRef
。
我注意到了这一点,但由于它是在原始 Apple 示例中的编写方式,所以我一直这样,直到它产生问题为止。我试图删除旧值,它产生了相同的结果:根本没有结果。
【参考方案1】:
我遇到了同样的问题,我假设您尝试导入不是从其他 ios 设备导出的 RSA 密钥。
原因似乎是不兼容的密钥格式 - 详细而言,iOS 期望不设置某些 ASN1 标头。为什么函数返回 OK 对我来说只能用一个错误来解释......
查看http://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/ 的代码,这是正确的解决方案,对我有用 - 非常感谢 Chris Luke
【讨论】:
你们有类似的私钥示例吗?以上是关于SecItemCopyMatching 返回 nil 值而没有任何错误的主要内容,如果未能解决你的问题,请参考以下文章
SecItemCopyMatching 返回 nil 值而没有任何错误
iOS 9:SecItemCopyMatching 返回成功状态码,但键为 nil
没有密码回退的 Touch ID 的 SecItemCopyMatching
来自命令行的 xcodebuild - 权利问题 -SecItemCopyMatching:缺少权利
SecItemCopyMatching 的 swift 2.0 钥匙串类型错误
Keychainitemwrapper 类中的 SecItemCopyMatching 条件失败,因此无法检索钥匙串中保存的值