iOS y SSL: no se puede validar el certificado del servidor autofirmado


Soy bastante nuevo para consumir servicios web utilizando el canal SSL. Después de una búsqueda bastante buena, encontré una forma de realizar la autenticación SSL / HTTPS utilizando las API de delegado NSURLConnection. A continuación se encuentra el fragmento de código que hace la autenticación real:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[self printLogToConsole:@"Authenticating...."];
[self printLogToConsole:[NSString stringWithFormat:@"\n%@\n", [challenge description]]];
NSLog(@"\n\nserverTrust: %@\n", [[challenge protectionSpace] serverTrust]);

/* Extract the server certificate for trust validation
 */
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
assert(protectionSpace);
SecTrustRef trust = [protectionSpace serverTrust];    
assert(trust);
CFRetain(trust); // Make sure this thing stays around until we're done with it
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];


/* On iOS 
 * we need to convert it to 'der' certificate. It can be done easily through Terminal as follows:
 * $ openssl x509 -in certificate.pem -outform der -out rootcert.der
 */
NSString *path = [[NSBundle mainBundle] pathForResource:@"rootcert" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);

/* Set up the array of certificates, we will authenticate against and create credentials */
SecCertificateRef rtCertificate = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rtCertificate };
trustedCerts = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rtCertificate); // for completeness, really does not matter

/* Build up the trust anchor using our root cert */
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, trustedCerts);
if (err == noErr) {
    err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust); // OK, now we're done with it

[self printLogToConsole:[NSString stringWithFormat:@"trustResult: %d\n", trustResult]];

/* http://developer.apple.com/library/mac/#qa/qa1360/_index.html
 */
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));

// Return based on whether we decided to trust or not
if (trusted) {
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    [self printLogToConsole:@"Success! Trust validation successful."];
} else {
    [self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}

}

Pero estoy recibiendo el siguiente error:

2012-06-11 17:10:12.541 SecureLogin[3424:f803] Error during connection: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x682c790 {NSErrorFailingURLKey=https://staging.esecure.url/authentication/signin/merchants, NSErrorFailingURLStringKey=https://staging.esecure.url/authentication/signin/merchants}


Estoy usando el mismo certificado que obtuve del servidor y lo convertí al formato 'der'. Estoy construyendo una aplicación para iOS 5.x. No estoy seguro de si me estoy perdiendo algo. Déjame saber de tus sugerencias.

Gracias.

EDITAR Después de examinar el certificado aquí, cómo se ve la salida:


Déjame saber si hay algo mal.

Gracias.

Respuestas a la pregunta(2)

Su respuesta a la pregunta