Usando openssl para obtener el certificado de un servidor
Estoy intentando obtener el certificado de un servidor remoto, que luego puedo usar para agregarlo a mi almacén de claves y usarlo dentro de mi aplicación Java.
Un desarrollador senior (que está de vacaciones :() me informó que puedo ejecutar esto:
openssl s_client -connect host.host:9999
para obtener un certificado sin formato, que luego puedo copiar y exportar. Recibo el siguiente resultado:
depth=1 /C=NZ/ST=Test State or Province/O=Organization Name/OU=Organizational Unit Name/CN=Test CA
verify error:num=19:self signed certificate in certificate chain
verify return:0
23177:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1086:SSL alert number 40
23177:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:188:
También lo he probado con esta opción:
-showcerts
y este (ejecutándose en Debian, claro está):
-CApath /etc/ssl/certs/
Pero me sale el mismo error.
Esta fuente dice que puedo usar ese indicador CApath pero no parece ayudar. Intenté varios caminos sin éxito.
Por favor, déjame saber dónde me estoy equivocando.
Con SNI
Si el servidor remoto utiliza SNI (es decir, comparte varios hosts SSL en una única dirección IP), deberá enviar el nombre de host correcto para obtener el certificado correcto.
openssl s_client -showcerts -servername www.example.com -connect www.example.com:443 </dev/null
Si recibe un error similar a xxx:error:xxx:BIO routines:BIO_lookup_ex:system lib:crypto/bio/bio_addr.c:758:nodename nor servname provided, or not known connect:errno=0
, ejecute el mismo comando sin ya www
que es posible que el dominio no lo admita.
También puede estar Secure Renegotiation IS NOT supported
detrás de un firewall corporativo, en cuyo caso, una solución temporal (pero peligrosa) es el -legacy_renegotiation
parámetro que se puede agregar al comando anterior.
Sin SNI
Si el servidor remoto no utiliza SNI, puede omitir -servername
el parámetro:
openssl s_client -showcerts -connect www.example.com:443 </dev/null
Para ver los detalles completos del certificado de un sitio, también puede utilizar esta cadena de comandos:
$ echo | \
openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \
openssl x509 -text
Una sola línea para extraer el certificado de un servidor remoto en formato PEM, esta vez usando sed
:
openssl s_client -connect www.google.com:443 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
Si bien estoy de acuerdo con la respuesta de Ari (y la voté :), necesitaba hacer un paso adicional para que funcionara con Java en Windows (donde era necesario implementarlo):
openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > derp.der
Antes de agregar la openssl x509 -outform DER
conversión, recibí un error de keytool en Windows quejándose del formato del certificado. Importar el archivo .der funcionó bien.
Resulta que aquí hay más complejidad: necesitaba proporcionar muchos más detalles para que esto funcionara. Creo que tiene algo que ver con el hecho de que es una conexión que necesita autenticación del cliente y el hankshake necesitaba más información para continuar hasta la etapa en la que se descartaron los certificados.
Aquí está mi comando de trabajo:
openssl s_client -connect host:port -key our_private_key.pem -showcerts \
-cert our_server-signed_cert.pem
Con suerte, esto es un empujón en la dirección correcta para cualquiera a quien le vendría bien más información.