Autenticación de certificate de cliente en iOS UIWebView funciona en iOS 6.1 pero no iOS 7

Estoy intentando utilizar la authentication del certificate del cliente para acceder a un website seguro. El código que estoy usando funciona bien en iOS 6.1, pero falla al devolver el server un error 403.7 al usar iOS 7.

Utilizo el controller connection: willSendRequestForAuthenticationChallenge para verificar el método de authentication y proporcionar el certificate del cliente.

Mi código es:

- (void)connection: (NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSLog(@"Trust Challenge"); SecTrustResultType trustResultType; OSStatus err = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType); NSLog(@"SecTrustResult %u %d",trustResultType, (int)err); if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultConfirm || trustResultType == kSecTrustResultUnspecified) { [challenge.sender useCnetworkingential:[NSURLCnetworkingential cnetworkingentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; } else{ [challenge.sender cancelAuthenticationChallenge:challenge]; } } else { NSString *path = [[NSBundle mainBundle]pathForResource:@"mycert" ofType:@"pfx"]; NSData *p12data = [NSData dataWithContentsOfFile:path]; CFDataRef inP12data = (__bridge CFDataRef)p12data; SecIdentityRef myIdentity; SecTrustRef myTrust; extractIdentityAndTrust(inP12data, &myIdentity, &myTrust); assert(myIdentity != nil); assert(myTrust != nil); long count = SecTrustGetCertificateCount(myTrust); NSMutableArray* myCertificates = nil; if(count > 1) { myCertificates = [NSMutableArray arrayWithCapacity:count]; for(int i = 1; i < count; ++i) { [myCertificates addObject:(__bridge id)SecTrustGetCertificateAtIndex(myTrust, i)]; } } NSURLCnetworkingential *cnetworkingential = [NSURLCnetworkingential cnetworkingentialWithIdentity:myIdentity certificates:myCertificates persistence:NSURLCnetworkingentialPersistenceNone]; assert(cnetworkingential != nil); NSLog(@"User: %@, certificates %@ identity:%@", [cnetworkingential user], [cnetworkingential certificates], [cnetworkingential identity]); [[challenge sender] useCnetworkingential:cnetworkingential forAuthenticationChallenge:challenge]; } } 

Utilizo esta function para extraer el contenido del certificate:

 OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust) { OSStatus securityError = errSecSuccess; CFStringRef password = CFSTR("password"); const void *keys[] = { kSecImportExportPassphrase }; const void *values[] = { password }; CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import(inP12data, options, &items); if (securityError == 0) { CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0); const void *tempIdentity = NULL; tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity); *identity = (SecIdentityRef)tempIdentity; const void *tempTrust = NULL; tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust); *trust = (SecTrustRef)tempTrust; CFIndex count = CFArrayGetCount(items); NSLog(@"Certificates found: %ld",count); } if (options) { CFRelease(options); } return securityError; } 

El file mycert.pfx contiene el certificate intermedio junto con el certificate del cliente.

La connection: la function didFailWithError nunca se llama.

 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"Error: %@", [error userInfo]); } 

Por lo tanto, parece que la negociación del certificate tiene éxito en algún nivel.

Mi problema es similar a SSL: se comporta de manera diferente en iOS7. pero estoy usando Windows Server 2008 R2 con IIS 7.5. Los protocolos TLS 1.1 y TLS 1.2 se han habilitado en el server.

Una traza de WireShark muestra que el marco del certificate durante el apretón de manos de TLS está vacío cuando se usa iOS 7. El certificate se envía y se verifica cuando se utiliza iOS 6.1.

Puedo acceder al sitio en iOS 7 usando Safari.

Cualquier ayuda es muy apreciada.

Pude encontrar una solución con la ayuda del soporte de Apple Developer. La solución implica crear un NSURLProtocol personalizado. Utilicé el código de ejemplo de Apple en https://developer.apple.com/library/ios/#samplecode/CustomHTTPProtocol/ . El código de muestra muestra cómo replace la evaluación de confianza del server HTTPS, por lo que debe modificarse para que funcione con la authentication del certificate del cliente.

Modifiqué la function AppDelegate didRecieveAuthenticationChallenge.

 - (void)customHTTPProtocol:(CustomHTTPProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge // A CustomHTTPProtocol delegate callback, called when the protocol has an authenticate // challenge that the delegate accepts via - customHTTPProtocol:canAuthenticateAgainstProtectionSpace:. // In this specific case it's only called to handle server trust authentication challenges. // It evaluates the trust based on both the global set of trusted anchors and the list of trusted // anchors returned by the CnetworkingentialsManager. { OSStatus err; NSURLCnetworkingential * cnetworkingential; assert(protocol != nil); assert(challenge != nil); cnetworkingential = nil; // Handle ServerTrust and Client Certificate challenges NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod]; if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSLog(@"Trust Challange"); SecTrustResultType trustResultType; err = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType); NSLog(@"SecTrustResult %u %d",trustResultType, (int)err); if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultUnspecified) { cnetworkingential = [NSURLCnetworkingential cnetworkingentialForTrust:challenge.protectionSpace.serverTrust]; assert(cnetworkingential != nil); } } else { NSString *path = [[NSBundle mainBundle]pathForResource:@"mycert" ofType:@"pfx"]; NSData *p12data = [NSData dataWithContentsOfFile:path]; SecIdentityRef identity = NULL; SecCertificateRef certificate = NULL; [Util identity:&identity andCertificate:&certificate fromPKCS12Data:p12data withPassphrase:@"asia1215"]; assert(identity != NULL); NSArray *certArray = [NSArray arrayWithObject:(__bridge id)certificate]; cnetworkingential = [NSURLCnetworkingential cnetworkingentialWithIdentity:identity certificates:certArray persistence:NSURLCnetworkingentialPersistencePermanent]; } [protocol resolveAuthenticationChallenge:challenge withCnetworkingential:cnetworkingential]; }