2011-12-09 17 views
54

Estas pueden formularse como preguntas separadas para mayor claridad, pero todas están relacionadas con el mismo problema.¿Cómo se resuelven los nombres del servidor de certificados SSL? ¿Puedo agregar nombres alternativos con la herramienta de claves?

¿Cómo se resuelven los nombres del servidor de certificados SSL?

¿Por qué los navegadores parecen usar el campo CN del certificado, pero el mecanismo de Java parece solo mirar "nombres alternativos del sujeto" solamente?

¿Es posible agregar nombres alternativos a un certificado SSL usando keytool? Si no, ¿está utilizando openSSL en su lugar una buena opción?

Solo un pequeño trasfondo: Necesito obtener un servidor principal para comunicarse con varios servidores usando HTTPS. Obviamente, no queremos comprar certificados SSL para cada servidor (podría haber muchos), así que quiero usar certificados autofirmados (he estado usando keytool para generarlos). Después de agregar los certificados como confiables en el sistema operativo, los navegadores (IE y Chrome) aceptan felizmente la conexión como de confianza. Sin embargo, incluso después de la adición de los certificados a cacerts de Java, Java sigue sin aceptar la conexión como de confianza y desencadena la siguiente excepción:

Causado por: java.security.cert.CertificateException: Ningún sujeto nombres alternativos presente en sun.security.util.HostnameChecker.matchIP (HostnameChecker.java:142) en sun.security.util.HostnameChecker.match (HostnameChecker.java:75) en com.sun.net.ssl.internal.ssl. X509TrustManagerImpl.checkIdentity (X509T rustManagerImpl.java:264) en com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted ( X509TrustManagerImpl.java:250)en com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate (Clien tHandshaker.java:1185) ... 14 más

He descubierto que puedo hacer Java confiar en el certificado implementar mi propio HostNameVerifier, que copié desde aquí: com.sun.jbi.internal.security.https.DefaultHostnameVerifier solo para probar (por cierto, el nombre de host pasado como argumento para el HostnameVerifier es correcto, así que creo que debería haber sido aceptado).

He estado usando el campo de certificado CN como nombre de host (generalmente la dirección IP).

¿Alguien puede decirme si estoy haciendo algo mal y señalarme en la dirección correcta?

+1

El enlace está roto. – axiopisty

+1

Elija su alternativa: http://grepcode.com/search?query=DefaultHostnameVerifier&n= – Renato

Respuesta

82

La forma en que se debe realizar la verificación del nombre de host se define en RFC 6125, que es bastante reciente y generaliza la práctica para todos los protocolos, y reemplaza RFC 2818, que era específico de HTTPS. (No estoy siquiera seguro de Java 7 utiliza el RFC 6125, lo que podría ser demasiado reciente para este.)

De RFC 2818 (Section 3.1):

Si una extensión subjectAltName de tipo dNSName está presente, que debe usarse como la identidad. De lo contrario, DEBE utilizarse el campo de nombre común (más específico) en el campo Asunto del certificado. Aunque el uso del Nombre común es una práctica existente, está en desuso y se recomienda a las Autoridades de certificación que usen el nombre dNSName.

[...]

En algunos casos, el URI se especifica como una dirección IP en lugar de un nombre de host . En este caso, el asunto iPAddressAltName debe estar presente en el certificado y debe coincidir exactamente con la dirección IP en el URI.

Básicamente, el problema específico que tiene proviene del hecho de que está usando direcciones IP en su CN y no un nombre de host. Algunos navegadores pueden funcionar porque no todas las herramientas siguen estrictamente esta especificación, en particular porque "más específico" en RFC 2818 no está claramente definido (ver las discusiones en RFC 6215).

Si está utilizando keytool, as of Java 7, keytool tiene una opción para incluir un nombre alternativo del sujeto (véase la tabla en la documentación para -ext): usted podría utilizar -ext san=dns:www.example.com o -ext san=ip:10.0.0.1.

EDIT:

Puede solicitar una SAN en OpenSSL cambiando openssl.cnf (que captará la copia en el directorio actual si no desea modificar la configuración global, por lo que yo recuerdo, o puede elegir una ubicación explícita usando la variable de entorno OPENSSL_CONF).

establecen las siguientes opciones (Encontrar las secciones correspondientes entre paréntesis primero):

[req] 
req_extensions = v3_req 

[ v3_req ] 
subjectAltName=IP:10.0.0.1 
# or subjectAltName=DNS:www.example.com 

También hay un buen truco de utilizar una variable de entorno para esto (en lugar de que la fijación en un archivo de configuración) aquí: http://www.crsr.net/Notes/SSL.html

+0

Esto es exactamente lo que necesitaba saber ... sin embargo, parece que Java 6 no tiene esta -siguiente opción. Intentaré cambiar mi VM a Java 7 y probar esto. – Renato

+2

Tenga en cuenta que puede usar keytool desde Java 7 en una máquina diferente y copiar el almacén de claves más adelante (no es necesario que esté ejecutando Java 7). Alternativamente, he editado mi respuesta para hacerlo con OpenSSL. Dicho esto, puede que le resulte más flexible usar nombres de host en lugar de direcciones IP a largo plazo (de todos modos, usar SAN es una buena idea). – Bruno

+0

¡La opción -ext no funciona en Java6! Cambiaré a Java 7 y veré si puedo hacerlo simplemente usando la herramienta de claves ... Muchas gracias por la respuesta ... (PD. Aceptará la respuesta una vez que la haya probado) – Renato

Cuestiones relacionadas