3

我的应用程序文件夹中有一个 PKCS12 文件,其中包含一个证书和一个私钥。由于 Apple 的文档(https://developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks. html#//apple_ref/doc/uid/TP40001358-CH208-DontLinkElementID_10)

我现在要做的是将此身份存储到钥匙串中,以便以后使用。我在 iOS Keychain 上阅读了很多不同的东西,我很难弄清楚它是如何工作的。

Apple 的代码似乎使用 persistent_ref 来检索存储在 Keychain 中的身份。但我真的不明白这是什么......它是像内存引用这样的简单引用吗?如果是这种情况,当设备重新启动时会发生什么?

无法找到更多关于此的信息,我尝试通过使用 kSecAttr 属性来做不同的事情。当前代码可以很好地将 Identity 添加到 keychain :

NSMutableDictionary * dictionary = [[[NSMutableDictionary alloc] init] autorelease];  

[dictionary setObject:@"LABEL" forKey:kSecAttrLabel];

[dictionary setObject:(id)newIdentity forKey:(id)kSecValueRef];

OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);

但是,如果我再次尝试添加它,我会收到 -25299 错误,这是“很好”,因为它已经存在。我尝试通过这样的更新来处理它:

NSMutableDictionary *searchDictionary = [[[NSMutableDictionary alloc] init] autorelease];
[searchDictionary setObject:@"LABEL" forKey:kSecAttrLabel];
[searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
[searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];

NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
[updateDictionary setObject:(id)newIdentity forKey:(id)kSecValueRef];

OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary,(CFDictionaryRef)updateDictionary);

使用此代码,我显然会收到 -50 状态错误,因为我的参数无效......哪一个?为什么 ?我该怎么做才能正确更新我的钥匙串?

编辑:正如建议的那样,我尝试在添加现有元素之前删除它,但我遇到了相同的状态代码(-50)。下面是我试过的代码:

NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
OSStatus status = SecItemDelete((CFDictionaryRef)searchDictionary);
NSAssert(status == noErr, @"Problem deleting current keychain item." );

setupSearchDirectoryForIdentifier 只需使用我的项目标签创建一个 NSDictionnary:

- (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {

    // Setup dictionary to access keychain.
    NSMutableDictionary *searchDictionary = [[[NSMutableDictionary alloc] init] autorelease];  

    [searchDictionary setObject:identifier forKey:kSecAttrLabel];

    return searchDictionary; 
}

谢谢

PS:我正在 Xcode 4.2 / iPad 5.1.1 上开发

4

2 回答 2

4

即使这是一篇旧文章,因为我最近在使用钥匙串中的身份(用于 SSL 客户端身份验证)时遇到了类似的问题,我提供了自己的经验(使用 XCode 5.0.1)作为对此的支持似乎仍然很混乱。

SecItemAdd确实必须与很少的键一起使用。kSecValueRef(带有身份)当然是强制性的,并且是可选的 kSecAttrLabel。使用其他几个密钥(例如 kSecClass)会导致静默失败,即没有报告错误但没有添加标识。这非常令人困惑。

我也没有成功使用具有这种身份的SecItemUpdate 。我所有的尝试都导致了 -50 错误。

为了能够更新现有身份,我使用 SecItemDelete 删除了现有身份,然后使用SecItemAdd添加了它。再次令人困惑的是,尽管对 SecItemDelete 的调用返回了 -25300 错误(errSecItemNotFound),但它可以被忽略,因为身份确实被删除了,因为之后可以添加它(使用 SecItemAdd)而不会出现错误。

于 2014-01-30T15:14:08.063 回答
3

SecIdentityRefs、SecKeyRefs 和类似的Sec...Ref值是钥匙串项的临时表示。当应用程序退出或它们的保留计数达到零时,它们变得无效。它们不能直接保存在持久存储中。

另一方面,持久引用是CFDataRef您以后可以用来检索特定钥匙串项的一部分。您可以将其存储在文件中、inNSUserDefaults中或您喜欢的任何其他位置。应用程序退出或设备重启时不会失效。(但是,当钥匙串本身被删除(即设备恢复时)、它所引用的项目被删除或项目的一个标识属性被修改时,持久引用可能会变得无效。)

Apple 的示例代码使用SecItemAdd的第二个参数来检索对它添加到钥匙串中的项目的持久引用。然后大概存储在NSUserDefaults. 给定持久引用,应用程序可以稍后SecItemCopyMatching将其转换为SecIdentityRef它可以使用的引用。

请注意,如果您不想使用持久引用,则不必使用;如果您愿意,您还可以选择根据标签或任何其他识别属性来检索钥匙串项目。

SecItemUpdate可能会失败,因为 aSecIdentityRef不是真正的钥匙串项目。它只是当公钥及其关联的私钥都在钥匙串上时构造的伪项。因此,更新它没有多大意义——它不拥有任何属性。它的所有属性都继承自其关联SecCertificateRef的(证书)和SecKeyRef(私钥)。更新这些项目而不是身份应该可以工作。(但更容易正确地创建项目:您可以通过将任何属性及其值添加到SecItemAdd的第一个参数来初始化任何属性。)或者,您可以尝试SecItemDelete在将其重新添加到钥匙串之前简单地删除身份 ( )。

于 2012-10-24T00:18:57.680 回答