iOS Mutual Auth验证成功,然后连接请求失败

时间:2013-10-23 20:45:10

标签: ios objective-c cocoa ssl authentication

我正在尝试为iPhone应用程序实现相互身份验证。到目前为止,似乎我能够验证服务器信任,并在本地验证我的客户端证书。在连接中的所有代码:didReceiveAuthenticationChallenge成功运行后,连接失败并显示:

“此服务器的证书无效。您可能正在连接到假装为x的服务器,这可能会使您的机密信息面临风险。”

此外,在Windows服务器端,它表示请求不包含客户端证书。 我错过了什么? 这是我的代码:

    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge previousFailureCount] == 0) {
        //******Server Auth******
        static NSArray *trustArray = nil;
        if (!trustArray)
        {
            trustArray = [self getTrustArray];
        }
        SecTrustRef trust = [[challenge protectionSpace] serverTrust];         // Create trust object
        SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef) trustArray );        // Set trust anchors
        SecTrustSetAnchorCertificatesOnly(trust, YES); //only check against the certs I provide
        //Set policies
        SecPolicyRef policyRef = SecPolicyCreateBasicX509();//Both this and secPolicyCreateSSL seem to work fine
        //SecPolicyRef policyRef = SecPolicyCreateSSL(YES, nil);
        SecTrustSetPolicies(trust, policyRef);
        SecTrustResultType trustResult;          // Store trust result in this
        SecTrustEvaluate(trust, &trustResult);         // Evaluate server trust

        if(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed) {
            //******Client Auth******
            //Apple Documentation: Certificate, Key, and Trust Services Tasks for iOS
            NSData *clientPKCS12Data = [self getClientCertDataFromFile];
            CFDataRef inClientPKCS12Data = (__bridge CFDataRef)(clientPKCS12Data);
            SecIdentityRef clientIdentity;
            SecTrustRef clientTrust;
            CFStringRef password = CFSTR("pw");
            extractIdentityAndTrust(inClientPKCS12Data, &clientIdentity, &clientTrust, password);
            if (!clientIdentity)
            {
                [challenge.sender cancelAuthenticationChallenge:challenge]; //Client auth failed
            }
            else
            {
                SecTrustResultType clientTrustResult;
                SecTrustEvaluate(clientTrust, &clientTrustResult);
                if (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)
                {
                    SecCertificateRef myReturnedCertificate = NULL;
                    OSStatus status = SecIdentityCopyCertificate(clientIdentity, &myReturnedCertificate);
                    if (status){
                        NSLog(@"SecIdentityCopyCertificate failed.");
                        //Gracefully exit here;
                    }
                    SecCertificateRef certs[1] = { myReturnedCertificate };
                    CFArrayRef array = CFArrayCreate(NULL, (const void **) certs, 1, NULL);
                    NSArray *myArray = (__bridge NSArray *)array;
                    // Create the NSURLCredential
                    NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:clientIdentity certificates:myArray persistence:NSURLCredentialPersistenceForSession];

                    // Send
                    [challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
                }

            }
        }
        //CFRelease(trustResult);
    } else {
        // Failed
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

- (NSString *)getClientCertLocation
{
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentDirectories objectAtIndex:0];
    NSString *certLocation = [documentDirectory stringByAppendingPathComponent:UserClientCertDataLocation];
    return certLocation;
}

- (NSData *)getClientCertDataFromFile
{
    NSString *thePath = [self getClientCertLocation];
    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
    NSString *stringData = [[NSString alloc] initWithData:PKCS12Data encoding:NSUTF8StringEncoding];
    NSData *base64 = [[NSData alloc] initWithBase64EncodedString:stringData options:NSDataBase64DecodingIgnoreUnknownCharacters];
    return base64;
}

- (NSArray *)getTrustArray
{
    NSData *rootCertData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"authority" ofType:@"cer"]];
    SecCertificateRef rootCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef) rootCertData);
    NSData *intermediateCertData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"intermediate" ofType:@"cer"]];
    SecCertificateRef intermediateCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef) intermediateCertData);
    NSArray *trustArray = [NSArray arrayWithObjects:(__bridge id)rootCertRef, (__bridge id)intermediateCertRef, nil];   // Add as many certificates as needed
    return trustArray;
}

OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data,
                                 SecIdentityRef *outIdentity,
                                 SecTrustRef *outTrust,
                                 CFStringRef keyPassword)
{
    OSStatus securityError = errSecSuccess;

    const void *keys[] =   { kSecImportExportPassphrase };
    const void *values[] = { keyPassword };
    CFDictionaryRef optionsDictionary = NULL;

    /* Create a dictionary containing the passphrase if one
     was specified.  Otherwise, create an empty dictionary. */
    optionsDictionary = CFDictionaryCreate(
                                           NULL, keys,
                                           values, (keyPassword ? 1 : 0),
                                           NULL, NULL);

    CFArrayRef items = NULL;
    securityError = SecPKCS12Import(inPKCS12Data,
                                    optionsDictionary,
                                    &items);


    if (securityError == 0) {
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
                                             kSecImportItemIdentity);
        CFRetain(tempIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = NULL;
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);

        CFRetain(tempTrust);
        *outTrust = (SecTrustRef)tempTrust;
    }

    if (optionsDictionary)
        CFRelease(optionsDictionary);

    if (items)
        CFRelease(items);

    return securityError;
}

1 个答案:

答案 0 :(得分:1)

要发送客户端证书,您需要在if条件下添加代码:

if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) 

对于服务器证书验证,请在

下添加代码
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) 

检查How to use Client Certificate Authentication in iOS App以获取更多信息

相关问题