nginx: Aktivierung von OCSP Must-Staple ohne Timeout

In diesem kurzen Microblog-Beitrag möchte ich auf die Aktivierung von OCSP Must-Staple in Kombination mit nginx eingehen. Nach der Aktivierung dieses Features hatte ich beim Aufruf sporadisch folgende Fehlermeldung im Client (Browser, Firefox):

MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING

Wie sich das Vermeiden lässt, zeigt der vorliegende Beitrag.

Was ist OCSP Stapling überhaupt? Das ist hier kompakt erklärt: Using OCSP Stapling to Improve Response Time and Privacy. Kurzer Ausschnitt aus der Wikipedia dazu:

Online Certificate Status Protocol stapling, formell bekannt als die TLS-Zertifikatsstatusabfrage-Erweiterung, ist ein alternativer Ansatz zum Online Certificate Status Protocol (OCSP) um den Gültigkeitsstatus von digitalen Zertifikaten nach X.509 zu prüfen.[1] Es ermöglicht dem Zertifizierten die Aufgabe der Zertifikatsvalidierung zu übernehmen, indem er eine von der Zertifizierungsstelle signierte OCSP-Antwort mit Zeitstempel an den ursprünglichen TLS-Handshake anhängt („stapling“). Dieses Verfahren verringert den Kommunikationsaufwand zwischen Clients und Zertifizierungsstellen deutlich.

OCSP Must-Staple ist nun eine Erweiterung für Zertifikate, damit Clients bereits während des TLS-Handshakes über die Verwendung von OCSP-Stapling informiert werden können.

Nun aber zur Umsetzung anhand eines Beispiels. Konkret wird eingesetzt:

Zunächst generieren wir uns den Certificate Signing Request (CSR):

openssl req -new -sha512 -key /etc/ssl/private/kuketz-blog.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:kuketz-blog.de,DNS:www.kuketz-blog.de\ntlsfeature=status_request")) > /etc/ssl/certs/kuketz-blog.csr

Achtet auf die Ergänzung:

tlsfeature=status_request (siehe RFC7633)

Wir setzen das Must-Staple Flag also direkt schon beim Signing Request.

Anschließend lassen wir den Request von Let’s Encrypt bestätigen bzw. unterschreiben:

acme.sh --signcsr --ocsp-must-staple --keylength ec-384 --csr /etc/ssl/certs/kuketz-blog.csr -w /var/www/sites/www.kuketz-blog.de/

Achtet hier auf die Ergänzung:

--ocsp-must-staple

Ihr müsst Let’s Encrypt über das Vorhandensein des Must-Staple Flag informieren.

Anschließend könnt ihr in nginx OCSP-Stapling aktivieren und das Zertifikat wie gewohnt ausrollen bzw. benutzen:

# OCSP-Stapling
ssl_stapling on;
ssl_stapling_verify on;

In der Praxis ist dann allerdings beim Aufruf des Blogs (erster Verbindungsversuch) via Firefox folgender Fehler aufgetreten:

MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING

Warum ist das so? Bei der Abfrage der OCSP-Antwort beim Aussteller des Zertifikats (hier Let’s Encrypt) ist nginx (teilweise) nicht schnell genug. Es kann also vorkommen, dass die erste Antwort an den Client ohne angeheftete OCSP-Informationen erfolgt. Folglich wird der Client (Browser) den Verbindungsaufbau ablehnen, da er diese Information als Teil der Zertifikats erwartet. Als Workaround kann der Nutzer einfach nochmal die Seite aktualisieren. Im Normalfall sendet nginx dann spätestens im zweiten Anlauf die OCSP-Information mit an den Client raus. Für die Praxis ist dies natürlich nicht optimal.

nginx bietet daher die Möglichkeit, über eine Direktive (ssl_stapling_file), die OCSP-Antwort der CA lokal aus einer Datei auszulesen, um diese bei einem Verbindungsaufbau direkt an den Client übersenden zu können – ohne dabei in Verzug zu kommen. Das Problem ist nur: Wie kommen wir an die OCSP-Antwort von Let’s Encrypt? Das geht via OpenSSL-Kommando.

Zunächst benötigen wir die OCSP-URI, die in unserem signierten Zertifikat steckt:

openssl x509 -noout -ocsp_uri -in /etc/ssl/certs/kuketz-blog.pem

Ausgabe

http://ocsp.int-x3.letsencrypt.org

Anschließend müssen wir diese Information gemeinsam mit der OCSP-Antwort für unser Zertifikat in DER-kodiertem Format speichern:

openssl ocsp -no_nonce -issuer /root/.acme.sh/kuketz-blog.de/ca.cer -verify_other /root/.acme.sh/kuketz-blog./ca.cer -cert /etc/ssl/certs/kuketz-blog.pem -respout /etc/ssl/certs/kuketz-blog_ocspresponse.der -url http://ocsp.int-x3.letsencrypt.org

Eben auf diese »zwischengespeicherte« OCSP-Antwort verweisen wir nun mit nginx:

# OCSP-Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_stapling_file /etc/ssl/certs/kuketz-blog_ocspresponse.der;

Problem gelöst. Keine verzögerten OCSP-Antworten mehr, die dann nicht mehr rechtzeitig bei einem Verbindungsversuch, von einem Client, mitgesendet werden können.

Testen ob OCSP Must-Staple funktioniert könnt ihr via SSL Labs. Unter dem Bereich »Server Key and Certificate #1« wird in der Zeile bei OCSP Must-Staple erscheinen:

Supported

Ich werde das Thema OCSP Stapling bzw. HTTP-Security-Header mal demnächst in einer Artikelserie aufgreifen.

Hinweis

Die OCSP-Antwort eurer CA solltet ihr alle 24 Stunden via Cronjob erneuern.
Der Kuketz-Blog ist spendenfinanziert! Mitmachen ➡