Utiliser openssl pour obtenir le certificat d'un serveur

354

J'essaie d'obtenir le certificat d'un serveur distant, que je peux ensuite utiliser pour ajouter à mon magasin de clés et utiliser dans mon application java.

Un développeur senior (qui est en vacances :() m'a informé que je pouvais exécuter ceci:

openssl s_client -connect host.host:9999

Pour obtenir un certificat brut, que je peux ensuite copier et exporter. Je reçois la sortie suivante:

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:

J'ai aussi essayé avec cette option

-showcerts 

et celui-ci (fonctionnant sur Debian, l'esprit vous)

-CApath /etc/ssl/certs/ 

Mais obtenez la même erreur.

Cette source dit que je peux utiliser cet indicateur CApath mais cela ne semble pas aider. J'ai essayé plusieurs chemins en vain.

Veuillez me faire savoir où je me trompe.

pâteux méchant
la source

Réponses:

464

Avec SNI

Si le serveur distant utilise SNI (c'est-à-dire qu'il partage plusieurs hôtes SSL sur une seule adresse IP), vous devrez envoyer le nom d'hôte correct afin d'obtenir le bon certificat.

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

Sans SNI

Si le serveur distant n'utilise pas SNI, vous pouvez ignorer le -servernameparamètre:

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


Pour afficher tous les détails du certificat d'un site, vous pouvez également utiliser cette chaîne de commandes:

$ echo | \
    openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \
    openssl x509 -text
Ari Maniatis
la source
3
Hmm. J'obtiens toujours la même erreur en essayant cette commande. J'ai remarqué que ma version d'OpenSL est «OpenSSL 0.9.8g 19 oct 2007». As tu des idées?
méchant pâteux
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 alternatif utile, de madboa.com :echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
rmeakins
9
Pour rendre cela un peu plus concis, vous pouvez remplacer le sedpar openssl x509et le lire en utilisant un sous-shell:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
Gabe Martin-Dempesy
27
Aussiecho | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle
68

Bien que je sois d'accord avec la réponse d'Ari (et l'a votée :), j'ai dû faire une étape supplémentaire pour le faire fonctionner avec Java sur Windows (où il devait être déployé):

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

Avant d'ajouter la openssl x509 -outform DERconversion, je recevais une erreur de keytool sur Windows se plaignant du format du certificat. L'importation du fichier .der a bien fonctionné.

David Jaquay
la source
Impair. J'utilise des certificats PEM avec keytool sur Windows depuis Java 6 et je n'ai jamais rencontré de problème.
imgx64
39

Il s'avère qu'il y a plus de complexité ici: j'avais besoin de fournir beaucoup plus de détails pour lancer ce processus. Je pense que c'est quelque chose à voir avec le fait que c'est une connexion qui a besoin d'une authentification client, et le hankshake avait besoin de plus d'informations pour continuer à l'étape où les certificats ont été vidés.

Voici ma commande de travail:

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

J'espère que c'est un coup de pouce dans la bonne direction pour quiconque pourrait faire plus d'informations.

pâteux méchant
la source
6
Je suis désolé, mais votre réponse n'a pas beaucoup de sens. Vous aviez besoin de passer le certificat au serveur afin d'obtenir le certificat?
Ari Maniatis
2
Oui. Authentification client AFAIK.
pâteux méchant
11
Il s'avère que '-prexit' renverra également ces données. Par exemple; openssl s_client -connect host: port -prexit
Robert
39

Un one-liner pour extraire le certificat d'un serveur distant au format PEM, cette fois en utilisant sed:

openssl s_client -connect www.google.com:443 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
André Fernandes
la source
2
Celui-ci est presque parfait pour extraire le certificat, manquant juste l' -servernameoption, je ne sais pas pourquoi, mais j'ai dû l'utiliser pour obtenir le certificat complet.
Karl.S
-servername est requis pour l'indication du nom du serveur (SNI). La recherche sur le Web peut étendre le reste.
Sam Gleske
32

La ligne de commande la plus simple pour cela, qui comprend la sortie PEM pour l'ajouter au magasin de clés, ainsi qu'une sortie lisible par l'homme et prend également en charge SNI, ce qui est important si vous travaillez avec un serveur HTTP est:

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

L' option -servername permet d'activer la prise en charge SNI et le texte openssl x509 imprime le certificat au format lisible par l'homme.

Florian
la source
Vous pouvez ajouter à votre -servername votre sous-domaine, par exemple ws.example.com au lieu d'exemple.com (appliquez-le également au paramètre -connect).
russellhoff
24

Pour obtenir le certificat du serveur distant, vous pouvez utiliser l' openssloutil et vous pouvez le trouver entre BEGIN CERTIFICATEet END CERTIFICATEque vous devez copier et coller dans votre fichier de certificat (CRT).

Voici la commande qui le démontre:

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

Pour retourner tous les certificats de la chaîne, ajoutez simplement g(global) comme:

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

Ensuite, vous pouvez simplement importer votre fichier de certificat ( file.crt) dans votre trousseau et le rendre fiable, donc Java ne devrait pas se plaindre.

Sous OS X, vous pouvez double-cliquer sur le fichier ou faire glisser et déposer votre accès au trousseau, il apparaîtra donc dans la connexion / Certificats. Double-cliquez ensuite sur le certificat importé et faites-lui toujours confiance pour SSL .

Sur CentOS 5, vous pouvez les ajouter dans un /etc/pki/tls/certs/ca-bundle.crtfichier (et exécuter sudo update-ca-trust force-enable:), ou dans CentOS 6 les copier /etc/pki/ca-trust/source/anchors/et les exécuter sudo update-ca-trust extract.

Dans Ubuntu, copiez-les /usr/local/share/ca-certificateset exécutez sudo update-ca-certificates.

kenorb
la source
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
akond
la source
6

pour imprimer uniquement la chaîne de certificats et non le certificat du serveur:

# 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}'

pour mettre à jour la confiance CA sur 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

sur 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
Mathieu CARBONNEAUX
la source
Exactement ce dont j'avais besoin sur CentOS7. Merci!
Arthur Hebert
5

Vous pouvez obtenir et stocker le certificat racine du serveur à l'aide du script bash suivant:

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'") }'

Remplacez simplement les variables requises.

Andrei Aleksandrov
la source
4

Si votre serveur est un serveur de messagerie (MS Exchange ou Zimbra), vous devrez peut-être ajouter les drapeaux starttlset 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

Où,

  • HOST_EMAIL est le domaine du serveur, par exemple, mail-server.com.

  • SECURE_PORT est le port de communication, par exemple, 587 ou 465

  • Nom de fichier de la sortie CERTIFICATE_NAME (format BASE 64 / PEM)

SHoko
la source