change certificates accept ios ssl https openssl activesync

certificates - iOS NSURLAuthenticationMethodClientCertificate no solicitado vs servidor ActiveSync



iphone accept certificate (1)

Como nadie respondió esto, y finalmente llegué a una solución funcional, aquí está.

La confianza del servidor no es un desafío del servidor al cliente, es una oportunidad para que el cliente valide la confianza ofrecida por el servidor. Con eso en mente, el código a continuación no verifica esa confianza, pero podría hacerlo.

Normalmente obtiene el NSURLAuthenticationMethodServerTrust, luego obtiene el NSURLAuthenticationMethodClientCertificate. No es ni-o. Aquí está el código de trabajo.

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; NSString *authenticationMethod = [protectionSpace authenticationMethod]; if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate] && self.accountCertKeychainRef != nil) { SecIdentityRef identity = [KeychainUtilities retrieveIdentityWithPersistentRef:self.accountCertKeychainRef]; NSURLCredential* credential = [CertificateUtilities getCredentialFromCert:identity]; if ( credential == nil ) { [[challenge sender] cancelAuthenticationChallenge:challenge]; } else { [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } } else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; } else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM] || [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]) { self.lastProtSpace = [challenge protectionSpace]; if ([challenge previousFailureCount] > 2) { [[challenge sender] cancelAuthenticationChallenge:challenge]; } else { [[challenge sender] useCredential:[self buildCredential] forAuthenticationChallenge:challenge]; } } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; } }

Para la siguiente pregunta, aquí le mostramos cómo puede obtener la identidad:

+ (SecIdentityRef)copyIdentityAndTrustWithCertData:(CFDataRef)inPKCS12Data password:(CFStringRef)keyPassword { SecIdentityRef extractedIdentity = nil; OSStatus securityError = errSecSuccess; const void *keys[] = {kSecImportExportPassphrase}; const void *values[] = {keyPassword}; CFDictionaryRef optionsDictionary = NULL; optionsDictionary = CFDictionaryCreate(NULL, keys, values, (keyPassword ? 1 : 0), NULL, NULL); CFArrayRef items = NULL; securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); if (securityError == errSecSuccess) { CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0); // get identity from dictionary extractedIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity); CFRetain(extractedIdentity); } if (optionsDictionary) { CFRelease(optionsDictionary); } if (items) { CFRelease(items); } return extractedIdentity; }

Para aquellos interesados, aquí está getCredentialForCert:

+ (NSURLCredential *)getCredentialFromCert:(SecIdentityRef)identity { SecCertificateRef certificateRef = NULL; SecIdentityCopyCertificate(identity, &certificateRef); NSArray *certificateArray = [[NSArray alloc] initWithObjects:(__bridge_transfer id)(certificateRef), nil]; NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession; NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identity certificates:certificateArray persistence:persistence]; return credential; }

Estoy intentando implementar la autenticación de certificado en un cliente de ActiveSync que estoy desarrollando. El código para usar la autenticación del certificado podría funcionar, pero a partir de ahora el servidor, o más exactamente, la interpretación de la biblioteca del iOS de la respuesta del servidor, me parece incorrecto. Aquí está mi código:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; NSString *authenticationMethod = [protectionSpace authenticationMethod]; if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) { NSURLCredential* credential = [ self buildCredentialClientCert]; if ( credential == nil ) { [[challenge sender] cancelAuthenticationChallenge:challenge]; } else { [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } } else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { .... // do other stuff

El problema es que, aunque sé que el servidor admite la autenticación del certificado del cliente, cuando configuro un punto de interrupción, authenticationMethod siempre se establece en NSURLAuthenticationMethodServerTrust .

La respuesta del servidor HTTPS sin formato contiene lo siguiente:

Código de error: 403 Prohibido. La página requiere un certificado de cliente como parte del proceso de autenticación. Si está utilizando una tarjeta inteligente, deberá insertar su tarjeta inteligente para seleccionar un certificado apropiado. De lo contrario, póngase en contacto con su administrador de servidor. (12213)

Mi pregunta es, ¿qué determina si el desafío de autenticación es NSURLAuthenticationMethodServerTrust versus NSURLAuthenticationMethodClientCertificate ?