Usar openssl para obtener el certificado de un servidor

Estoy tratando de obtener el certificado de un servidor remoto, que luego puedo usar para agregar a mi almacén de claves y usar 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 procesar arrojado, 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 he intentado con esta opción

 -showcerts 

y este (corriendo en Debian te importa)

 -CApath /etc/ssl/certs/ 

Pero obtén el mismo error

Esta fuente dice que puedo usar esa bandera de CApath, pero no parece ayudar. Intenté varias rutas sin resultado.

Por favor, hágame saber dónde me estoy equivocando.

Con SNI

Si el servidor remoto está utilizando SNI (es decir, compartiendo múltiples 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  

Sin SNI

Si el servidor remoto no está utilizando SNI, entonces puede omitir el parámetro -servername :

 openssl s_client -showcerts -connect www.example.com:443  

Para ver todos los detalles del certificado de un sitio, también puede usar esta cadena de comandos:

 $ echo | \ openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \ openssl x509 -text 

Si bien estoy de acuerdo con la respuesta de Ari (y la modifiqué :), tuve que dar un paso más para que funcione con Java en Windows (donde tenía que implementarse):

 openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > derp.der 

Antes de agregar la conversión openssl x509 -outform DER , recibí un error de keytool en Windows quejándose del formato del certificado. La importación del archivo .der funcionó bien.

Resulta que aquí hay más complejidad: necesitaba proporcionar muchos más detalles para poner esto en marcha. Creo que tiene algo que ver con el hecho de que es una conexión que necesita autenticación de cliente, y el Hankshake necesitaba más información para continuar a la etapa donde se arrojaron 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 

Esperemos que esto sea un empujón en la dirección correcta para cualquiera que pueda hacer algo más de información.

La línea de comando más fácil para esto, que incluye la salida PEM para agregarla al almacén de claves, así como una salida legible por humanos y también admite SNI, que es importante si está trabajando con un servidor HTTP es:

 openssl s_client -servername example.com -connect example.com:443 \ /dev/null | openssl x509 -text 

La opción -servername es para habilitar el soporte SNI y el openssl x509 -text imprime el certificado en formato legible para humanos.

Para obtener el certificado del servidor remoto, puede usar la herramienta openssl y puede encontrarla entre BEGIN CERTIFICATE y END CERTIFICATE que debe copiar y pegar en su archivo de certificado (CRT).

Aquí está el comando que lo demuestra:

 ex +'/BEGIN CERTIFICATE/,/END CERTIFICATE/p' < (echo | openssl s_client -showcerts -connect example.com:443) -scq > file.crt 

Para devolver todos los certificados de la cadena, simplemente agregue g (global) como:

 ex +'g/BEGIN CERTIFICATE/,/END CERTIFICATE/p' < (echo | openssl s_client -showcerts -connect example.com:443) -scq 

Luego, simplemente puede importar su archivo de certificado ( file.crt ) a su llavero y hacerlo confiable, por lo que Java no debería quejarse.

En OS X puede hacer doble clic en el archivo o arrastrar y soltar en su Acceso a Llaveros, por lo que aparecerá en el inicio de sesión / Certificados. Luego haga doble clic en el certificado importado y hágalo siempre confiable para SSL .

En CentOS 5 puede /etc/pki/tls/certs/ca-bundle.crt archivo /etc/pki/tls/certs/ca-bundle.crt (y ejecutar: sudo update-ca-trust force-enable ), o en CentOS 6 copiarlos en /etc/pki/ca-trust/source/anchors/ y ejecuta sudo update-ca-trust extract .

En Ubuntu, cópielos en /usr/local/share/ca-certificates y ejecute sudo update-ca-certificates .

Puede obtener y almacenar el certificado raíz del servidor utilizando el siguiente script bash:

 CERTS=$(echo -n | openssl s_client -connect $HOST_NAME:$PORT -showcerts | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p') echo "$CERTS" | awk -v RS="-----BEGIN CERTIFICATE-----" 'NR > 1 { printf RS $0 > "'$SERVER_ROOT_CERTIFICATE'"; close("'$SERVER_ROOT_CERTIFICATE'") }' 

Simplemente sobrescriba las variables requeridas.

 HOST=gmail-pop.l.google.com PORT=995 openssl s_client -servername $HOST -connect $HOST:$PORT < /dev/null 2>/dev/null | openssl x509 -outform pem 

para imprimir solo la cadena de certificados y no el certificado del servidor:

 # MYHOST=myhost.com # MYPORT=443 # openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null  

para actualizar la confianza de CA en CentOS / RHEL 6/7:

 # update-ca-trust enable # openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null /etc/pki/ca-trust/source/anchors/myca.cert # update-ca-trust extract 

en CentOS / RHEL 5:

 # openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null >/etc/pki/tls/certs/ca-bundle.crt 

Para el beneficio de otros como yo, que intentaron seguir los buenos consejos aquí al acceder a AWS CloudFront pero fallaron, el truco es agregar -servername domain.name..

Fuente: https://serverfault.com/a/780450/8972