【问题标题】:iOS doesn't accept valid self-signed certificate and does accept invalid onesiOS 不接受有效的自签名证书并接受无效的证书
【发布时间】:2017-02-06 13:41:19
【问题描述】:

我正在使用 NSURLSessionDelegate 的 (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler 来挑战这样的服务器身份验证:

BOOL trusted = NO;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

    if (!cert) {

        NSURL* certURL = [[NSBundle mainBundle] URLForResource: @"cert_new" withExtension: @"der"];
        NSData* certData = [NSData dataWithContentsOfURL: certURL];
        cert = SecCertificateCreateWithData(kCFAllocatorDefault, CFBridgingRetain(certData));

    }

    SecPolicyRef policyRef = SecPolicyCreateBasicX509();
    SecCertificateRef certArray[1] = { cert };
    CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

    //  Create a policy that ignores the host name…

    OSStatus err = SecTrustCreateWithCertificates(CFBridgingRetain((__bridge id _Nullable)(certArrayRef)), policyRef, &serverTrust);
    CFRelease(policyRef);
    if (err != noErr)
    {
        XLog(@"Error creating trust: %d", (int)err);
        [challenge.sender cancelAuthenticationChallenge: challenge];
        return;
    }

    err = SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
    if (err == noErr)
    {
        SecTrustResultType trustResult;
        err = SecTrustEvaluate(serverTrust, &trustResult);

        trusted = (err == noErr && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified));
    }
    CFRelease(certArrayRef);
    CFRelease(policyRef);
    CFRelease(cert);

}
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (trusted) {

    [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
    return;


} else {
    [challenge.sender cancelAuthenticationChallenge: challenge];
}

我必须使用的证书是 PEM 格式。所以我通过 openssl 将其转换为 DER 格式,如下所示:

openssl x509 -in pem_file.pem -out cert_new.der -outform DER

现在似乎每个特定位长度的证书(无论是否有效)都将被接受:trusted 将被评估为YES。由于kSecTrustResultRecoverableTrustFailure,具有较低位长度的有效证书将被评估为trusted = NO。奇怪的行为......有人可以向我解释如何正确地做吗?

谢谢!

【问题讨论】:

    标签: ios https certificate nsurlsession self-signed


    【解决方案1】:

    现在我有了一个工作版本:

    //  Build a new trust based on the supplied trust, so that we can set the policy…
    NSURLProtectionSpace* protectionSpace = challenge.protectionSpace;
    SecTrustRef trust = protectionSpace.serverTrust;
    
    CFIndex numCerts = SecTrustGetCertificateCount(trust);
    NSMutableArray* certs = [NSMutableArray arrayWithCapacity: numCerts];
    for (CFIndex idx = 0; idx < numCerts; ++idx)
    {
        SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
        [certs addObject: CFBridgingRelease(cert)];
    
    }
    
    //  Create a policy that ignores the host name…
    SecPolicyRef policy = SecPolicyCreateSSL(true, NULL);  // SecPolicyCreateBasicX509();
    OSStatus err = SecTrustCreateWithCertificates(CFBridgingRetain(certs), policy, &trust);
    CFRelease(policy);
    if (err != noErr)
    {
        //NSLogDebug(@"Error creating trust: %d", err);
        [challenge.sender cancelAuthenticationChallenge: challenge];
        return;
    }
    
    //  Set the root cert and evaluate the trust…
    NSURL* certURL = [[NSBundle mainBundle] URLForResource: @"doorbird_certificate" withExtension: @"der"];
    NSData* certData = [NSData dataWithContentsOfURL: certURL];
    SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, CFBridgingRetain(certData));
    
    NSArray* rootCerts = @[ CFBridgingRelease(rootCert) ];
    err = SecTrustSetAnchorCertificates(trust, CFBridgingRetain(rootCerts));
    if (err == noErr)
    {
        SecTrustResultType trustResult;
        err = SecTrustEvaluate(trust, &trustResult);
        SecTrustSetAnchorCertificatesOnly(trust, YES);
        NSURLCredential* credential = [NSURLCredential credentialForTrust: trust];
    
        CFRelease(trust);
    
        bool trusted = err == noErr;
        trusted = trusted && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified);
        if (trusted)
        {
    
            [challenge.sender useCredential: credential forAuthenticationChallenge: challenge];
            return;
        }
    }
    
    //  An error occurred, or we don't trust the cert, so disallow it…
    
    [challenge.sender cancelAuthenticationChallenge: challenge];
    

    但只有至少 1024 位的证书有效。 512 位的证书没有。有人可以确认吗?

    谢谢

    编辑:

    我创建了如下所述的证书:

    http://www.akadia.com/services/ssh_test_certificate.html

    【讨论】:

      猜你喜欢
      • 2015-12-25
      • 2021-05-21
      • 1970-01-01
      • 1970-01-01
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多