Überprüfen Sie eine Zertifikatkette mit openssl verify

128

Ich baue eine eigene Zertifikatskette mit folgenden Komponenten auf:

Root Certificate - Intermediate Certificate - User Certificate

Das Root-Zertifikat ist ein selbstsigniertes Zertifikat. Das Zwischenzertifikat wird von Root und der Benutzer von Intermediate signiert.

Jetzt möchte ich überprüfen, ob ein Benutzerzertifikat seinen Anker durch das Stammzertifikat hat.

Mit

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

Die Validierung ist in Ordnung. Im nächsten Schritt validiere ich das Benutzerzertifikat mit

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

und die Validierung zeigt

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

Was ist falsch?

Indra
quelle

Antworten:

164

Aus der verifyDokumentation:

Wenn ein Zertifikat gefunden wird, das sein eigener Aussteller ist, wird davon ausgegangen, dass es sich um die Stammzertifizierungsstelle handelt.

Mit anderen Worten, die Stammzertifizierungsstelle muss sich selbst signieren, damit die Überprüfung funktioniert. Aus diesem Grund hat Ihr zweiter Befehl nicht funktioniert. Versuchen Sie stattdessen Folgendes:

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

Es wird Ihre gesamte Kette in einem einzigen Befehl überprüfen.

Priyadi
quelle
2
Ich stimme dieser Antwort zu, da ich dies kürzlich tun musste, und nachdem man verifyich verschiedene Optionen ausprobiert hatte , stellte ich fest, dass der -untrustedParameter der richtige ist, der bei der Angabe des Zwischenzertifikats verwendet werden soll.
Anthony Geoghegan
Ich denke, die zweite Antwort: stackoverflow.com/a/31205833/173062 ist genauer - sie übergibt die Zertifikatskette an den Parameter -CAfile.
Glenjamin
2
-untrustedprüft nicht, ob die Zertifikatskette vollständig gültig ist. Bitte denken Sie daran, sowohl Intermediate als auch Root an den Befehl zu übergeben, -CAfilewie andere Fragen vermuten lassen.
Envek
2
Verwenden Sie -untrusted für Intermediate.pem, wenn Folgendes möglich ist: mail.python.org/pipermail/cryptography-dev/2016-August/…
Greg Smethells
2
Das ist nicht das, wonach OP gefragt hat, aber wenn Sie die NICHT selbstsignierte Kette überprüfen möchten, verwenden Sie die System- / Browser-CA-Datei anstelle Ihrer eigenen. Zum Beispiel unter OS X mit openssl von Homebrew:openssl verify -CAfile /usr/local/etc/openssl/cert.pem -untrusted Intermediate.pem UserCert.pem
Greg Dubicki
50

Das ist einer der wenigen legitimen Jobs für cat:

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

Aktualisieren:

Wie Greg Smethells in den Kommentaren hervorhebt, vertraut dieser Befehl implizit Intermediate.pem . Ich empfehle, den ersten Teil des Beitrags zu lesen, auf den Greg verweist (der zweite Teil befasst sich speziell mit pyOpenSSL und ist für diese Frage nicht relevant).

Für den Fall, dass der Beitrag verschwindet, zitiere ich die wichtigen Absätze:

Leider wird ein "Zwischen" -Zertifikat, das tatsächlich ein Root / selbstsigniert ist, als vertrauenswürdige Zertifizierungsstelle behandelt, wenn der oben angegebene empfohlene Befehl verwendet wird:

$ 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

Es scheint, dass openssl die Überprüfung der Kette beendet, sobald ein Stammzertifikat gefunden wird. Dies kann auch Intermediate.pem sein, wenn es selbstsigniert ist. In diesem Fall wird RootCert.pem nicht berücksichtigt. Stellen Sie daher sicher, dass Intermediate.pem von einer vertrauenswürdigen Quelle stammt, bevor Sie sich auf den obigen Befehl verlassen.

Peter
quelle
Wird das Zwischenzertifikat tatsächlich mit dem Stammzertifikat verglichen?
Augurar
Es tut. Ich habe die Befehle nur mit einer Kette erneut ausgeführt, von der ich weiß, dass sie korrekt ist (sie dient dem Produktionsverkehr für meinen Arbeitgeber), und dann erneut mit einem anderen, nicht verwandten Stammzertifikat. Siehe das Protokoll .
Peter
8
WARNUNG: Verwenden Sie diese Option NICHT , wenn Intermediate.pem überhaupt nicht vertrauenswürdig ist. Weitere Informationen finden Sie hier: mail.python.org/pipermail/cryptography-dev/2016-August/…
Greg Smethells
1
Danke, dass du darauf hingewiesen hast, Greg. Als ich die Antwort gab, lud ich sowohl Roots als auch Intermediates von den Homepages der Emittenten herunter, sodass mir der Gedanke nicht einfiel. Ich habe die Antwort aktualisiert, um zu verdeutlichen, dass dem Zwischenprodukt dieser Befehl implizit vertraut wird.
Peter
1
@somenickname, siehe Tonys Kommentar. Die Option -untrusted ist ohnehin vorzuziehen. Ich schlage vor, Sie stellen Ihre eigene Frage, wenn Sie weitere Hilfe benötigen. Kommentare sind nicht der richtige Ort, um Ihr Problem zu beheben.
Peter
17

Das Problem ist, dass openssl -verifydas nicht funktioniert.

Wie Priyadi erwähnt hat , openssl -verifystoppt es beim ersten selbstsignierten Zertifikat, daher überprüfen Sie die Kette nicht wirklich, da das Zwischenzertifikat häufig selbstsigniert ist.

Ich gehe davon aus, dass Sie zu 101% sicher sein möchten, dass die Zertifikatdateien korrekt sind, bevor Sie versuchen, sie im produktiven Webdienst zu installieren. Dieses Rezept hier führt genau diesen Pre-Flight-Check durch.

Bitte beachten Sie, dass die Antwort von Peter korrekt ist , die Ausgabe von openssl -verifyjedoch kein Hinweis darauf ist, dass danach wirklich alles funktioniert. Ja, es könnte einige Probleme geben, aber nicht alle.

Hier ist ein Skript, mit dem eine Zertifikatkette überprüft wird, bevor Sie sie in Apache installieren. Vielleicht kann dies mit etwas mystischerer OpenSSL-Magie verbessert werden, aber ich bin kein OpenSSL-Guru und folgende Werke:

#!/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

Beachten Sie, dass die Ausgabe danach EVERYTHING OKdie Apache-Einstellung ist, da Benutzer, die dies verwenden NginXoder haproxynormalerweise verwenden, dies auch perfekt lesen und verstehen können;)

Es gibt eine GitHub-Liste, die möglicherweise einige Updates enthält

Voraussetzungen dieses Skripts:

  • Sie haben die vertrauenswürdigen CA-Stammdaten /etc/ssl/certswie gewohnt, beispielsweise unter Ubuntu
  • Erstellen Sie ein Verzeichnis, DIRin dem Sie 3 Dateien speichern:
    • DIR/certificate.crt welches das Zertifikat enthält
    • DIR/certificate.key welches den geheimen Schlüssel für Ihren Webservice enthält (ohne Passphrase)
    • DIR/certificate.bundlewelches das CA-Bundle enthält. Informationen zur Vorbereitung des Bundles finden Sie weiter unten.
  • Führen Sie nun das Skript aus: ./check DIR/certificate(Dies setzt voraus, dass das Skript checkim aktuellen Verzeichnis benannt ist.)
  • Es ist sehr unwahrscheinlich, dass das Skript ausgegeben wird CA-Bundle is not needed. Dies bedeutet, dass Sie (read /etc/ssl/certs/:) bereits dem Signaturzertifikat vertrauen. Dies ist jedoch im WWW höchst unwahrscheinlich.
  • Für diesen Test muss Port 4433 auf Ihrer Workstation nicht verwendet werden. Führen Sie dies besser nur in einer sicheren Umgebung aus, da Port 4433 in Kürze für die Öffentlichkeit geöffnet wird, wodurch möglicherweise fremde Verbindungen in einer feindlichen Umgebung hergestellt werden.

Wie erstelle ich die certificate.bundleDatei?

Im WWW sieht die Vertrauenskette normalerweise so aus:

  • vertrauenswürdiges Zertifikat von /etc/ssl/certs
  • unbekannte Zwischenzertifikate, möglicherweise von einer anderen Zertifizierungsstelle signiert
  • Ihr Zertifikat ( certificate.crt)

Jetzt erfolgt die Auswertung von unten nach oben. Dies bedeutet, dass zuerst Ihr Zertifikat gelesen wird, dann das unbekannte Zwischenzertifikat benötigt wird, dann möglicherweise das Cross-Signing-Zertifikat und dann /etc/ssl/certskonsultiert wird, um das richtige vertrauenswürdige Zertifikat zu finden.

Das Ca-Bundle muss in genau der richtigen Verarbeitungsreihenfolge erstellt werden. Dies bedeutet, dass das erste benötigte Zertifikat (das Zwischenzertifikat, das Ihr Zertifikat signiert) an erster Stelle im Bundle steht. Dann wird das Cross-Signing-Zertifikat benötigt.

Normalerweise stellt Ihre Zertifizierungsstelle (die Behörde, die Ihr Zertifikat unterzeichnet hat) bereits eine solche ordnungsgemäße Ca-Bundle-Datei zur Verfügung. Wenn nicht, müssen Sie alle erforderlichen Zwischenzertifikate und catdiese zusammen in einer einzigen Datei (unter Unix) auswählen . Unter Windows können Sie einfach einen Texteditor (wie notepad.exe) öffnen und die Zertifikate in die Datei einfügen. Das erste wird oben benötigt und folgt den anderen.

Es gibt noch eine andere Sache. Die Dateien müssen im PEM-Format vorliegen. Einige Zertifizierungsstellen geben das DER-Format (ein Binärformat) aus. PEM ist leicht zu erkennen: Es ist ASCII-lesbar. Weitere Informationen zum Konvertieren von etwas in PEM finden Sie unter Konvertieren von .crt in .pem und Folgen der gelben Backsteinstraße.

Beispiel:

Du hast:

  • intermediate2.crt das Zwischenzertifikat, das Ihr unterschrieben hat certificate.crt
  • intermediate1.crt ein weiteres Zwischenzertifikat, das sang intermediate2.crt
  • crossigned.crt Dies ist ein Cross-Signing-Zertifikat einer anderen Zertifizierungsstelle, die signiert hat intermediate1.crt
  • crossintermediate.crtDas ist ein weiteres Zwischenprodukt der anderen CA, die unterschrieben hat crossigned.crt(so etwas werden Sie wahrscheinlich nie sehen).

Dann würde das richtige catso aussehen:

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

Und wie können Sie herausfinden, welche Dateien in welcher Reihenfolge benötigt werden oder nicht?

Nun, experimentiere, bis checkdir sagt, dass alles in Ordnung ist. Es ist wie ein Computer-Puzzlespiel, um das Rätsel zu lösen. Jeden. Single. Zeit. Auch für Profis. Aber Sie werden jedes Mal besser, wenn Sie dies tun müssen. Sie sind also definitiv nicht allein mit all dem Schmerz. Es ist SSL, weißt du? SSL ist wahrscheinlich eines der schlechtesten Designs, die ich je in über 30 Jahren professioneller Systemadministration gesehen habe. Haben Sie sich jemals gefragt, warum Krypto in den letzten 30 Jahren nicht zum Mainstream geworden ist? Deshalb. 'nuff sagte.

Tino
quelle
An den Downvoter: Bitte erklären Sie, was mit meiner Antwort nicht stimmt. Vielen Dank.
Tino
2
Ich bin einer der Downvoter. Was die Abwertung ausgelöst hat, ist Folgendes: "Und wie können Sie herausfinden, welche Dateien benötigt werden oder nicht und in welcher Reihenfolge? Nun, experimentieren Sie, bis die Prüfung Ihnen sagt, dass alles in Ordnung ist." Ich denke nicht, dass SSL ein Sonderfall ist. Probleme wie diese sollten eine deterministische Lösung haben.
Ychaouche
2
@ychaouche Danke! Wie du mag ich desterministische Dinge. Die Frage war: "Was ist los?" Und wie geht das mit "openssl verify"? Während wir uns im Stackoverflow befinden, erklärte ich dies, gefolgt von einer programmatischen (also deterministischen) Ja / Nein-Antwort. Sie können damit sogar die Prüfung des neuen Bundles automatisieren, bevor Sie es in die Produktion einbauen. Dies beantwortet die Frage vollständig. Was Sie nicht mögen, ist, dass ich über die Frustration bei "Wie erstelle ich ein richtiges Bündel?" Erzählt habe. Da ich denke, dass es dafür keine kurze deterministische Antwort geben kann, wäre eine Beantwortung dieser Frage im Zusammenhang hier offtopisch.
Tino
6
"Wie Priyadi erwähnt hat, stoppt openssl -verify beim ersten selbstsignierten Zertifikat. Daher überprüfen Sie die Kette nicht wirklich, da das Zwischenzertifikat häufig selbstsigniert ist." Offensichtlich sind Zwischenzertifikate niemals selbstsigniert (wenn sie es wären, wären sie Stammzertifikate). Bei der Überprüfung muss überprüft werden, ob Sie alle Zertifikate in die Kette aufgenommen haben, bis hin zu einem vertrauenswürdigen Stammzertifikat. Genau das macht die openssl-Überprüfung. Allerdings ist openssl mit seinen vertrauensvollen Richtlinien eher konservativ ...
Timo
4
"Oft ist das Zwischenzertifikat selbst signiert". Dies ist falsch, und Terminologie-Verwirrungen wie diese erschweren es Neulingen, ein Thema zu verstehen, das bei richtiger Erklärung eigentlich recht einfach ist. Aus RFC 5280: "[...] CA-Zertifikate können weiter in drei Klassen unterteilt werden: Kreuzzertifikate, selbst ausgestellte Zertifikate und selbstsignierte Zertifikate. Kreuzzertifikate sind CA-Zertifikate, bei denen der Aussteller und das Subjekt unterschiedliche Einheiten sind Kreuzzertifikate beschreiben eine Vertrauensbeziehung zwischen den beiden Zertifizierungsstellen. [...] ".
Dr. Jan-Philip Gehrcke
8

Ich musste ein letsencrypt-Zertifikat überprüfen und habe es so gemacht:

  1. Laden Sie das Root-Zertifikat und das Zwischenzertifikat aus der Vertrauenskette letsencrypt herunter .
  2. Geben Sie diesen Befehl ein:

    $ 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
quelle
1
Nun, es scheint John nicht gefallen zu haben, dass ich Danke gesagt habe. Ich bestehe auf dem harten Dankeschön, daher hier der gelöschte Text: Ich hoffe, er hilft Ihnen bei Ihren Letsencrypt-Zertifikaten. Vielen Dank für Priyadi. Ihre Lösung hat mir geholfen, diesen Befehl zu finden. Bitte stellen Sie sicher, dass Sie seine Lösung positiv bewerten.
Michael
5

Nachdem ich einen ganzen Tag mit genau demselben Problem verbracht hatte und keine Vorkenntnisse zu SSL-Zertifikaten hatte, lud ich das herunter unterbrochen hatte, lud CERTivity Keystores Manager importierte meinen Keystore in diesen und erhielt eine übersichtliche Visualisierung der Zertifikatkette.

Bildschirmfoto :

Geben Sie hier die Bildbeschreibung ein

praveen.chandran
quelle
1
Versucht nicht, Fragen zu beantworten, bei denen es um die Verwendung geht openssl verify.
Binki
Ja, aber diese Art von Tool kann Ihnen die erforderliche Visualisierung dieser Art von Dingen geben, wenn Sie die kryptischen Informationen von openssl-Befehlszeilentools nicht verstehen :) Hier ist meine positive Bewertung, es könnte auch einige Online-Inhalte geben, die dies tun.
David 天宇 Wong
2

Wenn Sie nur überprüfen möchten, ob der Aussteller von UserCert.pem tatsächlich ist, Intermediate.pem gehen Sie wie folgt vor (Beispiel verwendet :) OpenSSL 1.1.1:

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

und du wirst bekommen:

UserCert.pem: OK

oder

UserCert.pem: verification failed
Marinos An
quelle
Gibt es einen äquivalenten Befehl für openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pemPython 3.7?
Bogota
-5

Sie können eine Zertifikatskette einfach mit openssl überprüfen. Die vollständige Kette enthält das CA-Zertifikat, sodass Sie Details zur CA und zum Zertifikat selbst sehen sollten.

openssl x509 -in fullchain.pem -text -noout

Jorfus
quelle
4
1) Dies ist völlig ohne Erklärung. 2) Dies ist eine Antwort auf eine Frage, die der Fragesteller nicht ohne Kontext gestellt hat.
Shadur