如何从iOS中的白名单接受自签名服务器证书?

Mic*_*ine 6 ssl-certificate nsurlconnection ios

我试图在NSURLConnection中接受自签名证书,正如许多人在我之前所做的那样.问题是,我只想接受我信任的证书白名单中的证书.我决心要弄清楚如何接受单一证书.这是我在NSURLConnectionDelegate中到目前为止所获得的代码:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSString *thePath = [[NSBundle mainBundle] pathForResource:@"trusted" ofType:@"der"];
        NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath];
        CFDataRef myCertData = (__bridge_retained CFDataRef)certData;
        SecCertificateRef myCert = SecCertificateCreateWithData(NULL, myCertData);
        SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
        SecCertificateRef certArray[1] = { myCert };
        CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
        SecTrustRef myTrust;
        OSStatus status = SecTrustCreateWithCertificates(myCerts, myPolicy, &myTrust);

        SecTrustResultType trustResult;
        if (status == noErr) {
            status = SecTrustEvaluate(myTrust, &trustResult);
        }
        BOOL trusted = NO;

        if (trustResult == kSecTrustResultUnspecified) {
            // I never get here.  Instead, trustResult is always kSecTrustResultRecoverableTrustFailure
            trusted = YES; 
        }

        if (trusted) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
                 forAuthenticationChallenge:challenge];
        } else {
            [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
        }
        CFRelease(myTrust);
        CFRelease(myCerts);
        CFRelease(myPolicy);
        CFRelease(myCert);
        CFRelease(myCertData);
    } else {
        [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您在评论中看到的那样,我实际上从未获得过kSecTrustResultUnspecified,这是我期望得到的.我验证了我的证书是正确的,并且格式正确(DER).

Mic*_*ine 14

好吧,想通了.事实证明,您只需要检查服务器信任,并实际使用证书数据.

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    BOOL trusted = NO;
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSString *thePath = [[NSBundle mainBundle] pathForResource:@"trusted" ofType:@"der"];
        NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath];
        CFDataRef certDataRef = (__bridge_retained CFDataRef)certData;
        SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
        SecPolicyRef policyRef = SecPolicyCreateBasicX509();
        SecCertificateRef certArray[1] = { cert };
        CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
        SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
        SecTrustResultType trustResult;
        SecTrustEvaluate(serverTrust, &trustResult);
        trusted = (trustResult == kSecTrustResultUnspecified);
        CFRelease(certArrayRef);
        CFRelease(policyRef);
        CFRelease(cert);
        CFRelease(certDataRef);
    }
    if (trusted) {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else {
        [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
    }
}
Run Code Online (Sandbox Code Playgroud)