0

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

在此处输入图像描述

任何帮助是极大的赞赏!!!

4

2 回答 2

0

好的,我似乎已经修复了它。

改变了

 identity = (__bridge SecIdentityRef)([self _dumpCredentialsOfSecClass:kSecClassIdentity printSelector:@selector(_printIdentity:attributes:)]);

identity = (SecIdentityRef)CFBridgingRetain([self _dumpCredentialsOfSecClass:kSecClassIdentity printSelector:@selector(_printIdentity:attributes:)]);

希望这可以帮助某人

于 2013-06-14T05:16:38.177 回答
0

您是否尝试为您的项目启用僵尸对象?它可以帮助您找出问题所在。

于 2013-06-14T04:45:17.450 回答