PKI-Lab mit Root-CA und Teilnehmer-CA
PKI mit Root-CA und Sub-CA (Beispiel it213)
In diesem Beispiel wird eine einfache PKI aufgebaut.
Der Trainer betreibt eine Root-CA.
Die Teilnehmer erzeugen eine Sub-CA, die von der Root-CA signiert wird.
Mit dieser Sub-CA werden anschließend Server-Zertifikate signiert.
Root-CA erstellen
Die Root-CA ist der Vertrauensanker der PKI und ist selbstsigniert.
- openssl req -new -x509 -newkey rsa:4096 -nodes -keyout ca.key -out ca.crt -days 3650 -subj "/CN=Kit Root CA"
Das Zertifikat kann anschließend kontrolliert werden.
- openssl x509 -in ca.crt -text -noout
Root-CA auf Clients installieren
Damit Clients den Zertifikaten vertrauen, muss die Root-CA im Trust-Store installiert werden.
Debian
Das Root-Zertifikat wird in den lokalen CA-Speicher kopiert.
- cp ca.crt /usr/local/share/ca-certificates/
Der Trust-Store wird aktualisiert.
- update-ca-certificates
Rocky / RHEL
Das Root-Zertifikat wird in den Anchor-Store kopiert.
- cp ca.crt /etc/pki/ca-trust/source/anchors/
Der System Trust Store wird neu erzeugt.
- update-ca-trust extract
Firefox / Chrome / Mozilla
- Müssen getrennt importiert werden.
Sub-CA Request erzeugen (Beispiel it213)
Der Teilnehmer erzeugt einen privaten Schlüssel und eine Certificate Signing Request für seine CA.
- mkdir intermediata-ca
- cd intermediata-ca
- openssl req -new -newkey rsa:4096 -nodes -keyout it213-ca.key -out it213-ca.csr -subj "/CN=it213 Lab CA"
Der Certificate Signing Request muss nun zur Zertifizierungsstelle
Die Zertifikate können nun hier runtergeladen werden
Sub-CA durch Root signieren
Die Root-CA signiert die Teilnehmer-CA. Dadurch entsteht die Zertifikatskette.
- openssl x509 -req -in it213-ca.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out it213-ca.crt -days 1460 -extfile <(printf "basicConstraints=CA:TRUE\nkeyUsage=keyCertSign,cRLSign")
Das signierte CA-Zertifikat kann kontrolliert werden.
- openssl x509 -in it213-ca.crt -text -noout
Hinweis zum privaten Schlüssel
Der private Schlüssel der CA wird nur zum Signieren von Zertifikaten benötigt.
Zum Prüfen der Zertifikatskette werden nur die öffentlichen Zertifikate verwendet.
Beispiel:
www.it213.int.crt it213-ca.crt ca.crt
Die Prüfung erfolgt über die Signaturen der Zertifikate.
Server-Schlüssel und CSR erzeugen
Der Teilnehmer erzeugt einen Schlüssel und eine CSR für seinen Server.
- Erstellen
- openssl req -new -newkey rsa:2048 -nodes -keyout www.it213.int.key -out www.it213.int.csr -subj "/CN=www.it213.int"
- Anzeigen
- openssl req -in www.it213.int.csr -text -noout
Server-Zertifikat signieren
Die Sub-CA signiert das Server-Zertifikat und fügt einen Subject Alternative Name hinzu.
- Signieren
- openssl x509 -req -in www.it213.int.csr -CA it213-ca.crt -CAkey it213-ca.key -CAcreateserial -out www.it213.int.crt -days 365 -extfile <(printf "subjectAltName=DNS:www.it213.int")
- Anzeigen
- openssl x509 -in www.it213.int.crt -text -noout
Fullchain erstellen
Damit Clients die Zertifikatskette aufbauen können, muss der Server die Intermediate-CA mitliefern.
Dazu wird eine Fullchain-Datei erstellt.
- cat www.it213.int.crt it213-ca.crt > fullchain.pem
Die Reihenfolge ist wichtig.
www.it213.int.crt it213-ca.crt
Zertifikatskette prüfen
Die komplette Zertifikatskette kann mit OpenSSL überprüft werden.
- openssl verify -CAfile ca.crt -untrusted it213-ca.crt www.it213.int.crt
PKI-Struktur
Kit Root CA
└── it213-ca
└── www.it213.int
Der Client kennt die Root-CA aus dem Trust-Store.
Der Server liefert beim TLS-Handshake das Server-Zertifikat und die Sub-CA.
Der Client kann damit die vollständige Zertifikatskette prüfen.
Troubleshooting: OpenSSL & PKI Fehler
| Fehlermeldung / Symptom | Mögliche Ursache | Lösung |
|---|---|---|
| "Self-signed certificate in certificate chain" | Der Client vertraut der Root-CA nicht oder die Root-CA wurde nicht im Trust-Store installiert. | Prüfen, ob update-ca-certificates (Debian) oder update-ca-trust (Rocky) ausgeführt wurde. Browser ggf. neu starten. |
| "Depth lookup: unable to get local issuer certificate" | Die Intermediate-CA (Sub-CA) fehlt in der Kette, die der Server ausliefert. | Prüfen, ob die Datei fullchain.pem korrekt erstellt wurde (Reihenfolge!) und im Webserver (SSLCertificateFile / ssl_certificate) eingebunden ist. |
| "Certificate is not valid for 'xyz.int'" | Der Subject Alternative Name (SAN) fehlt oder ist falsch geschrieben. | Zertifikat prüfen mit: openssl x509 -in cert.crt -text -> Suche nach "X509v3 Subject Alternative Name". |
| "Verification error: certificate has expired" | Systemzeit auf Server oder Client ist falsch (häufig bei VMs nach Suspend). | Datum/Uhrzeit mit dem Befehl date prüfen und ggf. per NTP synchronisieren. |
| "Modulus mismatch" | Der private Schlüssel passt kryptografisch nicht zum vorliegenden Zertifikat. | Vergleichen der MD5-Hashes beider Dateien (siehe unten unter "Nützliche Befehle"). |
| "CA:FALSE" bei der Sub-CA | Die Sub-CA wurde ohne die Extension basicConstraints=CA:TRUE signiert. | Die Sub-CA ist nicht berechtigt, weitere Zertifikate zu signieren. Sub-CA mit den richtigen Extensions neu erstellen. |
Nützliche Prüfbefehle für die Administration
Modulus-Check (Passen Key und CRT zusammen?)
Um sicherzustellen, dass ein Zertifikat zu einem Private Key gehört, müssen die Modulus-Hashes identisch sein:
openssl x509 -noout -modulus -in www.it213.int.crt | openssl md5
openssl rsa -noout -modulus -in www.it213.int.key | openssl md5
TLS-Handshake live testen
Simuliert einen Verbindungsaufbau und zeigt die vom Server gesendete Zertifikatskette an:
openssl s_client -connect localhost:443 -showcerts
Zertifikatsinhalt schnell prüfen
openssl x509 -in fullchain.pem -text -noout
Python Webserver mit SSL/TLS
In dieser Anleitung wird ein einfacher HTTPS-Webserver mit Python erstellt, der statische Inhalte aus einem Verzeichnis ausliefert.
Als erstes müssen wir die fullchain.pem und den privaten Schlüssl zu Server bringen
- scp fullchain.pem it213-ca.key www:
Verzeichnis erstellen
Zuerst wird ein Arbeitsverzeichnis für die Webinhalte und das Server-Skript angelegt.
- mkdir html
Keys anpassen
Die Zertifikatsdateien müssen in das Verzeichnis kopiert und für das Skript passend benannt werden.
- cp fullchain.pem html/own.crt
- cp www.it213.int.key html/own.key
Konfiguration
Das Python-Skript konfiguriert den Server so, dass er auf Port 8443 lauscht und die SSL-Verschlüsselung nutzt.
- nano html/https.py
import http.server, ssl
server_address = ('0.0.0.0', 8443)
handler = http.server.SimpleHTTPRequestHandler
httpd = http.server.HTTPServer(server_address, handler)
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="own.crt", keyfile="own.key")
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print("HTTPS läuft auf https://0.0.0.0:8443")
httpd.serve_forever()
Statische Seite erstellen
Damit der Server eine Seite anzeigt, wird eine index.html im Verzeichnis erstellt.
- nano html/index.html
<html> <head> <title>IT213 Testseite</title> </head> <body> <h1>Erfolg!</h1> <p>Der verschlüsselte Python-Webserver funktioniert und liefert diese Seite aus.</p> </body> </html>
Starten
Um den Server zu starten, wechselt man in das Verzeichnis und führt das Skript aus.
- cd html
- python3 https.py
Der Zugriff erfolgt im Browser über https://www.it213.int:8443.