web-dev-qa-db-fra.com

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

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 d'utilisateur a son ancre par certificat racine.

Avec
openssl verify -verbose -CAfile RootCert.pem Intermediate.pem
la validation est ok. Dans la prochaine étape, je valide le certificat d'utilisateur avec
openssl verify -verbose -CAfile Intermediate.pem UserCert.pem
et la validation indique l'erreur 20 à 0 recherche de profondeur: impossible d'obtenir le certificat de l'émetteur local

Qu'est-ce qui ne va pas?

107
Indra

D'après la documentation de vérification: "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 ceci à la place:

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

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

126
Priyadi

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

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

Mise à jour:

Comme Greg Smethells le fait remarquer dans les commentaires, cette commande approuve implicitement Intermediate.pem . Je recommande de lire la première partie de les références de l'article 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 indiqué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 que openssl cesse 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 qu'Intermediate.pem provient d'une source approuvée avant de vous fier à la commande ci-dessus.

40
Peter

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

Comme Priyadi l'a mentionné , openssl -verify s'arrête au premier certificat auto-signé, vous ne vérifiez donc pas vraiment la chaîne, car le certificat intermédiaire est souvent 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 , cependant, le résultat de openssl -verify ne permet pas de conclure que tout fonctionne réellement par la suite. Oui, cela pourrait poser des problèmes, mais pas du tout.

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 OpenSSL les plus mystiques, mais je ne suis pas un gourou OpenSSL et des œ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 le résultat après EVERYTHING OK correspond au paramètre Apache, car les utilisateurs de NginX ou haproxy peuvent généralement le lire et le comprendre parfaitement;)

Il y a un GitHub Gist de celui-ci qui pourrait avoir quelques mises à jour

Prérequis de ce script:

  • Vous avez les données racine de l'autorité de certification approuvée dans /etc/ssl/certs comme d'habitude, par exemple sous Ubuntu.
  • Créez un répertoire DIR où vous stockez 3 fichiers:
    • DIR/certificate.crt qui contient le certificat
    • DIR/certificate.key qui contient la clé secrète de votre webservice (sans phrase secrète)
    • DIR/certificate.bundle qui contient le CA-Bundle. Pour savoir comment préparer le paquet, voir ci-dessous.
  • Maintenant, lancez le script: ./check DIR/certificate (cela suppose que le script s'appelle check dans le répertoire en cours)
  • Il y a un cas très improbable que le script génère CA-Bundle is not needed. Cela signifie que vous (lisez: /etc/ssl/certs/) approuve déjà le certificat de signature. Mais cela est hautement improbable sur le WWW.
  • Pour ce test, le port 4433 doit être inutilisé sur votre poste de travail. Et il est préférable d’exécuter cette opération uniquement dans un environnement sécurisé, car elle ouvre prochainement le port 4433 au public, qui risque de voir les connexions étrangères se connecter dans un environnement hostile.

Comment créer le fichier certificate.bundle?

Dans 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) par une autre autorité de certification
  • votre certificat (certificate.crt)

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

Le paquetage ca doit être constitué dans le bon ordre de traitement, c’est-à-dire que le premier certificat nécessaire (le certificat intermédiaire qui signe votre certificat) vient en premier dans le paquet. Ensuite, le cert-cross-signature est nécessaire.

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

Il y a autre chose. Les fichiers doivent être au format PEM. Certaines autorités de certification publient le format DER (binaire). PEM est facile à repérer: ASCII lisible. Pour plus d'informations sur la conversion de 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 certificat intermédiaire, qui a chanté intermediate2.crt
  • crossigned.crt qui est un certificat de signature croisée d'une autre autorité de certification ayant signé intermediate1.crt
  • crossintermediate.crt qui est un autre intermédiaire de l'autre autorité de certification qui a signé crossigned.crt (vous ne verrez probablement jamais une telle chose)

Alors le bon cat ressemblerait à 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 la check vous dise 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 irez mieux chaque fois que vous en aurez besoin. Donc, vous n'êtes 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 depuis plus de 30 ans dans l'administration système professionnelle. Vous êtes-vous déjà demandé pourquoi la crypto n’était pas devenue populaire au cours des 30 dernières années? C'est pourquoi. 'Nuff a dit.

13
Tino

J'ai eu à vérifier un certificat de letencrypt 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 de letsencrypt: https://letsencrypt.org/certificates/
  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

J'espère que cela vous aidera pour vos certificats Letencrypt. Merci pour Priyadi, votre solution m'a aidé à trouver cette commande. Palease s'assure de faire passer sa solution au vote.

5
Michael

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 CERTivity Keystores Manager et importé mon magasin de clés, et j'ai obtenu une visualisation claire de la chaîne de certificats. .

Capture d'écran :

enter image description here

3
praveen.chandran