Estoy creando una aplicación para iOS que se comunica con un servidor web mediante TLS. Cuando accedo al servidor web, presenta un certificado a mi dispositivo y me gustaría validar que puedo confiar en él.

Tengo el certificado raíz incrustado en mi proyecto xcode como un archivo der. El código que tengo hasta ahora obtiene versiones NSString de ambos certificados en la función delegada de NSURLConnection para el desafío de autenticación.

¿Alguna idea sobre cómo validar manualmente?

Aquí está mi código actual:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(@"Certificate challenge");
if (self.stageNum==0) {
    id <NSURLAuthenticationChallengeSender> sender=challenge.sender;
    NSURLProtectionSpace *protectionSpace=challenge.protectionSpace;
    SecTrustRef trust=[protectionSpace serverTrust];

    //Get server certificate
    SecCertificateRef certificate=SecTrustGetCertificateAtIndex(trust, 0);
    NSData *serverCertificateData=(__bridge NSData *)SecCertificateCopyData(certificate);
    NSString *serverBase64Certificate=[serverCertificateData base64EncodedStringWithOptions:0];

    //Get our certificate
    NSData *certData1 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"SUMOSRoot" ofType:@"der"]];
    NSString *certBase64=[certData1 base64EncodedStringWithOptions:0];

    //Heres where I need to compare the certificates
    //
    //

    [sender useCredential:[NSURLCredential credentialForTrust:protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
}
1
Ian Richard 13 ago. 2016 a las 00:24

2 respuestas

La mejor respuesta

Creo que esta publicación resuelve tu propósito. Bellamente escrito / explicado.

http://www.techrepublic.com/blog/software-engineer/use-https-certificate-handling-to-protect-your-ios-app/

Las personas que son demasiado perezosas para abrir los enlaces, agregaré una descripción aquí de la publicación.

enter image description here

2
Community 8 feb. 2017 a las 15:11

No estoy seguro de por qué querría obtener una representación de NSString. Una vez que tenga un SecTrustRef, puede llamar a SecTrustCopyPublicKey para copiar la clave pública a un SecKeyRef, luego compararlo con los datos de la clave original (bytes sin procesar). Si las claves públicas coinciden, debe aceptar el certificado.

Esta técnica se llama "fijación de certificados", y estoy seguro de que probablemente haya una serie de respuestas aquí en Stack Overflow que pueden proporcionar muestras de código completo si busca ese término.

Aparentemente, también podría comparar los certificados, pero probablemente eso no sea lo que quiera hacer, porque los certificados caducan periódicamente y deben actualizarse. Si compara la clave, seguirá funcionando incluso si regeneran el certificado (suponiendo que lo regeneren con el mismo par de claves privada / pública).

O si está dispuesto a vincularlo a un certificado raíz privado de larga duración en particular, puede simplemente agregarlo a la lista de anclajes confiables y reevaluar el objeto de confianza, con la advertencia de que esto se romperá cuando expire ese certificado raíz privado. Por otro lado, si fija la clave, se romperá si alguna vez tiene que cambiar la clave privada por alguna razón ... así que es una compensación.

Por supuesto, la mejor opción en general, si es posible, es obtener un certificado de CA real y no meterse con ninguna de las validaciones de la cadena, pero supongo que esto no es posible (por ejemplo, porque el servidor es en un dominio .local, en un dispositivo físico que genera su propio certificado sin acceso a Internet, o alguna otra razón similar). Entonces, para cosas como la comunicación segura con una pieza arbitraria de hardware en una red .local, la fijación de claves es el mejor enfoque. Si la clave no coincide, solicite al usuario que la agregue como un nuevo dispositivo o lo que sea.

1
dgatwood 13 ago. 2016 a las 06:50