1. Index
  2. Debian
  3. Desktop
  4. Heimserver
  5. Webserver

Zertifikate ausstellen

OpenSSL ist ein Werkzeugkasten für kryptografische Funktionen. Er ermöglicht den Betrieb einer PKI mit eigener Zertifizierungsstelle. Wir erzeugen hier Schlüssel und Zertifikate für unsere Server. Im Idealfall liegen die Daten auf einem sicheren Rechner ohne Verbindung zum Internet, aber ein verschlüsselter Arbeitsplatzrechner tut es auch.

Paket installieren

Das Paket openssl enthält das gleichnamige Programm und die zugehörige Dokumentation.

apt install openssl

Voreinstellungen konfigurieren

Standardmäßig liest das Programm openssl Voreinstellungen aus der globalen Konfigurationsdatei /etc/ssl/openssl.cnf. Wir legen für jede Zertifizierungsstelle eine eigene Datei an.

Die ersten Abschnitte konfigurieren das Ausstellen von Zertifikaten beim Aufruf des Subkommandos ca. Wir speichern alle Dateien im Arbeitsverzeichnis.

openssl.cnf
[ca] default_ca = illusioni_ca [illusioni_ca] dir = . # Where everything is kept certs = $dir # - issued certificates crl_dir = $dir # - issued crl's new_certs_dir = $dir # - new certificates RANDFILE = $dir/.rand # Private random number file serial = $dir/serial # Certificate serial number crlnumber = $dir/crlnumber # Revocation serial number database = $dir/index.txt # Database of issued certificates certificate = $dir/ca.crt # CA certificate private_key = $dir/ca.key # CA private key crl = $dir/crl.pem # Revocation List x509_extensions = usr_cert # Extensions for issued certificates 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 = 30 # How long before next CRL default_md = default # Public key default preserve = no # Keep passed DN ordering policy = illusioni_policy # Similarity constraints [illusioni_policy] countryName = match stateOrProvinceName = optional organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional

Die nächsten Abschnitte konfigurieren das Anfordern von Zertifikaten und welche Felder abgefragt werden.

# Key Generation and Certificate Signing Request
[req]
default_bits		= 2048
default_keyfile 	= private.key
string_mask		= utf8only
distinguished_name	= req_dn
attributes		= req_attr
x509_extensions		= v3_ca		# Extensions for self signed certificate
req_extensions		= v3_req	# Extensions for certificate requests

[req_dn]
countryName		= Country Name (2 letter code)
countryName_default	= DE
countryName_min		= 2
countryName_max		= 2
#stateOrProvinceName	= State or Province Name (full name)
#localityName		= Locality Name (eg, city)
0.organizationName	= Organization Name (eg, company)
#organizationalUnitName	= Organizational Unit Name (eg, section)
commonName		= Common Name (e.g. server FQDN or YOUR name)
commonName_max		= 64
emailAddress		= Email Address
emailAddress_max	= 64

[req_attr]
challengePassword	= A challenge password
challengePassword_min	= 4
challengePassword_max	= 20
unstructuredName	= An optional company name

Die restlichen Abschnitte werden referenziert, um festzulegen, wie die ausgestellten Zertifikate verwendet werden könnne.

[usr_cert]
basicConstraints	= CA:FALSE
subjectKeyIdentifier	= hash
authorityKeyIdentifier	= keyid, issuer
keyUsage		= nonRepudiation, digitalSignature, keyEncipherment

[v3_req]
basicConstraints	= CA:FALSE
keyUsage		= nonRepudiation, digitalSignature, keyEncipherment

[v3_ca]
basicConstraints	= critical, CA:true
subjectKeyIdentifier	= hash
authorityKeyIdentifier	= keyid:always, issuer
keyUsage		= cRLSign, keyCertSign

Die letzten beiden Abschnitte schränken die Verwendungsmöglichkeiten von Zertifikaten für OpenVPN ein.

[v3_vpn_server]
basicConstraints	= critical, CA:FALSE
subjectKeyIdentifier	= hash
authorityKeyIdentifier	= keyid:always, issuer:always
keyUsage		= critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
extendedKeyUsage	= critical, serverAuth

# Extension for OpenVPN client
[v3_vpn_client]
basicConstraints	= critical, CA:FALSE
subjectKeyIdentifier	= hash
authorityKeyIdentifier	= keyid:always, issuer:always
keyUsage		= critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage	= critical, clientAuth

Wurzelzertifikat erzeugen

Wir legen ein Verzeichnis für die Zertifizierungsstelle an und darin Dateien für eine Seriennummer und eine Liste der ausgestellten Zertifikate. Andernfalls verweigert die Zertifizierungsstelle ihre Arbeit. Schließlich kopieren wir die im noch anzupassende Konfigurationsdatei.

org=illusioni
mkdir $org
cd    $org
touch index.txt
touch index.txt.attr
echo 01 > serial
echo 01 > crlnumber

Begleitet von einer feierlichen Zeremonie erzeugen wir den Schlüssel und ein selbst-signiertes Wurzelzertifikat mit einer Gültigkeit von 10 Jahren.

orga=Illusioni
openssl req \
	-config openssl.cnf \
	-x509   \
	-new    \
	-nodes  \
	-newkey rsa:4096 \
	-days   3650 \
	-subj   /C=DE/O=$orga/CN=$orga CA \
	-keyout ca.key \
	-out    ca.crt

Dazu erzeugen wir eine Widerrufsliste (CRL), falls ein Schlüssel kompromittiert wird.

openssl ca -config openssl.cnf -gencrl -out ca.crl

Den Schlüssel halten wir geheim, aber das Zertifikat und die Widerrufsliste verteilen wir regelmäßig auf alle Server.

Serverzertifikat ausstellen

Ein Serverzertifikat wird in zwei Schritten ausgestellt: Zuerst generiert der Prinzipal einen Schlüssel und eine Anfrage (CSR), mit den zu beglaubigenden Metadaten.

orga=Illusioni
zone=illusioni.de
host=durmstrang
year=$(date +%Y)
openssl req \
	-config openssl.cnf \
	-new    \
	-nodes  \
	-subj   "/C=DE/O=$orga/CN=$host.$zone \
	-keyout $host-$year.key \
	-out    $host-$year.csr

Dann unterschreibt die Zertifizierungsstelle die Anfrage mit ihrem Schlüssel und stellt so das Zertifikat aus.

openssl ca \
	-config openssl.cnf \
	-notext \
	-in     $host-$year.csr \
	-out    $host-$year.crt

Wurzelzertifikat, Widerrufsliste sowie Serverzertifikat und -schlüssel kopieren wir auf den entsprechenden Host, der unter diesem Namen auch per Secure Shell erreichbar sein sollte.

scp ca.{crt,crl} $host-$year.{crt,key} $host:/etc/ssl

Zertifikat widerrufen

Falls der Schlüssel zu einem Zertifikat kompromittiert wurde oder es vor Ablauf der Frist aus dem Verkehr gezogen werden soll, widerrufen wir es und aktualisieren die Widerrufsliste.

openssl ca -config openssl.cnf -revoke $host-$year.crt
openssl ca -config openssl.cnf -gencrl -out ca.crl

Widerrufsliste ausgeben:

openssl crl -in ca.crl -noout -issuer -lastupdate -nextupdate
issuer=C = DE, ST = Some-State, O = Illusioni, CN = Illusioni Certificate Authority
lastUpdate=Nov 27 11:01:46 2018 GMT
nextUpdate=Dec 27 11:01:46 2018 GMT

Formate konvertieren

ASN.1
Abstract Syntax Notation One, Beschreibungssprache und Kodierung für verschachtelte Datenstrukturen
DER
Distinguished Encoding Rules, ASN.1-kodierte Binärdaten. Daneben gibt es noch PER CER und BER, die spielen im kryptographischen Kontext aber keine Rolle.
PEM
Privacy Enhanced Mail, Base64-kodierte DER-Daten

Unter Linux werden Schlüssel (*.key) Zertifikate (*.crt), Widerrufslisten (*.crl) etc. grundsätzlich, als PEM-Dateien in der Base64-kodierten gespeichert. Für den Austausch mit anderen Systemen müssen wir diese gelegentlich in andere Containerformate konvertieren.

PEM Beispiel

-----BEGIN CERTIFICATE-----
MIIDmTCCAoGgAwIBAgIBBTANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJERTE…
-----END CERTIFICATE-----

DER erzeugen

openssl x509 -outform der -in certificate.pem -out certificate.der
openssl x509 -inform  der -in certificate.crt -out certificate.pem

P7B erzeugen

openssl crl2pkcs7 -nocrl -certfile certificate.crt -out certificate.p7b -certfile ca.crt
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.pem

PFX erzeugen

openssl pkcs12 -export -inkey private.key -in certificate.crt -certfile ca.crt -out certificate.pfx
openssl pkcs12 -nodes -in certificate.pfx -out certificate.pem

Nachrichten verschlüsseln

Alice und Bob erzeugen jeweils ein Schlüsselpaar und lassen dieses von der Zertifizierungsstelle ihres Vertrauens unterschreiben.

openssl req   \
	-new    \
	-nodes  \
	-subj   /C=DE/O=Example/CN=Alice/emailAddress=alice@example.org \
	-keyout alice.key \
	-out    alice.csr
openssl ca -batch \
        -in     alice.csr \
        -out    alice.crt

Alice unterzeichnet ihre Nachricht mit ihrem Schlüssel.

openssl smime \
	-sign   \
        -signer alice.crt \
        -inkey  alice.key \
        -in     plaintext.eml \
        -out    signed.eml

Alice verschlüsselt die Nachricht für Bob:

openssl smime \
	-encrypt \
        -subject Hello \
        -from    alice@example.org \
        -to      bob@example.net \
        -in      signed.eml \
        -out     encrypted.eml \
        bob.crt

Bob entschlüsselt die Nachricht von Alice:

openssl smime \
	-decrypt \
	-in     encrypted.eml
	-out    decrypted.eml

Bob verifiziert die digitale Signatur von Alice:

openssl smime \
	-verify \
	-in     decrypted.eml \
	...

Referenz

@todo Disclaimer

Kommando Operand Beschreibung
opensslhelp [Command] (Optionen eines) Kommandos auflisten
asn1parse ASN-1-Strukturen erkunden
ca Zertifikate ausstellen und widerrufen
ciphers Verschlüsselungsverfahren auflisten
cms Certificate S/MIME-Nachrichten im CMS-Standard bauen
crl Widerufsliste verwalten
crl2pkcs7 Widerufsliste und Zertifikate verpacken
dgst File Prüfsumme bilden
dhparam Bits Diffie-Hellmann-Paramter erzeugen
dsa DSA-Schlüssel erzeugen
dsaparam DSA-Parameter erzeugen
ec EC-Schlüssel erzeugen
ecparam EC-Parameter erzeugen
enc Daten verschlüsseln und entschlüsseln
engine Engine Treiber anzeigen
errstr ErrorCode Fehlercode nachschlagen
gendsa File DSA-Schlüssel aus Parameter-Datei erzeugen
genpkey Privaten Schlüssel erzeugen
genrsa Bits RSA-Schlüssel erzeugen
list Algorithmen oder Kommandos auflisten
nseq Netscape-Zertifikatslisten untersuchen
ocsp OCSP-Status eines Zertifikats abfragen
passwd Password Prüfsumme berechnen
pkcs7 PKCS#7-Zertifikate verwalten
pkcs8 PKCS#8-Schlüssel verwalten
pkcs12 PKCS#12-Schlüsselring verwalten
pkey Private und öffentliche Schlüssel verarbeiten
pkeyparam Parameter für öffentliche Schlüssel verarbeiten
pkeyutl Operation auf öffentlichem Schlüssel ausführen
prime [Number] Primzahl finden oder prüfen
rand Count Zufällige Bytes erzeugen
rehash Dir Symbolische Links für Zertifikate erzeugen
req PKCS#10 Zertifikatsanfrage stellen
rsa RSA-Schlüssel bearbeiten
rsautl Daten signieren, ver-/entschlüsseln und verifizieren
s_client Target TLS-Client
s_server TLS-Server
s_time Zeit für Seitenaufrufe messen
sess_id SSL-Sitzung untersuchen
smime S/MIME-Nachrichten signieren, ver-/entschlüsseln und verifizieren
speed Leistungs-Selbsttest durchführen
spkac SPKAC-Werkzeug
srp SRP-Passwortdatei verwalten
storeutl Url ?
ts TSA Zeitstempel erzeugen
verify Certificate Zertifikat verifizieren
version Version ausgeben
x509 Zertifikat verwalten

Konfigurationsdatei

Direktive Vorgabe Option Beschreibung
[ca]
default_ca Section -name Konfiguration der Zertifizierungsstelle
oid_file File Datei mit Objekt-Identifizierer
oid_section Section Abschnitt mit Objekt-Identifizierern
new_certs_dir Path -outdir Verzeichnis für neue Zertifikate
certificate File -cert Wurzelzertifikat
private_key File -keyfile Schlüssel des Wurzelzertifikats
RANDFILE File Zustand des Zufallszahlengenerators
default_days Number -days Gültigkeitsdauer des Zertifikats
default_startdate Date -startdate Beginn der Gültigkeit
default_enddate Date -enddate Ablauf der Gültigkeit
default_crl_hours Number -crlhours Gültigkeitsdauer der Widerrufsliste
default_crl_days Number -crldays Gültigkeitsdauer der Widerrufsliste
default_md default -md Streufunktion
database File Ausgestellte Zertifikate: index.txt
unique_subject yes Eindeutige Namen forcieren
serial File Seriennummer für Zertifikate
crlnumber File Seriennummer für Widerrufsliste
x509_extensions Section -extensions Erweiterte Attribute des Zertifikats
crl_extensions Section -crlexts Erweiterte Attribute der Widerrufsliste
preserve no -preserveDN Reihenfolge der Attribute beibehalten
email_in_dn no -noemailDN Feld für Elektropost entfernen
policy Section -policy Abschnitt für Pflichtfelder
name_opt default_ca -nameopt Beim Ausstellen anzuzeigende Felder
cert_opt default_ca -certopt Beim Ausstellen anzuzeigende Felder
copy_extensions none Umgang mit angefragten Erweiterungen
[req]
input_password Text -passin Passwort für Schlüssel (lesend)
output_password Text -passout Passwort für Schlüssel (schreibend)
default_bits 2048 -newkey Stärke für RSA-Schlüssel (512–4096)
default_keyfile File -keyout Ausgabedatei für Schlüssel
oid_file File Datei mit Objekt-Identifizierer
oid_section Section Abschnitt mit Objekt-Identifizierern
RANDFILE File Zustand des Zufallszahlengenerators
encrypt_key yes -nodes Schlüssel verschlüsseln
default_md Algorithm -md Streufunktion
string_mask utf8only Erlaubte Zeichenkodierungen
req_extensions Section -reqexts Abschnitt für erweiterte Attribute der Anfrage
x509_extensions Section -extensions Abschnitt für erweiterte Attribute des Zertifikats
prompt Boolean Felder interaktiv abfragen
utf8 no Zeichenkodierung für Felder
attributes Section Dialog für Abfrage der Attribute
distinguished_name Section Dialog für Abfrage der Felder
match Feld muss übereinstimmen
supplied Feld muss vorhanden sein
optional Feld darf fehlen
countryName Länderkennung
stateOrProvinceName Bundesland
localityName Ort
organizationName Firmenname
organizationalUnitName Firmenbereich
commonName Benutzer- oder Hostname
emailAddress Elektropost-Adresse
…{_default,_min,_max} … Vorgabe, Mindest- und Maximallänge

Literatur

  1. Ivan Ristić: OpenSSL Cookbook, Online Version
  2. Thomas Leister: Eine eigene OpenSSL CA erstellen und Zertifikate ausstellen