2011-10-26 13 views
5

Mi aplicación intenta evaluar un certificado de confianza del servidor para un certificado autofirmado. Esto funciona bien con SecPolicyCreateBasicX509 pero no funciona para SecPolicyCreateSSLSecTrustEvaluate siempre devuelve kSecTrustResultRecoverableTrustFailure con SecPolicyCreateSSL

Aquí está mi código:

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

Después de mucha investigación ya he realizado cambios en el certificado autofirmado mediante la adición de extensión como se ha mencionado en este publicación: Unable to trust a self signed certificate on iphone

¿Alguien tiene otra pista que podría faltar aquí?

Respuesta

6

Después de muchas pruebas resolví este problema. Lo siguiente ha sido cambiado.

  • La política se establece en NO para la evaluación del servidor. Esto significa que el certificado se verifica para la autenticación del cliente. ¡Obviamente el certificado del servidor no tendrá esto! Establecer esto en SÍ realmente comprobará si extendedKeyUsage está establecido en serverAuth para el certificado del servidor.

  • SecTrustSetAnchorCertificates y SecTrustSetAnchorCertificatesOnly siempre se deben llamar antes de la evaluación y no solo si está proporcionando sus propios certificados de anclaje. Debe llamar esto con un conjunto vacío, de lo contrario, los certificados de anclaje conocidos del sistema no se utilizan para la evaluación. Incluso los certificados raíz confiables instalados de MDM funcionan entonces.

Este es un ejemplo de trabajo basada en el primer código:

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

Esperamos que esto ayude a alguien.

+0

'kSecTrustResultConfirm' está en desuso a partir de iOS7. –

3

Puede ser un problema de certificado de servidor ....

Comprobar here, he resuelto mi problema kSecTrustResultRecoverableTrustFailure, añadiendo subjectAltName = DNS:example.com en el archivo de configuración de OpenSSL, específicamente en la generación de claves del servidor ...

Si no está usando openssl para generarlo, lo siento pero puedo ayudarlo ... De todas formas, si quiere usar openssl, here es un buen tutorial para generar esas claves y luego firmarlo con su propia autoridad de certificación raíz.

De este tutorial, acabo de cambiar mi archivo de configuración del servidor OpenSSL para:

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

espero que ayude!

Cuestiones relacionadas