在我的应用程序中,我需要根据证书对用户进行身份验证。我就是这样做的 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 发件人,应用程序就会崩溃。
任何帮助是极大的赞赏!!!