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?
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! –
Wenn es leer ist, können wir SecTrustRef verwenden. TrustRef = [[challenge protectionSpace] serverTrust]; SecTrustSetPolicies (TrustRef, policyRef); –