SecTrustEvaluate始终使用SecPolicyCreateSSL返回kSecTrustResultRecoverableTrustFailure [英] SecTrustEvaluate always returns kSecTrustResultRecoverableTrustFailure with SecPolicyCreateSSL

查看:880
本文介绍了SecTrustEvaluate始终使用SecPolicyCreateSSL返回kSecTrustResultRecoverableTrustFailure的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序尝试评估自签名证书的服务器信任证书。这适用于SecPolicyCreateBasicX509,但不适用于SecPolicyCreateSSL

My application tries to evaluate a server trust certificate for a self signed certificate. This is working fine with SecPolicyCreateBasicX509 but not working for SecPolicyCreateSSL

这是我的代码:

if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
        // create trust from protection space
        SecTrustRef trustRef;
        int trustCertificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);

        NSMutableArray* trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount];
        for (int i = 0; i < trustCertificateCount; i++) {
            SecCertificateRef trustCertificate =  SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
            [trustCertificates addObject:(id) trustCertificate];
        }            

        // set evaluation policy
        SecPolicyRef policyRef;
        // policyRef = SecPolicyCreateBasicX509(); this is working
        policyRef = SecPolicyCreateSSL(NO, (CFStringRef)             
        SecTrustCreateWithCertificates((CFArrayRef) trustCertificates, policyRef, &trustRef);

        [trustCertificates release];

        // load known certificates from keychain and set as anchor certificates
        NSMutableDictionary* secItemCopyCertificatesParams = [[NSMutableDictionary alloc] init];    
        [secItemCopyCertificatesParams setObject:(id)kSecClassCertificate forKey:(id)kSecClass];
        [secItemCopyCertificatesParams setObject:@"Server_Cert_Label" forKey:(id)kSecAttrLabel];
        [secItemCopyCertificatesParams setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
        [secItemCopyCertificatesParams setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];

        CFArrayRef certificates;
        certificates = nil;
        SecItemCopyMatching((CFDictionaryRef) secItemCopyCertificatesParams, (CFTypeRef*) &certificates);

        if (certificates != nil && CFGetTypeID(certificates) == CFArrayGetTypeID()) {
            SecTrustSetAnchorCertificates(trustRef, certificates);
            SecTrustSetAnchorCertificatesOnly(trustRef, NO);
        }

        SecTrustResultType result;
        OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result);
        if (trustEvalStatus == errSecSuccess) {
            if (result == kSecTrustResultConfirm || result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
                // evaluation OK
                [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
            } else {
                // evaluation failed 
                // ask user to add certificate to keychain
        } else {
            // evaluation failed - cancel authentication
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }
}

经过大量研究后,我已经对通过添加此帖中提到的扩展名来自签名证书:无法信任iphone上的自签名证书

After a lot of research i have already made changes to the self-signed certificate by adding extension like mentioned in this post: Unable to trust a self signed certificate on iphone

有没有人有另外提示可能会缺少什么?

Does anyone have another hint what might be missing here?

推荐答案

经过大量测试后,我解决了这个问题。以下内容已更改。

After a lot of testing I have worked out this problem. The following has been changed.


  • 对于服务器评估,策略设置为NO。这意味着将检查证书以进行客户端身份验证。显然服务器证书不会有这个!将此设置为YES将实际检查服务器证书的 extendedKeyUsage 是否设置为 serverAuth

SecTrustSetAnchorCertificates SecTrustSetAnchorCertificatesOnly 应始终在评估前调用,而不仅仅是如果您提供自己的锚证书。您需要使用空数组调用此方法,否则系统已知的锚证书不会用于评估。甚至从MDM安装的受信任的根证书也正常工作。

SecTrustSetAnchorCertificates and SecTrustSetAnchorCertificatesOnly should always be called before evaluation and not only if you are providing your own anchor certificates. You need to call this with an empty array, otherwise the system known anchor certificates are not used for evaluation. Even installed trusted root certificates from MDM are working then.

这是基于第一个代码的工作示例:

Here is a working sample based on the first code:

if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
    // create trust from protection space
    SecTrustRef trustRef;
    int trustCertificateCount = SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);

    NSMutableArray* trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount];
    for (int i = 0; i < trustCertificateCount; i++) {
        SecCertificateRef trustCertificate =  SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
        [trustCertificates addObject:(id) trustCertificate];
    }            

    // set evaluation policy
    SecPolicyRef policyRef;
    // set to YES to verify certificate extendedKeyUsage is set to serverAuth
    policyRef = SecPolicyCreateSSL(YES, (CFStringRef) challenge.protectionSpace.host);
    SecTrustCreateWithCertificates((CFArrayRef) trustCertificates, policyRef, &trustRef);

    [trustCertificates release];

    // load known certificates from keychain and set as anchor certificates
    NSMutableDictionary* secItemCopyCertificatesParams = [[NSMutableDictionary alloc] init];    
    [secItemCopyCertificatesParams setObject:(id)kSecClassCertificate forKey:(id)kSecClass];
    [secItemCopyCertificatesParams setObject:@"Server_Cert_Label" forKey:(id)kSecAttrLabel];
    [secItemCopyCertificatesParams setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
    [secItemCopyCertificatesParams setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];

    CFArrayRef certificates;
    certificates = nil;
    SecItemCopyMatching((CFDictionaryRef) secItemCopyCertificatesParams, (CFTypeRef*) &certificates);

    if (certificates != nil && CFGetTypeID(certificates) == CFArrayGetTypeID()) {
        SecTrustSetAnchorCertificates(trustRef, certificates);
        SecTrustSetAnchorCertificatesOnly(trustRef, NO);
    } else {
        // set empty array as own anchor certificate so system anchos certificates are used too!
        SecTrustSetAnchorCertificates(trustRef, (CFArrayRef) [NSArray array]);
        SecTrustSetAnchorCertificatesOnly(trustRef, NO);
    }

    SecTrustResultType result;
    OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result);
    if (trustEvalStatus == errSecSuccess) {
        if (result == kSecTrustResultConfirm || result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
            // evaluation OK
            [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } 
        else {
            // evaluation failed 
            // ask user to add certificate to keychain
        }
    } 
    else {
        // evaluation failed - cancel authentication
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

希望这会对某人有所帮助。

Hope this will help someone.

这篇关于SecTrustEvaluate始终使用SecPolicyCreateSSL返回kSecTrustResultRecoverableTrustFailure的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆