Eigene Zertifizierungsstelle (CA) mit Sub-Zertifizierungsstellen (Sub-CA’s)

Achtung! Dieser Artikel ist älter als ein Jahr. Der Inhalt ist möglicherweise nicht mehr aktuell!

Artikel zur Erstellung einer Zertifizierungsstelle mit nur einer Identität gibt es wie Sand am Meer. Die darin beschriebenen Methoden sind aber meistens sehr wage beschrieben oder verwenden veraltete Crypto.

Für die Arbeit habe ich eine neue PKI erstellen müssen. Im folgenden Artikel sind meine Erkenntnisse zusammengefasst.

Vorbereitung

Soll-Zustand

Als erstes sollte man sich Gedanken machen, wie die Struktur der Zertifizierungsstellen aussehen soll. Als Beispiel nehme ich in diesem Artikel die Example AG. Diese hat mehrere Abteilungen, zum Beispiel „Development“. Damit Unternehmensweit eine anständige Public-Key-Infrastruktur (PKI) verfügbar ist, soll eine unternehmensweite Zertifizierungsstelle (Root-CA) entstehen sowie eine Unter-Zertifizierungsstelle für jede Abteilung (Sub-CA).

Der Aufbau sieht also wie folgt aus:

ca_struktur

Warnung: Das ist kein Copy & Paste Tutorial! Bitte unbedingt mitdenken!

Bestandteile, die nicht behandelt werden

Einige Bestandteile covert dieser Artikel (noch) nicht:

Im Normalfall existieren solche System schon oder werden gar nicht benötigt.

Verwendete Softwareumgebung

In diesem Artikel verwende ich einen normalen Debian 8.1 Server. Für die CAs wird OpenSSL aus den Standardrepositories verwendet. Aktuell habe ich die Version 1.0.1k vom 08. Januar 2015. Die Verwendete Linux Distribution ist im Normalfall irrelevant. Meistens ändert sich nur der Pfad der Standard-Konfigurationsdatei. Der Aufbau der Kommandos unterscheiden sich nicht.

Konfigurationsdatei

OpenSSL verwendet auf Debian-Basierenden Systemen standardmäßig die Config-Datei unter /etc/ssl/openssl.cnf . Diese Datei muss zuerst erweitert werden. Neue Blöcke sollten immer an das Ende der Datei gepackt werden.

Mit Blöcken sind Abschnitte gemeint, wobei jeder Abschnitt durch eine Zeile mit „[ irgendeintext]“ gekennzeichnet ist.

Zertifizierungsstellen definieren

Jede Zertifizierungsstelle benötigt einen eigenen Block in der Konfigurationsdatei. Für die Root-CA sieht der Block wie folgt aus:

[ CA_example-root ]
dir = /opt/ca/example-root-ca # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/ca-cert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/ca-key.pem # The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = v3_ca # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 1825 # how long to certify for
default_crl_days= 7 # how long before next CRL
default_md = sha256 # use public key default MD
preserve = no # keep passed DN ordering
policy = policy_match

Hervorzuhebende / Wichtige Einstellungen sind:

Für jede Sub-CA muss jeweils ein eigener Block eingefügt werden. Hier am Beispiel der Development Sub-CA:

[ CA_example-development ]
dir = /opt/ca/example-development-ca # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/ca-cert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/ca-key.pem # The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 365 # how long to certify for
default_crl_days= 7 # how long before next CRL
default_md = sha256 # use public key default MD
preserve = no # keep passed DN ordering
policy = policy_anything

Vergleicht man die Parameter mit der der Root-CA gibt es zwei wesentliche Unterschiede:

Optional: Policies

Dieser Schritt ist optional und nur wichtig, wenn eine eigene Policy angelegt werden soll. Im Normalfall reichen die vordefinierten Policies _policymatch und _policyanything vollkommen aus.

Beispiel einer Policy anhand der bestehenden Policy _policymatch:

[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

Die einzelnen Optionen sind die selben, die man bei der Erstellung eines CSR ausfüllen muss. Dahinter steht dann entweder

Möchte man eine eigene Policy erstellen kopiert man den Block und ändert ihn dementsprechend.

Erstellen der Infrastruktur

In der Konfigurations-Datei wurde das Layout des Filesystems definiert. Nun muss diese Vorgabe physisch im Dateisystem erstellt werden. Danach erstellt man den privaten Schlüssel – dem wichtigsten Teil der PKI.

Erstellung der Root-CA

Wechsle ins Verzeichnis /opt und erstelle einen Ordner example-root-ca:

:~$ cd /opt
:~$ mkdir example-root-ca
:~$ cd example-root-ca

Erstellen der benötigten Dateien und Ordner sowie initiale Wertebefüllung:

:~$ mkdir certs crl newcerts private
:~$ touch index.txt
:~$ echo "01" > serial
:~$ echo "01" > crlnumber

Im Ordern certs werden Kopien der ausgestellten Zertifikate gespeichert. Im Ordner crl wird eine Kopie aller erstellen CRL’s gespeichert. Im Ordner private wird der private Schlüssel gespeichert. Hier möchte man eventuell die Rechte 0600 setzen.

Den privaten Schlüssel erstellt man mit folgendem Kommando:

:~$ openssl genrsa -aes256 -out private/ca-key.pem 4096

Der private Schlüssel wird durch ein Passwort geschützt. Möchte man das nicht tun – was ich nicht empfehle – muss man nur den Parameter -aes256 entfernen.

Das Passwort sollte entsprechend lang und komplex sein.

Da das Zertifikat eine Gültigkeit von 10 Jahre besitzen soll muss die verwendete Kryptographie zukunftssicher sein. 1024 bit RSA oder DSA ist unter keinen Umständen mehr sicher. 2048 bit ist aktuell als sicher einzustufen, aber bestimmt nicht für die nächsten 10 Jahre. Deswegen wird 4096 bit RSA verwendet.

Die Root-CA muss Ihre Identität selbst unterschreiben. Deswegen wird das Zertifikat mit dem eigenen Key signiert („self signed“):

:~$ openssl req -new -x509 -days 3650 -sha512 -key private/ca-key.pem -out ca-cert.pem

Man wird nun zur Eingabe von Zertifikatsdetails gebeten:

Enter pass phrase for private.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:DE
State or Province Name (full name) []:Bayern
Locality Name (eg, city) [Default City]:Regensburg
Organization Name (eg, company) [Default Company Ltd]:Example AG
Organizational Unit Name (eg, section) []:.
Common Name (eg, your name or your server's hostname) []:Example AG Root Certificate Authority
Email Address []:contact@example.com

Das Root-Zertifikat ist nun 3650 Tage (~ 10 Jahre) gültig, hat einen starken Kryptographischen Unterbau und verwendet SHA-512 als Unterzeichnus-Algorithmus.

Erstellung von Sub-CA’s

Wenn die Root-CA steht können weitere Sub-CAs erstellt werden. Diese Zertifizierungsstellen beglaubigen letztendlich End-Zertifikate und werden bis auf den letzten Schritt identisch erstellt. Der Unterschied: Die Sub-CA unterschreibt ihr Zertifikat nicht mit dem eigenen privaten Schlüssel. Die Root-CA stellt das Zertifikat aus. Dadurch wird die „Chain of trust“ aufgebaut.

Angenommen die Example CA hat eine Abteilung Development, für die eine Sub-CA erstellt werden soll:

:~$ cd /opt
:~$ mkdir example-development-ca
:~$ cd example-development-ca
:~$ mkdir certs crl newcerts private
:~$ touch index.txt
:~$ echo "01" > serial
:~$ echo "01" > crlnumber
:~$ openssl genrsa -aes256 -out private/ca-key.pem 2048

Während der Erstellung des neuen privaten Schlüssels wird man wieder nach einem Passwort gefragt. Dieses sollte sich von dem der Root-CA unterscheiden. Diese Identität muss nun von der Root-CA signiert werden. Dazu muss ein Certificate Signing Request (CSR) erstellt werden.

:~$ openssl req -new -key private/ca-key.pem -out example-development-ca.csr

Bei der Erstellung wird man wieder nach den Details gefragt:

Enter pass phrase for private.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:DE
State or Province Name (full name) []:Bayern
Locality Name (eg, city) [Default City]:Regensburg
Organization Name (eg, company) [Default Company Ltd]:Example AG
Organizational Unit Name (eg, section) []:.
Common Name (eg, your name or your server's hostname) []:Example AG Development Certificate Authority
Email Address []:development@example.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

In jedem Ordner einer Sub-CA sollte nun ein CSR liegen. Diese werden nun nacheinander der Root-CA vorgeworfen, die letztendlich das Zertifikat ausstellt.

Arbeiten mit den CA’s

Signieren einer neuen Sub-CA

Wie oben beschrieben muss die Sub-CA zuerst erstellt werden. Der daraus resultierende CSR wird dann von der Root-CA bearbeitet und letztendlich das Zertifikat ausgestellt. Dazu wechselt man als erstes in den Ordner der Root-CA:

:~$ cd /opt/ca/example-root-ca

Mit Hilfe des folgenden Befehls wird der CSR eingelesen und ein Zertifikat ausgestellt:

:~$ openssl ca -name CA_example-root -in ../example-development-ca/example-development-ca.csr -out ../example-development-ca/ca-cert.pem

Während des Vorgangs wird man nach einem Passwort gefragt. Dabei handelt es sich um das Passwort des privaten Schlüssels der Root-CA. Die benötigten default-Einstellungen wird mit Hilfe des Blocks in der Konfigurationsdatei und der Angabe als Parameter geladen (Orange-markiert).

Wichtig ist, dass man die grün markierten Pfade für jede Sub-CA ändert!

Signieren von normalen Zertifikaten

Normale Zertifikate werden mit den Sub-CA’s ausgestellt. Damit ein Zertifikat ausgestellt werden kann, wird ein CSR benötigt. Im Normalfall kommt jemand auf einen zu uns sagt: „Du bist doch der, der die Zertifikate macht – ich bräuchte eins“.

Angenommen dein Kollege hat dir schon einen CSR geschickt und du hast ihn auf dem Server unter /tmp/request.csr abgelegt. Zum Ausstellen des Zertifikates wird folgender Befehl verwendet:

:~$ openssl ca -name CA_example-development -in /tmp/request.csr -out /tmp/certificate.pem

Während dieses Vorgangs wird man wieder nach einem Passwort gefragt. Dabei handelt es sich um das Passwort für den privaten Schlüssel der Sub-CA. Danach liegt unter /tmp/certificate.pem das ausgestellte Zertifikat, das du deinem Kollegen schickst.

Verteilung der CA Zertifikate

Damit ausgestellte End-Zertifikate korrekt validiert werden und es zu keinen Fehlermeldungen oder Warnungen kommt, muss das Zertifikat der Root-CA und der Sub-CA an die Clients manuell als vertrauenswürdig eingestuft werden.

Bei Firefox und Chrome muss man die Zertifikate der Root-CA und Sub-CA als Zertifizierungsstellen hinzugefügt werden. Beim Java Keytool müssen beide Zertifikate in einen Keystore/Truststore importiert werden.

Nur wenn beide CA Zertifikate vorhanden und beglaubigt sind wird eine Fehlermeldung verhindert, da das ausgestellte Endzertifikat anhand der Chain of Trust überprüft werden kann.

Further Reading


Du hast einen Kommentar, einen Wunsch oder eine Verbeserung? Schreib mir doch eine E-Mail! Die Infos dazu stehen hier.

🖇️ = Link zu anderer Webseite
🔐 = Webseite nutzt HTTPS (verschlüsselter Transportweg)
Zurück