我正在使用大型多平台库,其中使用了客户端身份。要求是应用程序私下维护客户端身份,并且可以从系统存储中导入客户端身份(如果是Mac OS默认密钥链)。
所以基本上API必须涵盖以下
最初我在一些私人加密文件中计划了商店标识,但事实证明Apple API不允许在没有钥匙串的情况下导入客户端身份。
所以我决定我的图书馆将维护私人钥匙串。如果导入身份表单文件,它很简单,它确实有效:
NSDictionary *options =
@{
(id)kSecImportExportPassphrase:password.stringValue,
(id)kSecImportExportKeychain:(__bridge id)keychain,
};
CFArrayRef arrayResult = NULL;
OSStatus status = SecPKCS12Import((CFDataRef)pkcs12,
(CFDictionaryRef)options,
&arrayResult);
if (status != errSecSuccess)
现在的问题是如何将客户端身份表格默认的keychian复制到私人钥匙串?
这是我用来创建钥匙串的代码:
- (void)setupOpenMyKeychain
{
NSString *keychainPath = [self keychainPath];
NSString *pass = @"dasndiaisdfs"; // used only for testing
OSStatus status = SecKeychainCreate(keychainPath.UTF8String,
(UInt32)strlen(pass.UTF8String),
pass.UTF8String,
NO,
NULL,
&keychain);
if (status == errSecDuplicateKeychain)
{
status = SecKeychainOpen(keychainPath.UTF8String, &keychain);
if (status == errSecSuccess)
{
status = SecKeychainUnlock(keychain,
(UInt32)strlen(pass.UTF8String),
pass.UTF8String,
TRUE);
if (status != errSecSuccess)
{
[self showOSStatusFailureAlert: status forAction: @"Unlock failure"];
}
}
}
if (status != errSecSuccess)
{
[self showOSStatusFailureAlert: status forAction: @"Open/Create failure"];
}
}
现在我在默认钥匙串中有SecIdentityRef和SecCertificate(在CFArrayRef中),我想将它复制到我的自定义keychian:
- (NSData *)persistantRefFor: (id)item
{
CFTypeRef result = NULL;
NSDictionary *dic =
@{
(id)kSecValueRef:(id)item,
(id)kSecReturnPersistentRef:(id)kCFBooleanTrue,
//(id)kSecUseKeychain:(__bridge id)keychain,
};
OSStatus status = SecItemCopyMatching((CFDictionaryRef)dic,
&result);
if (status != errSecSuccess)
{
[self showOSStatusFailureAlert: status
forAction: @"Failed to find reference"];
return nil;
}
return (__bridge_transfer NSData *)result;
}
-(OSStatus)copyItemWithPersistantRef:(NSData *)persistantReference
{
SecKeychainItemRef item = NULL;
OSStatus result = SecKeychainItemCopyFromPersistentReference((__bridge CFDataRef)persistantReference, &item);
if (result != errSecSuccess)
{
[self showOSStatusFailureAlert: result forAction: @"Get item from reference"];
return result;
}
CFAutorelease(item);
SecKeychainRef soruceKeychain = NULL;
result = SecKeychainItemCopyKeychain(item, &soruceKeychain);
if (result == errSecSuccess)
{
if (soruceKeychain == keychain)
{
CFRelease(soruceKeychain);
// item is already in desired keychain
return result;
}
} else {
[self showOSStatusFailureAlert: result forAction: @"Fetching source keychain"];
return result;
}
SecAccessRef access = NULL;
result = SecKeychainCopyAccess(keychain, &access);
if (result != errSecSuccess)
{
[self showOSStatusFailureAlert: result forAction: @"Get Access object"];
// return result;
} else {
CFAutorelease(access);
}
SecKeychainItemRef itemCopy = NULL;
result = SecKeychainItemCreateCopy(item, keychain, access, &itemCopy);
if (result != errSecSuccess)
{
[self showOSStatusFailureAlert: result forAction: @"Create copy in private keychain"];
return result;
}
CFAutorelease(itemCopy);
NSLog(@"Copied item %@", itemCopy);
NSData *copyPersistantRef = [self persistantRefFor: (__bridge id)itemCopy];
NSLog(@"Old persisntatn reference %@\n"
"New persisntatn reference %@\n"
"%@", persistantReference, copyPersistantRef,
[persistantReference isEqualToData: copyPersistantRef]?@"SAME":@"DIFFRENT");
return result;
}
- (IBAction)copyIdentityToPrivateKeychain:(id)sender
{
if (!identity)
{
return;
}
NSData *perRef = [self persistantRefFor: (__bridge id)identity];
OSStatus status = [self copyItemWithPersistantRef: perRef];
if (status != errSecSuccess)
{
[self showOSStatusFailureAlert: status forAction: @"Copy Identity has failed"];
}
}
尝试将SecCertificateRef复制到我的私钥钥匙时。发生以下事情:
NSData *copyPersistantRef = [self persistantRefFor: (__bridge id)itemCopy];
失败。我无法获得对复制项目的持久引用。没有此引用,我无法在应用程序启动时加载适当的证书尝试复制SecIdentityRef时更糟糕,
Error: 0xFFFF9D28 -25304 The specified item is no longer valid. It may have been deleted from the keychain.
的SecKeychainItemCopyKeychain上的Error: 0xFFFF9D28 -25304 The specified item is no longer valid. It may have been deleted from the keychain.
根据它假设工作的文档的底线,但它不起作用。可能我做错了什么,但我无法找到问题所在。
我们将不胜感激。
同样的问题我posted on Apple forum。
需要支持OS X 10.10。
这是我用于快速测试的small test application。
答案 0 :(得分:0)
使用 SecPKCS12Import
代替 SecItemImport
。将 kSecFormatPKCS12
作为 inputFormat 传递,kSecItemTypeAggregate
作为 itemType(要求身份或 kSecItemTypeUnknown
,它会尝试为您检测类型)并将 importKeychain 设置为 NULL
,这样可以防止导入到钥匙串。