【问题标题】:Client Certificate Authentication on iOS UIWebView Works on iOS 6.1 but not iOS 7iOS UIWebView 上的客户端证书身份验证适用于 iOS 6.1 但不适用于 iOS 7
【发布时间】:2014-08-12 15:58:52
【问题描述】:

我正在尝试使用客户端证书身份验证来访问安全网站。我使用的代码在 iOS 6.1 中运行良好,但在使用 iOS 7 时服务器返回 403.7 错误而失败。

我使用 connection:willSendRequestForAuthenticationChallenge 处理程序来检查身份验证方法并提供客户端证书。

我的代码是:

- (void)connection: (NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        NSLog(@"Trust Challenge");
        SecTrustResultType trustResultType;
        OSStatus err = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);

        NSLog(@"SecTrustResult %u %d",trustResultType, (int)err);

        if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultConfirm || trustResultType == kSecTrustResultUnspecified) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
        else{
            [challenge.sender cancelAuthenticationChallenge:challenge];
        }

    } else {
        NSString *path = [[NSBundle mainBundle]pathForResource:@"mycert" ofType:@"pfx"];
        NSData *p12data = [NSData dataWithContentsOfFile:path];

        CFDataRef inP12data = (__bridge CFDataRef)p12data;

        SecIdentityRef myIdentity;
        SecTrustRef myTrust;
        extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);
        assert(myIdentity != nil);
        assert(myTrust != nil);

        long count = SecTrustGetCertificateCount(myTrust);
        NSMutableArray* myCertificates = nil;
        if(count > 1) {
            myCertificates = [NSMutableArray arrayWithCapacity:count];
            for(int i = 1; i < count; ++i) {
                [myCertificates addObject:(__bridge id)SecTrustGetCertificateAtIndex(myTrust, i)];
            }
        }

        NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:myCertificates persistence:NSURLCredentialPersistenceNone];
        assert(credential != nil);

        NSLog(@"User: %@, certificates %@ identity:%@", [credential user], [credential certificates], [credential identity]);
        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    }
}

我使用这个函数来提取证书的内容:

OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust)
{
    OSStatus securityError = errSecSuccess;

    CFStringRef password = CFSTR("password");
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };

    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inP12data, options, &items);

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

        CFIndex count = CFArrayGetCount(items);
        NSLog(@"Certificates found: %ld",count);
    }

    if (options) {
        CFRelease(options);
    }

    return securityError;
}

mycert.pfx 文件包含中间证书以及客户端证书。

connection:didFailWithError 函数永远不会被调用。

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
        NSLog(@"Error: %@", [error userInfo]);
    }

看来证书协商在某种程度上是成功的。

我的问题类似于SSL - behaves differently in iOS7?,但我使用的是带有 IIS 7.5 的 Windows Server 2008 R2。服务器已启用 TLS 1.1 和 TLS 1.2 协议。

WireShark 跟踪显示,使用 iOS 7 时,TLS 握手期间的证书帧为空。使用 iOS 6.1 时发送并验证证书。

我可以使用 Safari 在 iOS 7 中访问该站点。

非常感谢任何帮助。

【问题讨论】:

    标签: ios ssl ios7


    【解决方案1】:

    在 Apple Developer 支持的帮助下,我找到了解决方案。该解决方案涉及创建自定义 NSURLProtocol。我在https://developer.apple.com/library/ios/#samplecode/CustomHTTPProtocol/ 使用了Apple 示例代码。示例代码展示了如何覆盖 HTTPS 服务器信任评估,因此需要对其进行修改以使用客户端证书身份验证。

    我修改了 AppDelegate didRecieveAuthenticationChallenge 函数。

    - (void)customHTTPProtocol:(CustomHTTPProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    // A CustomHTTPProtocol delegate callback, called when the protocol has an authenticate
    // challenge that the delegate accepts via -   customHTTPProtocol:canAuthenticateAgainstProtectionSpace:.
    // In this specific case it's only called to handle server trust authentication challenges.
    // It evaluates the trust based on both the global set of trusted anchors and the list of trusted
    // anchors returned by the CredentialsManager.
    {
        OSStatus            err;
        NSURLCredential *   credential;
    
        assert(protocol != nil);
        assert(challenge != nil);
    
        credential = nil;
    
        // Handle ServerTrust and Client Certificate challenges
    
        NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
        if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            NSLog(@"Trust Challange");
            SecTrustResultType trustResultType;
            err = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);
    
            NSLog(@"SecTrustResult %u %d",trustResultType, (int)err);
    
            if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultUnspecified) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                assert(credential != nil);
            }
        } else {
            NSString *path = [[NSBundle mainBundle]pathForResource:@"mycert" ofType:@"pfx"];
            NSData *p12data = [NSData dataWithContentsOfFile:path];
    
            SecIdentityRef identity = NULL;
            SecCertificateRef certificate = NULL;
    
            [Util identity:&identity andCertificate:&certificate fromPKCS12Data:p12data withPassphrase:@"asia1215"];
    
            assert(identity != NULL);
    
            NSArray *certArray = [NSArray arrayWithObject:(__bridge id)certificate];
            credential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
        }
    
        [protocol resolveAuthenticationChallenge:challenge withCredential:credential];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      • 1970-01-01
      • 2017-08-20
      • 2014-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多