Vérifier une chaîne de certificats à l'aide de openssl verify

128

Je construis ma propre chaîne de certificats avec les composants suivants:

Root Certificate - Intermediate Certificate - User Certificate

Le certificat racine est un certificat auto-signé, le certificat intermédiaire est signé par la racine et l'utilisateur par l'intermédiaire.

Maintenant, je veux vérifier si un certificat utilisateur a son ancre par certificat racine.

Avec

openssl verify -verbose -CAfile RootCert.pem Intermediate.pem

la validation est ok. À l'étape suivante, je valide le certificat d'utilisateur avec

openssl verify -verbose -CAfile Intermediate.pem UserCert.pem

et la validation montre

error 20 at 0 depth lookup:unable to get local issuer certificate

Qu'est-ce qui ne va pas?

Indra
la source

Réponses:

164

De la verifydocumentation:

Si un certificat est trouvé qui est son propre émetteur, il est supposé être l'autorité de certification racine.

En d'autres termes, l'autorité de certification racine doit s'auto-signer pour que la vérification fonctionne. C'est pourquoi votre deuxième commande n'a pas fonctionné. Essayez plutôt ceci:

openssl verify -CAfile RootCert.pem -untrusted Intermediate.pem UserCert.pem

Il vérifiera toute votre chaîne en une seule commande.

Priyadi
la source
2
Je vote cette réponse car j'ai récemment dû le faire et après avoir essayé différentes options répertoriées par man verify, j'ai trouvé que le -untrustedparamètre est le bon à utiliser lors de la spécification du certificat intermédiaire.
Anthony Geoghegan
Je pense que la deuxième réponse: stackoverflow.com/a/31205833/173062 est plus précise - il passe la chaîne de certificats au paramètre -CAfile.
Glenjamin
2
-untrustedne vérifie pas si la chaîne de certificats est entièrement valide. Veuillez envisager de passer à la fois intermédiaire et racine à la commande comme -CAfilele suggèrent d'autres questions.
Envek
2
Utilisez -untrusted pour Intermediate.pem s'il est possible que ce qui suit se produise: mail.python.org/pipermail/cryptography-dev/2016-August
Greg Smethells
2
Ce n'est pas ce que OP a demandé, mais au cas où vous voudriez vérifier la chaîne NON auto-signée, utilisez le fichier CA système / navigateur au lieu du vôtre. Par exemple sur OS X avec openssl à partir de l'utilisation de homebrew:openssl verify -CAfile /usr/local/etc/openssl/cert.pem -untrusted Intermediate.pem UserCert.pem
Greg Dubicki
50

C'est l'un des rares emplois légitimes pour cat:

openssl verify -verbose -CAfile <(cat Intermediate.pem RootCert.pem) UserCert.pem

Mettre à jour:

Comme Greg Smethells le souligne dans les commentaires, cette commande fait implicitement confiance à Intermediate.pem . Je recommande de lire la première partie des références post Greg (la deuxième partie concerne spécifiquement pyOpenSSL et n'est pas pertinente pour cette question).

Au cas où le message disparaît, je citerai les paragraphes importants:

Malheureusement, un certificat "intermédiaire" qui est en fait une racine / auto-signé sera traité comme une autorité de certification de confiance lors de l'utilisation de la commande recommandée ci-dessus:

$ openssl verify -CAfile <(cat geotrust_global_ca.pem rogue_ca.pem) fake_sometechcompany_from_rogue_ca.com.pem fake_sometechcompany_from_rogue_ca.com.pem: OK

Il semble qu'openssl arrêtera de vérifier la chaîne dès qu'un certificat racine est rencontré, qui peut également être Intermediate.pem s'il est auto-signé. Dans ce cas, RootCert.pem n'est pas pris en compte. Assurez-vous donc que Intermediate.pem provient d'une source fiable avant de vous fier à la commande ci-dessus.

Peter
la source
Cela vérifiera-t-il réellement le certificat intermédiaire par rapport au certificat racine?
augurar
Cela fait. Je viens de relancer les commandes avec une chaîne que je sais correcte (elle sert le trafic de production pour mon employeur), puis à nouveau avec un autre certificat racine non lié. Voir l'essentiel de la transcription .
Peter
8
AVERTISSEMENT: ne l' utilisez PAS si Intermediate.pem n'est pas du tout fiable. Pour plus d'informations, lisez ici: mail.python.org/pipermail/cryptography-dev/2016-August
Greg Smethells
1
Merci de l'avoir signalé, Greg. Quand j'ai donné la réponse, j'ai téléchargé à la fois les racines et les intermédiaires à partir des pages d'accueil des émetteurs, donc l'idée ne m'est pas venue. J'ai mis à jour la réponse pour préciser que l'intermédiaire est implicitement confié à cette commande.
Peter
1
@somenickname, voir le commentaire de Tony. L'option -untrusted est préférable de toute façon. Je vous suggère de poser votre propre question si vous souhaitez une aide supplémentaire. Les commentaires ne sont pas le bon endroit pour déboguer votre problème.
Peter
17

Le problème est que openssl -verifycela ne fait pas le travail.

Comme Priyadi l'a mentionné , openssl -verifys'arrête au premier certificat auto-signé, donc vous ne vérifiez pas vraiment la chaîne, car souvent le certificat intermédiaire est auto-signé.

Je suppose que vous voulez être sûr à 101% que les fichiers de certificat sont corrects avant d'essayer de les installer dans le service Web productif. Cette recette effectue ici exactement cette vérification avant vol.

Veuillez noter que la réponse de Peter est correcte , mais la sortie de openssl -verifyne donne aucun indice que tout fonctionne vraiment après. Oui, il peut y avoir des problèmes, mais pas tous.

Voici un script qui vérifie une chaîne de certificats avant de l'installer dans Apache. Peut-être que cela peut être amélioré avec certaines des magies les plus mystiques d'OpenSSL, mais je ne suis pas un gourou d'OpenSSL et les œuvres suivantes:

#!/bin/bash
# This Works is placed under the terms of the Copyright Less License,
# see file COPYRIGHT.CLL.  USE AT OWN RISK, ABSOLUTELY NO WARRANTY. 
#
# COPYRIGHT.CLL can be found at http://permalink.de/tino/cll
# (CLL is CC0 as long as not covered by any Copyright)

OOPS() { echo "OOPS: $*" >&2; exit 23; }

PID=
kick() { [ -n "$PID" ] && kill "$PID" && sleep .2; PID=; }
trap 'kick' 0

serve()
{
kick
PID=
openssl s_server -key "$KEY" -cert "$CRT" "$@" -www &
PID=$!
sleep .5    # give it time to startup
}

check()
{
while read -r line
do
    case "$line" in
    'Verify return code: 0 (ok)')   return 0;;
    'Verify return code: '*)    return 1;;
#   *)  echo "::: $line :::";;
    esac
done < <(echo | openssl s_client -verify 8 -CApath /etc/ssl/certs/)
OOPS "Something failed, verification output not found!"
return 2
}

ARG="${1%.}"
KEY="$ARG.key"
CRT="$ARG.crt"
BND="$ARG.bundle"

for a in "$KEY" "$CRT" "$BND"
do
    [ -s "$a" ] || OOPS "missing $a"
done

serve
check && echo "!!! =========> CA-Bundle is not needed! <========"
echo
serve -CAfile "$BND"
check
ret=$?
kick

echo
case $ret in
0)  echo "EVERYTHING OK"
    echo "SSLCertificateKeyFile $KEY"
    echo "SSLCertificateFile    $CRT"
    echo "SSLCACertificateFile  $BND"
    ;;
*)  echo "!!! =========> something is wrong, verification failed! <======== ($ret)";;
esac

exit $ret

Notez que la sortie après EVERYTHING OKest le paramètre Apache, car les personnes utilisant NginXou haproxygénéralement peuvent parfaitement lire et comprendre cela aussi;)

Il y a un GitHub Gist de ceci qui pourrait avoir des mises à jour

Prérequis de ce script:

  • Vous avez les données racine de l'autorité de certification de confiance /etc/ssl/certscomme d'habitude, par exemple sur Ubuntu
  • Créez un répertoire dans DIRlequel vous stockez 3 fichiers:
    • DIR/certificate.crt qui contient le certificat
    • DIR/certificate.key qui contient la clé secrète de votre webservice (sans mot de passe)
    • DIR/certificate.bundlequi contient le CA-Bundle. Pour savoir comment préparer le bundle, voir ci-dessous.
  • Maintenant, exécutez le script: ./check DIR/certificate(cela suppose que le script est nommé checkdans le répertoire courant)
  • Il existe un cas très improbable que le script génère CA-Bundle is not needed. Cela signifie que vous (lisez /etc/ssl/certs/:) fait déjà confiance au certificat de signature. Mais c'est très improbable sur le WWW.
  • Pour ce test, le port 4433 doit être inutilisé sur votre poste de travail. Et mieux vaut ne l'exécuter que dans un environnement sécurisé, car il ouvre prochainement le port 4433 au public, ce qui pourrait voir des connexions étrangères dans un environnement hostile.

Comment créer le certificate.bundlefichier?

Sur le WWW, la chaîne de confiance ressemble généralement à ceci:

  • certificat de confiance de /etc/ssl/certs
  • certificat (s) intermédiaire (s) inconnu (s), éventuellement signé (s) croisé (s) par une autre autorité de certification
  • votre certificat ( certificate.crt)

Maintenant, l'évaluation se déroule de bas en haut, cela signifie d'abord que votre certificat est lu, puis le certificat intermédiaire inconnu est nécessaire, puis peut-être le certificat de signature croisée, puis il /etc/ssl/certsest consulté pour trouver le certificat de confiance approprié.

Le ca-bundle doit être constitué exactement dans le bon ordre de traitement, cela signifie que le premier certificat nécessaire (le certificat intermédiaire qui signe votre certificat) vient en premier dans le bundle. Ensuite, le certificat de signature croisée est nécessaire.

Habituellement, votre autorité de certification (l'autorité qui a signé votre certificat) fournira déjà un tel fichier ca-bundle approprié. Sinon, vous devez sélectionner tous les certificats intermédiaires nécessaires et catles rassembler dans un seul fichier (sous Unix). Sous Windows, vous pouvez simplement ouvrir un éditeur de texte (comme notepad.exe) et coller les certificats dans le fichier, le premier nécessaire en haut et en suivant les autres.

Il y a autre chose. Les fichiers doivent être au format PEM. Certaines autorités de certification émettent le format DER (un binaire). PEM est facile à repérer: il est lisible en ASCII. Pour en savoir plus sur la façon de convertir quelque chose en PEM, voir Comment convertir .crt en .pem et suivez la route de briques jaunes.

Exemple:

Tu as:

  • intermediate2.crt le certificat intermédiaire qui a signé votre certificate.crt
  • intermediate1.crt un autre cert intermédiaire, qui a chanté intermediate2.crt
  • crossigned.crt qui est un certificat de signature croisée d'une autre autorité de certification, qui a signé intermediate1.crt
  • crossintermediate.crtqui est un autre intermédiaire de l'autre CA qui a signé crossigned.crt(vous ne verrez probablement jamais une telle chose)

Alors le bon catressemblerait à ceci:

cat intermediate2.crt intermediate1.crt crossigned.crt crossintermediate.crt > certificate.bundle

Et comment savoir quels fichiers sont nécessaires ou non et dans quel ordre?

Eh bien, expérimentez, jusqu'à ce que checkvous disiez que tout va bien. C'est comme un jeu de puzzle informatique pour résoudre l'énigme. Chaque. Célibataire. Temps. Même pour les pros. Mais vous vous améliorerez à chaque fois que vous en aurez besoin. Vous n'êtes donc définitivement pas seul avec toute cette douleur. C'est SSL, tu sais? SSL est probablement l'une des pires conceptions que j'ai jamais vues en plus de 30 ans d'administration système professionnelle. Vous êtes-vous déjà demandé pourquoi la cryptographie n'était pas devenue courante au cours des 30 dernières années? C'est pourquoi. dit Nuff.

Tino
la source
À l'électeur défavorable: Veuillez expliquer ce qui ne va pas avec ma réponse. Merci.
Tino
2
Je fais partie des votes négatifs. Ce qui a déclenché le vote défavorable est le suivant: "Et comment savoir quels fichiers sont nécessaires ou non et dans quel ordre? Eh bien, expérimentez, jusqu'à ce que la vérification vous dise que tout va bien". Je ne pense pas que SSL soit un cas particulier. Des problèmes comme celui-ci devraient avoir une solution déterministe.
ychaouche
2
@ychaouche Merci! Comme toi, j'aime les choses desterministes. La question était: "Qu'est-ce qui ne va pas" et comment le faire avec "openssl verify". Comme nous sommes sur stackoverflow, j'ai expliqué cela, suivi d'une réponse programmatique (donc déterministe) oui / non. Vous pouvez même l'utiliser pour automatiser les vérifications du nouveau Bundle avant de l'installer en production. Cela répond pleinement à la question. Ce que vous n'aimez pas, c'est que j'ai parlé de la frustration sur "Comment créer un bundle approprié?". Comme je pense qu'il ne peut y avoir de réponse déterministe brève à cela, répondre à cette question serait hors sujet dans le contexte ici.
Tino
6
"Comme Priyadi l'a mentionné, openssl -verify s'arrête au premier certificat auto-signé, donc vous ne vérifiez pas vraiment la chaîne, car souvent le certificat intermédiaire est auto-signé." De toute évidence, les certificats intermédiaires ne sont jamais auto-signés (s'ils l'étaient, ils seraient des certificats racine). Et tout le point de vérification est de vérifier que vous avez inclus tous les certificats de la chaîne jusqu'à un certificat racine de confiance. C'est précisément ce que fait la vérification openssl. Cependant, openssl a tendance à être plutôt conservateur avec ses politiques de confiance ...
Timo
4
"souvent le certificat intermédiaire est auto-signé". C'est faux, et des confusions de terminologie comme celle-ci font qu'il est difficile pour les nouveaux arrivants de comprendre un sujet qui est en fait plutôt simple lorsqu'il est expliqué de la bonne manière. D'après RFC 5280: «[...] les certificats CA peuvent être divisés en trois classes: les certificats croisés, les certificats auto-émis et les certificats auto-signés. Les certificats croisés sont des certificats CA dans lesquels l'émetteur et le sujet sont des entités différentes . Les certificats croisés décrivent une relation de confiance entre les deux autorités de certification. [...] ".
Dr.Jan-Philip Gehrcke
8

J'ai dû faire une vérification d'un certificat letsencrypt et je l'ai fait comme ceci:

  1. Téléchargez le certificat racine et le certificat intermédiaire à partir de la chaîne de confiance letsencrypt .
  2. Émettez cette commande:

    $ openssl verify -CAfile letsencrypt-root-cert/isrgrootx1.pem.txt -untrusted letsencrypt-intermediate-cert/letsencryptauthorityx3.pem.txt /etc/letsencrypt/live/sitename.tld/cert.pem 
    /etc/letsencrypt/live/sitename.tld/cert.pem: OK
    
Michael
la source
1
Eh bien, il semble que John n'a pas aimé que je vous dise merci. J'insiste sur le "Merci" difficile, alors voici le texte supprimé: J'espère que cela vous aidera pour vos certificats letsencrypt. Merci pour Priyadi, votre solution m'a aidé à trouver cette commande. Veuillez vous assurer de voter pour sa solution.
Michael
5

Après avoir passé une journée entière sur le même problème, sans aucune connaissance préalable des certificats SSL, j'ai téléchargé le gestionnaire de fichiers de clés CERTivity et y ai importé mon magasin de clés , et j'ai obtenu une visualisation claire de la chaîne de certificats.

Capture d'écran :

entrez la description de l'image ici

praveen.chandran
la source
1
N'essaye pas de répondre à la question sur la façon de l'utiliser openssl verify.
binki
oui mais ce genre d'outil peut vous donner la visualisation nécessaire de ce genre de choses si vous ne comprenez pas les informations cryptiques des outils de ligne de commande openssl :) Alors voici mon avis positif, il pourrait y avoir des trucs en ligne qui le font aussi.
David 天宇 Wong
2

Si vous souhaitez uniquement vérifier que l' émetteur de UserCert.pem est réellement, Intermediate.pem procédez comme suit (l'exemple utilise:) OpenSSL 1.1.1:

openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pem

et vous obtiendrez:

UserCert.pem: OK

ou

UserCert.pem: verification failed
Marinos An
la source
existe-t-il une commande équivalente pour openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pemPython 3.7?
Bogota
-5

Vous pouvez facilement vérifier une chaîne de certificats avec openssl. La chaîne complète comprendra le certificat de l'autorité de certification, vous devriez donc voir les détails sur l'autorité de certification et le certificat lui-même.

openssl x509 -in fullchain.pem -text -noout

Jorfus
la source
4
1) Ceci est entièrement sans aucune explication. 2) c'est une réponse à une question que le demandeur n'a pas posée, sans aucun contexte.
Shadur