2012-10-22 48 views
2

我在我的应用程序的文档文件夹中有一个PKCS12文件,其中包含一个证书和一个私钥。 我可以打开此.p12文件,提取标识对象并显示一些信息,这要归功于Apple的文档(https://developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks .html#// apple_ref/doc/uid/TP40001358-CH208-DontLinkElementID_10)如何将已添加的SecIdentityRef更新为iOS应用程序的钥匙串?

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

Apple的代码似乎使用persistent_ref来检索存储在Keychain中的Identity。但我真的不明白这是什么...它是一个简单的参考,如记忆参考?如果是这种情况,设备重新启动时会发生什么?

无法找到关于此的更多信息我试图通过使用kSecAttr属性以不同方式执行此操作。 目前的代码工作正常添加身份到钥匙串:

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

回答

3

SecIdentityRef S,SecKeyRef S和类似Sec...Ref值是钥匙扣的短暂交涉项目。当应用程序退出或保留计数达到零时,它们就会失效。它们不能直接保存在持久性存储中。

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

Apple's sample代码使用SecItemAdd的第二个参数来检索对添加到钥匙串的项目的持久引用。这大概存储在NSUserDefaults。鉴于持久的参考,应用程序可以稍后使用SecItemCopyMatching将其转换为它可以使用的SecIdentityRef

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

SecItemUpdate可能失败,因为SecIdentityRef不是真正的钥匙串项目。这只是一个伪项目,当一个公钥和它的相关私钥都在钥匙串上时,这个伪项目就构成了。因此,更新它没有多大意义 - 它没有任何属性。其所有属性都从其关联的SecCertificateRef(证书)和SecKeyRef(私钥)继承。更新这些项目而不是身份应该起作用。 (但是简单地正确创建项目比较容易:您可以通过将其添加到SecItemAdd的第一个参数中来初始化任何属性。)或者,您可以尝试简单地删除标识(SecItemDelete),然后重新将其添加到钥匙扣。

+0

刚编辑我的问题。我试图删除之前添加项目,但我仍然有相同的状态代码,即使我只在searchDictionary中有一个元素。对我来说没有多大意义。 – Anth0

4

即使这是一个旧帖子,当我在处理钥匙链中的身份(用于SSL客户端身份验证)时最近出现类似问题时,我提供了我自己的体验(使用XCode 5.0.1)因为对此的支持似乎仍然非常混乱。

SecItemAdd的确必须使用很少的按键。 kSecValueRef(带有身份)当然是强制性的,可以选择kSecAttrLabel。使用其他几个密钥(例如kSecClass)导致无提示失败,即没有错误报告,但没有添加身份。这很混乱。

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

为了能够更新现有标识,我使用SecItemDelete删除了现有标识,然后将其与SecItemAdd一起添加。再次令人困惑的是,虽然对SecItemDelete的调用返回了-25300错误(errSecItemNotFound),但它可以被忽略,因为可以在事后添加它(使用SecItemAdd)而不会出错。

相关问题