2011-10-26 8 views
5

Ứng dụng của tôi cố đánh giá chứng chỉ tin cậy máy chủ cho chứng chỉ tự ký. Đây là hoạt động tốt với SecPolicyCreateBasicX509 nhưng không làm việc cho SecPolicyCreateSSLSecTrustEvaluate luôn trả về kSecTrustResultRecoverableTrustFailure với SecPolicyCreateSSL

Đây là mã của tôi:

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

Sau rất nhiều nghiên cứu tôi đã thực hiện thay đổi đối với chứng chỉ tự ký bằng cách thêm phần mở rộng như đề cập trong này bài đăng: Unable to trust a self signed certificate on iphone

Có ai có gợi ý nào khác về điều gì có thể bị thiếu ở đây không?

Trả lời

6

Sau nhiều lần kiểm tra, tôi đã giải quyết được vấn đề này. Sau đây đã được thay đổi.

  • Chính sách được đặt thành KHÔNG để đánh giá máy chủ. Điều này có nghĩa là chứng chỉ được kiểm tra để xác thực ứng dụng khách. Rõ ràng là chứng chỉ máy chủ sẽ không có điều này! Đặt cài đặt này thành YES sẽ thực sự kiểm tra xem extendedKeyUsage có được đặt thành serverAuth cho chứng chỉ máy chủ hay không.

  • SecTrustSetAnchorCertificatesSecTrustSetAnchorCertificatesOnly phải luôn được gọi trước khi đánh giá và không chỉ khi bạn đang cung cấp chứng chỉ neo của riêng mình. Bạn cần gọi điều này với một mảng trống, nếu không thì các chứng chỉ neo đã biết của hệ thống không được sử dụng để đánh giá. Ngay cả khi cài đặt chứng chỉ gốc đáng tin cậy từ MDM cũng đang hoạt động.

Đây là một mẫu làm việc dựa trên mã đầu tiên:

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

Hy vọng điều này sẽ giúp một ai đó.

+0

'kSecTrustResultConfirm' không được chấp nhận bắt đầu từ iOS7. –

3

Nó có thể là một vấn đề chứng chỉ máy chủ ....

Kiểm tra here, tôi giải quyết kSecTrustResultRecoverableTrustFailure vấn đề của tôi, thêm subjectAltName = DNS:example.com vào tập tin cấu hình openssl, đặc biệt trong máy chủ thế hệ then chốt ...

Nếu bạn không sử dụng openssl để tạo ra nó, tôi xin lỗi nhưng tôi có thể giúp bạn .. Dù sao nếu bạn muốn sử dụng openssl, here là một hướng dẫn tốt để tạo ra các khóa đó và sau đó ký với cơ quan chứng chỉ gốc của riêng bạn.

Từ hướng dẫn này, tôi chỉ cần thay đổi tập tin cấu hình máy chủ openssl tôi để:

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

Hy vọng nó sẽ giúp!