在我的应用中,我需要根据证书对用户进行身份验证。 我就是这样做的 1.首先,我将证书导出到沙箱中。 2.然后我从证书中提取SecIdentityRef,将其添加到钥匙串,然后从沙箱中删除证书。 3.当我实际将此身份传递给NSURL连接的身份验证质询时,应用程序只会在没有提供任何有意义信息的情况下崩溃。
以下是所有相关的代码段
//Exporting the certificate into the app and extracting the identity from it
- (void)importCertificateIntoKeychain:(NSString *)Password
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"Certificates"];
NSString *certFolderName = [[[[NSUserDefaults standardUserDefaults] objectForKey:@"CertificatePath"] lastPathComponent]stringByDeletingPathExtension];
NSString *path = [NSString stringWithFormat:@"%@/%@",dataPath,certFolderName];
NSArray*array = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:
path
error:nil];
NSString *thePath;
NSString *fileName;
for (int i=0;i<array.count;i++) {
if ([[array objectAtIndex:i]hasSuffix:@".pfx"]) {
fileName= [array objectAtIndex:i];
thePath = [NSString stringWithFormat:@"%@/%@",path,fileName];
}
}
SecIdentityRef identityApp = nil;
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
NSString *pwd = Password;
CFStringRef password = (CFStringRef)CFBridgingRetain(pwd);
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if (securityError == errSecSuccess) {
NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identityApp, &certificate);
OSStatus status = errSecSuccess;
CFTypeRef persistent_ref = NULL;
const void *keys[] = { kSecReturnPersistentRef, kSecValueRef };
const void *values[] = { kCFBooleanTrue, identityApp };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
2, NULL, NULL);
status = SecItemAdd(dict, &persistent_ref);
NSLog(@"Status %ld",status);
if (dict)
CFRelease(dict);
[Utils deleteCertificateFromInboxFolder];
} else {
NSLog(@"Error opening Certificate.");
[Utils displayAlertWithTitle:@"Wrong Password" andMessage:@"Error opening certificate"];
}
}
在身份验证质询中传递此凭据
if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate)
{
fprintf(stderr, "identities:\n");
fprintf(stderr, "certificates:\n");
NSLog(@"NSURLAuthenticationMethodClientCertificate");
SecIdentityRef identity;
identity = (__bridge SecIdentityRef)([self _dumpCredentialsOfSecClass:kSecClassIdentity printSelector:@selector(_printIdentity:attributes:)]);
SecCertificateRef certificate1 = NULL;
OSStatus *stat = SecIdentityCopyCertificate (identity, &certificate1);
//const void *certs[] = {certificate1};
SecCertificateRef certArray[1] = { certificate1 };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(certificate1);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity
certificates:(__bridge NSArray *)myCerts
persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);
// CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
//
// NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistenceNone];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
将此凭据传递给NSURLChallenge发件人后,应用程序崩溃。
非常感谢任何帮助!!!
答案 0 :(得分:0)
您是否尝试为项目启用zombie对象?它可以帮助您找出问题所在。
答案 1 :(得分:0)
好的,我好像修好了。
已更改
identity = (__bridge SecIdentityRef)([self _dumpCredentialsOfSecClass:kSecClassIdentity printSelector:@selector(_printIdentity:attributes:)]);
到
identity = (SecIdentityRef)CFBridgingRetain([self _dumpCredentialsOfSecClass:kSecClassIdentity printSelector:@selector(_printIdentity:attributes:)]);
希望这有助于某人