SecTrustEvaluate始终使用SecPolicyCreateSSL返回kSecTrustResultRecoverableTrustFailure

我的应用程序尝试评估一个自签名证书的服务器信任证书。 这与SecPolicyCreateBasicX509正常工作,但不适用于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上信任自签名证书

有没有人有另一个提示什么可能会在这里失踪?

经过大量的testing,我已经解决了这个问题。 以下已被更改。

  • 该策略设置为NO用于服务器评估。 这意味着证书被检查客户端authentication。 显然服务器证书不会有这个! 将其设置为YES将实际检查是否extendedKeyUsage设置为serverAuth作为服务器证书。

  • SecTrustSetAnchorCertificatesSecTrustSetAnchorCertificatesOnly应始终在评估之前调用,而不仅仅是在您提供自己的锚定证书时。 你需要用一个空数组来调用它,否则系统已知的锚定证书不能用于评估。 即使从MDM安装受信任的根证书正在工作。

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

 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]; } } 

希望这会帮助别人。

这可能是一个服务器证书问题….

在这里检查,我解决了我的kSecTrustResultRecoverableTrustFailure问题,添加subjectAltName = DNS:example.com到opensslconfiguration文件,特别是在服务器密钥生成…

如果你不使用openssl来生成它,我很抱歉,但我可以帮你。无论如何,如果你想使用openssl, 这是一个很好的教程来生成这些密钥,然后用自己的根证书颁发机构签名。

在本教程中,我只是将我的openssl服务器configuration文件更改为:

     [服务器]
     basicConstraints = critical,CA:FALSE
     keyUsage = digitalSignature,keyEncipherment,dataEncipherment
     extendedKeyUsage = serverAuth
     nsCertType =服务器
     subjectAltName = IP:10.0.1.5,DNS:office.totendev.com
    

希望能帮助到你 !