【问题标题】:Adding private key into iOS Keychain将私钥添加到 iOS 钥匙串中
【发布时间】:2015-01-30 16:48:58
【问题描述】:

我正在尝试将私钥添加到 iOS 钥匙串中。证书(公钥)工作正常,但私钥拒绝......我完全困惑为什么下面的代码不起作用。

首先,我正在检查当前密钥(如果 Keychain 是键/值存储,则 = 键)在 Keychain 中是否“免费”。然后我要添加私钥。

CFStringRef labelstring = CFStringCreateWithCString(NULL, [key cStringUsingEncoding:NSUTF8StringEncoding], kCFStringEncodingUTF8);

NSArray* keys = [NSArray arrayWithObjects:(__bridge id)kSecClass,kSecAttrLabel,kSecReturnData,kSecAttrAccessible,nil];
NSArray* values = [NSArray arrayWithObjects:(__bridge id)kSecClassKey,labelstring,kCFBooleanTrue,kSecAttrAccessibleWhenUnlocked,nil];
NSMutableDictionary* searchdict = [NSMutableDictionary dictionaryWithObjects:values forKeys:keys];

CFRelease(labelstring);

NSMutableDictionary *query = searchdict;


CFTypeRef item = NULL;
OSStatus error = SecItemCopyMatching((__bridge_retained CFDictionaryRef) query, &item);

if (error)
{
    NSLog(@"Error: %ld (statuscode)", error);
}

if(error != errSecItemNotFound)
{
    SecItemDelete((__bridge_retained CFDictionaryRef) query);
}

[query setObject:(id)data forKey:(__bridge id)kSecValueData];

OSStatus status = SecItemAdd((__bridge_retained CFDictionaryRef) query, &item);

if(status)
{
    NSLog(@"Keychain error occured: %ld (statuscode)", status);
    return NO;
}

调试输出如下:

2012-07-26 15:33:03.772 App[15529:1b03] Error: -25300 (statuscode)
2012-07-26 15:33:11.195 App[15529:1b03] Keychain error occured: -25299 (statuscode)

第一个错误代码-25300代表errSecItemNotFound。所以这个键没有存储任何值。然后,当我尝试将私钥添加到钥匙串中时,我得到-25299,这意味着errSecDuplicateItem。我不明白。为什么会这样?

有人对此有线索或提示吗?

苹果的错误代码:

errSecSuccess                = 0,       /* No error. */
errSecUnimplemented          = -4,      /* Function or operation not implemented. */
errSecParam                  = -50,     /* One or more parameters passed to a function where not valid. */
errSecAllocate               = -108,    /* Failed to allocate memory. */
errSecNotAvailable           = -25291,  /* No keychain is available. You may need to restart your computer. */
errSecDuplicateItem          = -25299,  /* The specified item already exists in the keychain. */
errSecItemNotFound           = -25300,  /* The specified item could not be found in the keychain. */
errSecInteractionNotAllowed  = -25308,  /* User interaction is not allowed. */
errSecDecode                 = -26275,  /* Unable to decode the provided data. */
errSecAuthFailed             = -25293,  /* The user name or passphrase you entered is not correct. */ 

提前致谢!

更新 #1:我发现它只在第一次工作。即使数据和密钥不同,在第一次存储到钥匙串后,我也无法存储更多的密钥。

【问题讨论】:

  • 我面临着完全相同的问题。使用 SecItemAdd 添加的第一个键没有问题,然后对 SecItemAdd 的任何连续调用都失败并出现 errSecDuplicateItem,尽管 SecItemCopyMatching 返回 errSecItemNotFound。你找到解决方案了吗?

标签: ios objective-c keychain private-key


【解决方案1】:

以下代码对我有用:

NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; 
[query setObject:(id)kSecClassKey forKey:(id)kSecClass]; 
[query setObject:(id)kSecAttrAccessibleWhenUnlocked forKey:(id)kSecAttrAccessible]; 
[query setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];

//adding access key 
[query setObject:(id)key forKey:(id)kSecAttrApplicationTag];


//removing item if it exists 
SecItemDelete((CFDictionaryRef)query);

//setting data (private key) 
[query setObject:(id)data forKey:(id)kSecValueData];

CFTypeRef persistKey; OSStatus status = SecItemAdd((CFDictionaryRef)query, &persistKey);

if(status) {
    NSLog(@"Keychain error occured: %ld (statuscode)", status);
    return NO; 
}

【讨论】:

  • 删除钥匙串项目只是为了添加具有相同信息的项目是不好的做法。我不记得具体原因,但我认为这样做可能会导致冲突。
  • 我在去年的 WWDC 上与一位从事 Keychain 工作的 Apple 员工进行了交谈,他告诉我,事实上他们现在还没有提供其他方法来实现这一点,但他们有一个私有 API他们将发布很快...
  • 我不明白你的意思,克里斯。我遇到了同样的问题,并且能够修复我的代码以正确找到现有项目。我的问题是我在添加它时将其定义为可通过 iCloud 同步,但在搜索时未将其包含在查询中,因此找不到匹配项。我不必删除并重新添加它。
  • 这个可以用来把String转成SecKeyRef吗?
  • @Joey 这是一种不好的做法,尤其是在 OSX 上,因为用户可能已将密钥移动到不同的钥匙串(如果您愿意,您可以拥有数百个),并且当您删除并重新创建它时,它总是在默认钥匙串中重新创建,然后用户必须再次移动它。在 iOS 和 OS X 上这是不好的做法,因为系统/用户设置的任何访问控制或从其他应用程序添加的任何额外数据(如果项目是共享的,这是可能的)都会以这种方式丢失。
【解决方案2】:

抱歉,我永远无法调试您的代码。 Apple 提供了一些示例代码(KeychainItemWrapper),可以让您保存一个字符串(我记得)。它对处理钥匙链有很大帮助。网络上有一个要点是该类的修改版本,但保存和恢复字典(存档为数据对象,这是 Apple 代码对字符串所做的)。这使您可以在一个界面中将多个项目保存到钥匙串。要点在这里Keychain for NSDictionary/data

【讨论】:

  • 谢谢,但需要存储为kSecClassKey(对应的证书为kSecClassCertificate)。我知道 Apple 提供了这个示例代码,用于将用户凭据(但只有字符串)存储到钥匙串中。考虑到,想要验证证书或使用kSecClassKey 的额外保护,它无法使用Apple 示例代码或您的链接中的方法进行存储。但是,我想我已经找到了一个解决方案,但在我在这里发布之前必须验证这一点。
  • 根据我的经验,钥匙串包装器不允许将多个项目保存到同一个钥匙串组中。这引起了一些严重的挫折,但可以在这里找到解决方案:stackoverflow.com/questions/11055731/…
  • 这很有趣 - 因为我在我的应用程序中使用字典并保存电子邮件、密码和其他与用户相关的上下文。但是我修改了 Apple 的代码并不多 - 你可以在我的答案的链接中看到它。这是现在数千部手机中的工作代码(而不是数百万部:-()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多