¿Cómo verifica que un certificado pertenece a un dominio?

4

Estoy usando PHP e intento verificar que un certificado SSL pertenece al dominio SMTP / IP al que me estoy conectando.

Actualmente puedo verificar que el certificado es válido usando el siguiente código

$resource = fsockopen( "tcp://mail.example.com", 25, $errno, $errstr ); 

...

stream_set_blocking($resource, true);

stream_context_set_option($resource, 'ssl', 'verify_host', true);
stream_context_set_option($resource, 'ssl', 'verify_peer', true);
stream_context_set_option($resource, 'ssl', 'allow_self_signed', false);

stream_context_set_option($resource, 'ssl', 'cafile', __DIR__ . '/cacert.pem');

$secure = stream_socket_enable_crypto($resource, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
stream_set_blocking($resource, false);

if( ! $secure)
{
    die("failed to connect securely\n");
}

Según la documentación parece que debo hacer algo como esto.

stream_context_set_option($resource, 'ssl', 'SNI_enabled', true);
stream_context_set_option($resource, 'ssl', 'SNI_server_name', 'expected.example.com');

¿Cómo verifico que el servidor al que me estoy conectando también tenga un certificado válido para expected.example.com ? ¿Debo hacer un chequeo de rDNS primero? ¿Qué pasa si el DNS fue alterado por un ataque MITM?

    
pregunta Xeoncross 17.11.2012 - 20:49
fuente

3 respuestas

5

SNI es Indicación del nombre del servidor ; no es parte de ninguna verificación . Un cliente utiliza SNI para informar al servidor sobre el nombre que el cliente está tratando de alcanzar; el nombre se envía en los primeros pasos del protocolo de enlace SSL. Está pensado para admitir múltiples servidores (es decir, varios nombres ) que comparten la misma dirección IP: el SNI le dice al servidor qué certificado debe usar para esta conexión en particular.

La elección de este certificado es importante porque los clientes esperan que el certificado del servidor contenga el nombre al que desean acceder. Y esta "expectativa" es precisamente lo que debe hacer: debe informar a su implementación SSL que desea llegar a un servidor con un nombre específico ( mail.example.com , aparentemente) y que el certificado del servidor DEBE contener ese nombre (esto es crucial : sin esta prueba, un atacante activo podría darle su propio certificado y secuestrar su conexión en silencio). Parece que esto se hace con la opción CN_match .

(Por supuesto que puede usar SNI; incluso se recomienda porque realmente puede ayudar al servidor. Pero eso no es SNI, que lo protege contra los ataques MitM). / p>     

respondido por el Thomas Pornin 04.12.2012 - 01:53
fuente
3

La forma típica de definir la validez es una serie de comprobaciones: a veces se omiten las comprobaciones posteriores, si el riesgo de no realizarlas se considera lo suficientemente bajo.

  1. Hay una prueba de que el remitente tiene el control de la clave privada: en una transacción SSL, esto se maneja como parte del protocolo de enlace.

  2. El certificado está construido y firmado correctamente; tiene una validez firma: apostaría a que la línea de comandos para "Verify_peer" logra esto (calificación: nunca lo he hecho en PHP)

  3. El certificado está firmado por una fuente confiable - significa que no puede usar un certificado autofirmado sin almacenar una copia en caché. Normalmente, debe aprovisionar el servidor con una colección de CA confiables. Probablemente cubierto por su comando haciendo referencia a que allow_self_signed es falso.

  4. El certificado no ha caducado: verificar la fecha de validez lo hará. No estoy seguro de que alguno de tus códigos esté haciendo esto, no es un hecho, debes probarlo y revisar la documentación más a fondo.

  5. El certificado está en buen estado (no se ha revocado) con la CA emisora; implica verificar la CRL de la CA o realizar una solicitud de OCSP. La CA revocará el certificado si hay motivos para dudar de que el par de claves permanezca en manos privadas de la fuente. No veo ningún código en tu biblioteca que proporcione esto. No es inusual: varias veces he tenido que hacer que los grupos con los que trabajo usen bibliotecas adicionales para agregar este control. Aquí es donde muchos desarrolladores web comienzan a saltear los pasos, ya que el riesgo es lo suficientemente bajo.

Como complemento, algunas políticas de seguridad determinarán que el certificado debe representar correctamente el servidor que lo proporciona. Para un servidor web, esto suele ser que el Nombre común (CN) del certificado coincide con el DNS del host con el que se está contactando (consulte enlace para un ejemplo). Otros sistemas también pueden verificar el Nombre alternativo del sujeto (también disponible en el certificado de Google, por ejemplo).

Esto no está totalmente estandarizado. Los RFC describirán los usos y formatos potenciales de estos campos, pero depende de la política de seguridad de su entidad indicar claramente lo que se requiere aquí.

Normalmente, para este tipo de verificación, he:

  • Tenía acceso al DNS deseado para la conexión
  • Se hizo la conexión, se obtuvo el certificado
  • Extrajo el certificado de la conexión y verificó que el CN o el Nombre alternativo del sujeto coincidían con lo que originalmente pedí en el primer paso.

Eso, combinado con la CA de confianza es suficiente para verificar que:

  • una entidad en la que confías
  • verificó que obtuvo lo que pidió

El paso 4 en la lista anterior es la garantía adicional de que en el tiempo transcurrido entre la CA que expide el certificado y ahora, nada ha cambiado.

    
respondido por el bethlakshmi 14.05.2013 - 19:21
fuente
2

Hacer esto tú mismo está lleno de problemas. Uno que se mencionó es que debe verificar si el certificado ha sido revocado, lo que implica ponerse en contacto con la Autoridad de Certificación de confianza. Y rechazar el certificado si ese contacto falla. Otro es que el nombre común en el certificado es una secuencia de bytes, que puede incluir cero bytes. Por ejemplo, cuando se comunica con www.amazon.com, espera que el nombre común sea de 14 bytes. Podría ser más bytes, con el byte # 14 siendo cero, un ataque que muchas implementaciones no pudieron detectar. Mucho mejor usar una biblioteca que se actualiza regularmente.

    
respondido por el gnasher729 15.03.2014 - 13:39
fuente

Lea otras preguntas en las etiquetas