Erstellung eigener vertrauenswürdiger SSL-Zertifikate

Für öffentliche (Web)Server ist die Erstellung von kostenlosen SSL-Zertifikaten dank Let's Encrypt mittlerweile sehr einfach möglich. Benötigt man aber ein Zertifikat für Server im Intranet, z.B. für Testsysteme oder weil eine Software SSL voraussetzt, ist ein Abruf von Zertifikaten von Let's Encrypt nicht mehr möglich. Denn dazu müsste der Server über das Internet erreichbar sein und der Domainname im DNS des Providers registriert sein.

Für private Server bleibt daher nur die Verwendung von Zertifikaten, die man selbst erstellt und zertifiziert hat. Allerdings lassen sich diese Zertifikate nicht (mehr) so einfach verwenden, da sie insbesondere aus Sicht der Web Browser ein Sicherheitsrisiko darstellen. Aber auch andere Tools müssen häufig erst "überredet" werden, solche Zertifikate zu akzeptieren.

Die Ursache des Problems ist, dass die selbst-zertifizierten SSL-Zertifikaten nicht von einer vertrauenswürdigen Stammzertifizierungstelle (Certificate Authority, kurz "CA") gegenzertifiziert wurden. Die vertrauenswürdigen CAs (bzw. deren öffentliche Schlüssel) sind im Betriebssystem (bzw. Browser) fest hinterlegt und werden z.B. bei Betriebssystemupdates aktualisiert.

Die Lösung des Problems ist daher ganz einfach: wir machen uns selbst zu einer CA. Dazu müssen wir ein Stammzertifikat erstellen und dieses dann auf allen Geräten (und teilweise auch Browsern), die unsere selbst erstellten Zertifikate benötigen, importieren.

Das Verfahren benötigt zwar nur einzige Werkzeug ("OpenSSL"), aber die Verwendung ist nicht ganz trivial und ich habe auch einige Versuche und viel "Googlerei" benötigt, bis alles wie gewünscht funktionierte. Ich beschreibe daher im Folgenden ein Verfahren, mit dem sich die diversen Zertifikate unter verschiedenen Betriebssystemen und Browsern verwenden lassen.

Voraussetzung

Für die Arbeit mit Zertifikaten benötigt man nur ein Command Line Werkzeug: openssl. Auf Linux-Systemen ist OpenSSL i.d.R. bereits installiert oder kann einfach über die jeweilige Paketverwaltung installiert werden. Für Windows-Systeme kann es von der Website des OpenSSL Installation Projects heruntergeladen werden.

Ich habe die Windows-Variante nicht getestet, sondern das Ganze lieber unter Linux (bzw. in der WSL) gemacht.

💡
Ich habe openssl in der WSL (mit Ubuntu) von Windows 11 ausgeführt. Damit die Befehle besser lesbar sind, habe ich sie umgebrochen. In der Windows Command Line müssen die Befehle entweder in eine Zeile geschrieben werden oder der \ am Zeilenende muss durch ^ ersetzt werden.

Stammzertifikat (ROOT)-Zertifikat erstellen

Im ersten Schritt muss ein Stammzertifikat mit zugehörigem privatem Schlüssel erstellt werden.

Zunächst wird ein privater Schlüssel erzeugt, der in der Datei myRoot.key gespeichert wird (der Dateiname ist natürlich frei wählbar):

openssl genrsa -out myRoot.key 2048

Im nächsten Schritt wird dann das eigentliche Zertifikat für unsere CA erstellt:

openssl req -x509 -new -nodes -key myRoot.key -sha256 -days 3650 \  
            -out myRoot.crt

Das neue Zertifikat wird in der Datei myRoot.crt gespeichert. Die Speicherung erfolgt dabei im PEM-Format(). Allerdings ist die Dateierweiterung .crt gebräuchlicher als .pemund erleichtert später das Einspielen des Zertifikats.

Für die Erstellung des Zertifikats werden verschiedene Informationen abgefragt:

Country Name (2 letter code) [1]:DE
State or Province Name (full name) [2]:NRW
Locality Name (eg, city) :Brilon
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyFirma
Organizational Unit Name (eg, section) :
Common Name (e.g. server FQDN or YOUR name) :example.com
Email Address :root@example.com

Es ist eigentlich relativ egal, was hier eingegeben wird, aber sinnvolle Eingaben erleichtern später das Auffinden des Zertifikats.

Ob das Zertifikat richtig erstellt wurde, kann mit Hilfe von openssl überprüft werden. Mit dem Befehl

openssl x509 -in myRoot.crt -text -noout

werden alle im Zertifikat enthaltenen Informationen ausgegeben. Besonders wichtig ist dabei dieser Wert:

X509v3 Basic Constraints: critical
                CA:TRUE

Installation des Zertifikats

Das im vorherigen Schritt erstellte Zertifikat myRoot.crt kann jetzt auf allen Rechnern und Browsern installiert werden, dies es benötigen.

Microsoft Windows

Microsoft Windows hat eine zentrale Zertifikatsverwaltung, die aber nicht so ganz einfach zu finden ist. Um sie aufzurufen, startet man die "Microsoft Management Console" (mmc.exe) und fügt das Snap-in "Zertifikate" hinzu.

Zum Importieren des selbst erstellten Zertifikats benötigt man diese Verwaltung allerdings nicht zwingend. Es reicht aus, die Datei mit dem Zertifikat (myRoot.crt) mit der rechten Maustaste anzuklicken und im Kontextmenü den Menüpunkt Zertifikat installieren aufzurufen. Es wird dann der "Zertifikatimport-Assistent" gestartet.

Im Assistenten wählt man auf der Startseite unter Speicherort die Einstellung "Lokaler Computer" aus und klickt den Weiter-Knopf an. Hierzu sind Administratorrechte nötig.

Auf der Folgeseite muss dann der passende Speicher für das Zertifikat ausgewählt werden.

Das Zertifikat muss zwingend im Speicher für "Vertrauenswürdige Stammzertifizierungsstellen" abgelegt werden.

Linux (Debian, Ubuntu)

Auf Linux-Systemen muss das Zertifikat ebenfalls in den entsprechenden Zertifikatsspeicher kopiert werden. Unter Debian und Ubuntu geht dies wie folgt:

sudo mkdir /usr/local/share/ca-certificates/extra
sudo cp myRoot.crt \    
        /usr/local/share/ca-certificates/extra/myRoot.crt
sudo update-ca-certificates

Bei anderen Linux-Systemen dürfte das Verfahren ähnlich sein.

Android und iOS

Bei Android- und iOS-Geräten muss zunächst die Zertifikatsdatei auf das Gerät gelangen. Das ist bei Android-Geräten meistens einfacher als bei den iOS-Pendants.

Eine allgemein verfügbare Möglichkeit ist der Versand per E-Mail. Hierbei kann es allerdings passieren, dass die Mail vom Provider blockiert wird, weil die angehängte Datei verdächtig erscheint (T-Online mag sie zum Beispiel nicht).
Ist die Datei erst einmal auf dem Gerät, reicht ein "Klick" auf die Datei, um die passende System-App für den Import zu starten. Alternativ kann die Zertifikatsverwaltung auch aus den Systemeinstellungen.

Firefox Browser

Der Firefox Browser hat eine eigene Verwaltung für Stammzertifikate. Um ein neues Zertifikat zu importieren, ruft man die Einstellungen auf und wählt den Unterpunkt Datenschutz & Sicherheit aus.

Ganz unten auf der Einstellungsseite befindet sich der Button Zertifikate anzeigen .... Klickt man diesen Button an, erscheint ein Dialog mit mehreren Tabs. Dort wechselt man zunächst zum Tab Zertifizierungsstellen und klickt auf den Importieren Button. Es kann dann über einen Dateiauswahldialog das Zertifikat (myRoot.crt) ausgewählt werden.

Im Bestätigungsdialog für das "Herunterladen des Zertifikats" muss noch die Option "Dieser CA vertrauen, um Websites zu identifizieren" selektiert und der Dialog mit OK verlassen werden. Anschließend sollte sich das Zertifikat dann unter Zertifikatsstellen befinden.

Zertifikat für eine (Sub)Domain erstellen

Nach der Erstellung und Verteilung des Stammzertifikats können jetzt beliebig viele Zertifikate für (Sub)Domains erstellt werden. Das Verfahren entspricht der allgemeinen Vorgehensweise für die Beantragung und Erstellung eines Zertifikats:

  1. Zunächst werden ein privater Schlüssel und ein CSR (Certificate Signing Request) erstellt.
  2. Aus dem CSR wird dann mit Hilfe des Stammzertifikats ein Zertifikat für die Domäne erstellt.
  3. Dieses Zertifikat kann anschließend z.B. im Web Server konfiguriert werden.

Es gibt verschiedene Möglichkeiten den Schlüssel, den CSR und das Zertifikat zu erstellen. Dabei gibt es evtl. auch einfachere Varianten als das von mir getestete und beschriebene Verfahren.

Die nach diesem Verfahren erstellten Zertifikate werden von allen getesteten Browsern (Chrome, Firefox, Edge) anstandslos akzeptiert.
Insbesondere Chrome ist da sehr "sensibel".

Privater Schlüssel und CSR erstellen

Für jede Zertifikatsanforderung müssen zunächst ein privater Schlüssel und ein CSR erstellt werden. Das geht am einfachsten, in dem pro Domain zunächst eine Konfigurationsdatei mit den notwendigen Daten erstellt wird.

Als Domainname verwende ich in den Beispielen test.example.private.

Die Konfigurationsdatei sieht dann wie folgt aus:

[req]  
default_bits = 2048   
prompt = no  
default_md = sha256 
distinguished_name = dn
[dn]
C=DE
ST=NRW
L=MeinOrt
O=MeinName
emailAddress=webmaster@example.private
CN = test.example.private

Der gewünschte Domainname steht in der letzten Zeile. Für eine andere Domain muss nur diese Zeile angepasst werden. Ich würde aber auch für die anderen Werte im Bereich [dn] passende Werte eintragen.

Ich habe die Konfigurationsdatei unter dem Dateinamen test.example.csr.cnf gespeichert.

Der CSR und der private Schlüssel werden dann mit diesem Befehl erstellt:

openssl req -new -sha256 -nodes \    
            -out test.example.csr \    
            -newkey rsa:2048 -keyout test.example.key \    
            -config test.example.csr.cnf

Der private Schlüssel wird in der Datei test.example.key abgelegt. Er wird später auch für die Konfiguration des (Web)Servers benötigt.

Der CSR befindet sich in der Datei test.example.csr. Für die Erzeugung des Zertifikats wird nur der CSR benötigt.

Server-Zertifikat erstellen

Für die Erstellung des Server-Zertifikats wird zunächst eine weitere Konfigurationsdatei erstellt:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = test.example.private

Auch hier muss für andere Domains nur jeweils die letzte Zeile angepasst werden.
Der Eintrag in dieser Zeile muss unbedingt exakt dem Eintrag CN in der Konfigurationsdatei für die CSR-Erstellung entsprechen.

Die Konfigurationsdatei habe ich unter dem Namen test.example.ext.cnf gespeichert.

Neben dieser Konfigurationsdatei und der CSR-Datei werden auch das Zertifikat und der private Schlüssel der CA benötigt.

Die Erstellung des Zertifikats erfolgt mit dem folgenden Befehl:

openssl x509 -req -in test.example.csr \  
             -CA myRoot.crt -CAkey myRoot.key -CAcreateserial \  
             -extfile test.example.ext.cnf \  
             -out test.example.crt -days 3650 -sha256

Das neu erzeugte Zertifikat ist in diesem Bespiel 10 Jahre (= 3650 Tage) gültig und wird in der Datei test.example.crt gespeichert.

Der Inhalt des Zertifikats kann durch Aufruf des Befehls

openssl x509 -in test.example.crt -text -noout

überprüft werden. Wichtig sind die folgenden Einträge:

 X509v3 extensions:
     ...
     X509v3 Subject Alternative Name:
         DNS:test.example.private

Es muss unbedingt die "X509v3 extension" vorhanden sein und der "Subject Alternative Name" muss dem Domainnamen entsprechen.

SSL im Web Server konfigurieren

Die folgende Konfiguration eines NGINX Web Servers ist nur ein Beispiel.
Für die Konfiguration des Servers für den Zugriff via SSL werden das Server-Zertifikat (ssl_certificate) und der zugehörige private Schlüssel (ssl_certificate_key) benötigt.
Die Konfiguration sieht dann wie folgt aus (Pfadangaben sind Windows-like):

server {
   listen 443 ssl;
   server_name  test.example.private;
   ssl_certificate c:/nginx/test.example.crt; 
   ssl_certificate_key c:/nginx/test.example.key; 

   location / {
      ...
   }
}

Für andere Web Server wie z.B. Apache sieht die Konfiguration ähnlich aus.