Usare openssl per ottenere il certificato da un server


354

Sto cercando di ottenere il certificato di un server remoto, che posso quindi utilizzare per aggiungere al mio keystore e utilizzare all'interno della mia applicazione Java.

Un senior dev (che è in vacanza :() mi ha informato che posso eseguire questo:

openssl s_client -connect host.host:9999

Per ottenere un certificato grezzo scaricato, che posso quindi copiare ed esportare. Ricevo il seguente output:

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:

Ho anche provato con questa opzione

-showcerts 

e questo (correndo su debian, attenzione)

-CApath /etc/ssl/certs/ 

Ma ottieni lo stesso errore.

Questa fonte dice che posso usare quel flag CApath ma non sembra aiutare. Ho provato più percorsi senza alcun risultato.

Per favore fatemi sapere dove sto andando storto.

Risposte:


463

Con SNI

Se il server remoto utilizza SNI (ovvero la condivisione di più host SSL su un singolo indirizzo IP) sarà necessario inviare il nome host corretto per ottenere il certificato giusto.

openssl s_client -showcerts -servername www.example.com -connect www.example.com:443 </dev/null

Senza SNI

Se il server remoto non utilizza SNI, è possibile saltare il -servernameparametro:

openssl s_client -showcerts -connect www.example.com:443 </dev/null


Per visualizzare i dettagli completi del certificato di un sito è possibile utilizzare anche questa catena di comandi:

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

3
Hmm. Ottengo ancora lo stesso errore quando provo quel comando. Ho notato che la mia versione di Openssl è "OpenSSL 0.9.8g 19 ott 2007". Hai qualche idea?
brutto pastello,

39
Utile: echo "" | openssl s_client -connect server:port -prexit 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' stackoverflow.com/a/12918442/843000
mbrownnyc

16
Script utile alternativo, da madboa.com :echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
rmeakins

9
Per renderlo un po 'più conciso, puoi sostituirlo sedcon openssl x509e leggerlo usando una sotto-shell:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
Gabe Martin-Dempesy

27
Inoltreecho | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle il

68

Mentre sono d'accordo con la risposta di Ari (e l'ho votata :), dovevo fare un passo in più per farlo funzionare con Java su Windows (dove doveva essere distribuito):

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

Prima di aggiungere la openssl x509 -outform DERconversione, ho ricevuto un errore da keytool su Windows che si lamentava del formato del certificato. L'importazione del file .der ha funzionato bene.


Dispari. Uso Java certificati PEM con keytool su Windows da Java 6 e non ho mai avuto problemi.
imgx64,

39

Si scopre che qui c'è più complessità: avevo bisogno di fornire molti più dettagli per ottenere questo risultato. Penso che abbia a che fare con il fatto che si tratta di una connessione che necessita dell'autenticazione del client e che l'hankshake necessitasse di maggiori informazioni per continuare con la fase in cui sono stati scaricati i certificati.

Ecco il mio comando funzionante:

openssl s_client -connect host:port -key our_private_key.pem -showcerts \
                 -cert our_server-signed_cert.pem

Spero che questa sia una spinta nella giusta direzione per chiunque possa fare qualche informazione in più.


6
Mi dispiace, ma la tua risposta non ha molto senso. Hai bisogno di passare il certificato al server per ottenere il certificato?
Ari Maniatis,

2
Sì. Autenticazione client AFAIK.
brutto pastello il

11
Si scopre che '-prexit' restituirà anche quei dati. Per esempio; openssl s_client -connect host: port -prexit
Robert

39

Un one-liner per estrarre il certificato da un server remoto in formato PEM, questa volta usando sed:

openssl s_client -connect www.google.com:443 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

2
Questo è quasi perfetto per estrarre il certificato, manca solo l' -servernameopzione, non so perché, ma ho dovuto usarlo per ottenere il certificato completo.
Karl.S

-servername è richiesto per l'indicazione del nome del server (SNI). La ricerca Web può espandersi sul resto.
Sam Gleske,

32

La riga di comando più semplice per questo, che include l'output PEM per aggiungerlo al keystore, nonché un output leggibile dall'uomo e supporta anche SNI, che è importante se si lavora con un server HTTP è:

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

L' opzione -servername serve per abilitare il supporto SNI e il testo -s x509 openssl stampa il certificato in un formato leggibile dall'uomo.


Puoi aggiungere al tuo -servername il tuo sottodominio, ad esempio ws.example.com invece di example.com (applicalo anche al parametro -connect).
Russellhoff,

24

Per ottenere il certificato del server remoto puoi usare lo opensslstrumento e puoi trovarlo tra BEGIN CERTIFICATEe END CERTIFICATEche devi copiare e incollare nel tuo file di certificato (CRT).

Ecco il comando che lo dimostra:

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

Per restituire tutti i certificati dalla catena, è sufficiente aggiungere g(globale) come:

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

Quindi puoi semplicemente importare il tuo file di certificato ( file.crt) nel tuo portachiavi e renderlo affidabile, quindi Java non dovrebbe lamentarsi.

Su OS X puoi fare doppio clic sul file o trascinare e rilasciare nel tuo Accesso portachiavi, quindi apparirà in login / certificati. Quindi fare doppio clic sul certificato importato e renderlo sempre attendibile per SSL .

Su CentOS 5 puoi accodarli in /etc/pki/tls/certs/ca-bundle.crtfile (ed eseguirli sudo update-ca-trust force-enable:), oppure in CentOS 6 copiarli /etc/pki/ca-trust/source/anchors/ed eseguirli sudo update-ca-trust extract.

In Ubuntu, copiali /usr/local/share/ca-certificatesed eseguili sudo update-ca-certificates.


12
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

6

per stampare solo la catena di certificati e non il certificato del server:

# MYHOST=myhost.com
# MYPORT=443
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}'

aggiornare la fiducia della CA su CentOS / RHEL 6/7:

# update-ca-trust enable
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >/etc/pki/ca-trust/source/anchors/myca.cert
# update-ca-trust extract

su CentOS / RHEL 5:

# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >>/etc/pki/tls/certs/ca-bundle.crt

Esattamente quello di cui avevo bisogno su CentOS7. Grazie!
Arthur Hebert,

5

Puoi ottenere e archiviare il certificato radice del server usando il prossimo 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'") }'

Basta sovrascrivere le variabili richieste.


4

Se il tuo server è un server di posta elettronica (MS Exchange o Zimbra), forse devi aggiungere i flag starttlse smtp:

openssl s_client -starttls smtp -connect HOST_EMAIL:SECURE_PORT 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > CERTIFICATE_NAME.pem

Dove,

  • HOST_EMAIL è il dominio del server, ad esempio mail-server.com.

  • SECURE_PORT è la porta di comunicazione, ad esempio 587 o 465

  • Nome file dell'uscita CERTIFICATE_NAME (formato BASE 64 / PEM)


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.