2014-02-11 6 views
6

Hier ist mein ziemlich Standard NSURLConnection Rückruf für die Verwendung von selbstsignierten Zertifikat Authentifizierung:SecTrustEvaluate nicht mit kSecTrustResultRecoverableTrustFailure für selbst signierte CA mit nicht passendem Betreff Namen

- (SecCertificateRef)certRefFromDerNamed:(NSString*)derFileName resultingDataRef:(CFDataRef*)dataRefPtr{ 
    NSString *thePath = [[NSBundle mainBundle] pathForResource:derFileName ofType:@"der"]; 
    NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath]; 
    CFDataRef certDataRef = (__bridge_retained CFDataRef)certData; 
    SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef); 
    *dataRefPtr = certDataRef; 
    return cert; 
} 

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 

if (connection == self.connection) { 

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

     SecPolicyRef policyRef = SecPolicyCreateBasicX509(); 

     SecCertificateRef cert1; 
     CFDataRef certData1; 

     cert1 = [self certRefFromDerNamed:@"some3rdpartycacert" resultingDataRef:&certData1]; 

     SecCertificateRef certArray[1] = { cert1 }; 
     CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL); 

     SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; 
     SecTrustSetAnchorCertificates(serverTrust, certArrayRef); 
     SecTrustResultType trustResult; 

     SecTrustEvaluate(serverTrust, &trustResult); 

     trusted = (trustResult == kSecTrustResultUnspecified); 

     CFRelease(certArrayRef); 
     CFRelease(policyRef); 
     CFRelease(cert1); 
     CFRelease(certData1); 
    } 
    if (trusted) { 
     [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; 
    } else { 
     [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; 
    } 
} 
} 

Und trustResult ist immer kSecTrustResultRecoverableTrustFailure.

Das Zertifikat selbst ist ein wenig problematisch. Entsprechend curl cert Subjektname auf Server stimmt nicht mit der URL überein, zu der ich mich verbinde. Ich habe diese 3rd-Party-Firma kontaktiert und sie haben mir gesagt, dass ich diese URL-Übereinstimmung in meinem Code akzeptieren muss. Das Problem ist, dass ich nicht weiß, wie man das unter iOS macht. Ich kann entweder die Zertifikatsüberprüfung vollständig umgehen (indem ich einfach trusted=YES annehme und useCredential anrufe) oder komplett fehlschlagen. Die erste Lösung ist aus Sicherheitsgründen offensichtlich falsch und anfällig für MITM-Angriffe.

Hier ist der CURL Ausgang (ich habe verwendet PEM-Version für das gleiche cert hier):

ukaszs-iMac:Preferences lukasz$ curl --verbose --cacert ~/Desktop/some3rdpartycacert.txt https://dev-service.some3rdparty.com:50101/ 
* About to connect() to dev-service.some3rdparty.com port 50101 (#0) 
* Trying XXX.XXX.XXX.XXX... 
* connected 
* Connected to dev-service.some3rdparty.com (XXX.XXX.XXX.XXX) port 50101 (#0) 
* successfully set certificate verify locations: 
* CAfile: /Users/lukasz/Desktop/some3rdpartycacert.txt 
    CApath: none 
* SSLv3, TLS handshake, Client hello (1): 
* SSLv3, TLS handshake, Server hello (2): 
* SSLv3, TLS handshake, CERT (11): 
* SSLv3, TLS handshake, Request CERT (13): 
* SSLv3, TLS handshake, Server finished (14): 
* SSLv3, TLS handshake, CERT (11): 
* SSLv3, TLS handshake, Client key exchange (16): 
* SSLv3, TLS change cipher, Client hello (1): 
* SSLv3, TLS handshake, Finished (20): 
* SSLv3, TLS change cipher, Client hello (1): 
* SSLv3, TLS handshake, Finished (20): 
* SSL connection using AES256-SHA 
* Server certificate: 
* subject: C=CA; ST=Ontario; O=Some 3rdParty Corporation; CN=otherpage.some3rdparty.com; [email protected] 
* start date: 2013-10-30 16:52:14 GMT 
* expire date: 2013-10-30 16:52:14 GMT 
* SSL: certificate subject name 'otherpage.some3rdparty.com' does not match target host name 'dev-service.some3rdparty.com' 
* Closing connection #0 
* SSLv3, TLS alert, Client hello (1): 
curl: (51) SSL: certificate subject name 'otherpage.some3rdparty.com' does not match target host name 'dev-service.some3rdparty.com' 

So, wie auf iOS diesen speziellen Fehler zu ignorieren?

Antwort

9

Sie benötigen eine spezielle Richtlinie mit dem eigentlichen Hostnamen erstellen, dann erstellen und serverTrust aus, dass zu bewerten. Ungefähr:

SecPolicyRef policyRef = SecPolicyCreateSSL(true, CFSTR("otherpage.some3rdparty.com")); 

OSStatus status; 
SecTrustRef serverTrust; 
status = SecTrustCreateWithCertificates(certificatesFromOriginalServerTrust, policyRef, & serverTrust); 
// noErr == status? 

status = SecTrustSetAnchorCertificates(serverTrust, certArrayRef); 
// noErr == status? 

SecTrustResultType trustResult; 
status = SecTrustEvaluate(serverTrust, &trustResult); 
// noErr == status? 

if(kSecTrustResultProceed == trustResult || kSecTrustResultUnspecified == trustResult) { 
    // all good 
} 

p.s. Sie verwenden nicht die von Ihnen erstellte Richtlinie.

Ich fand nur eine ausführlichere Erklärung here.

+0

toller Link, es funktioniert! Es gibt jedoch einen Fehler in ihrem Code - 'SecTrustCreateWithCertificates (CFBridgingRetain (certs), policy, & trust);' könnte fehlschlagen, wenn certs ein leeres Array ist. Mit dieser behoben funktioniert es perfekt! –

+0

Wenn es leer ist, können wir SecTrustRef verwenden. TrustRef = [[challenge protectionSpace] serverTrust]; SecTrustSetPolicies (TrustRef, policyRef); –

0

Für dieses spezielle Problem müssen Sie lesen "iOS 5 Programmierung, die Grenzen zu verschieben: Entwickeln außergewöhnliche Mobile Apps für Apple iPhone, iPad und iPod Touch" Buch. (Von Rob Napier, Mugunth Kumar)

In dem Buch am Ende der Seite 219, heißt es: „Wenn Sie mit dem Namen in Ordnung sind Sie übergeben wurden, neu zu bewerten Sie das Zertifikat als einfaches X.509 Zertifikat statt als Teil eines SSL-Handshakes (das heißt, Sie bewerten es, während Sie den Hostnamen ignorieren) "

Dann haben sie eine spezielle RNSecTrustEvaluateAsX509-Funktion. Mit dieser Funktion werten Sie also das Zertifikat aus, indem Sie den Hostnamen ignorieren und diesen Teil als "vertrauenswürdig" festlegen. Siehe http://bit.ly/1g1RzdF (Gehe zu Seite 219)

-Code aus dem Buch finden Sie hier: https://github.com/iosptl/ios5ptl/blob/master/ch11/Connection/Connection/ConnectionViewController.m

Verwandte Themen