Aus bekannten Gründen müssen auch X.509-Zertifikate, welche zwischen September 2006 und Mai 2008 auf Debian-Systemen erzeugt wurden, neu generiert werden.
Mit EASY-RSA, einer Sammlung von Scripten aus dem OpenVPN-Paket, oder TinyCA, einem Frontend für OpenSSL, bekommt man zwar relativ leicht seine eigene Zertifikats-Hierarchie aufgebaut. Doch alle mir bekannten OpenSSL-Howtos zur manuellen Vorgehensweise sind eher mittelmäßig, da oft wichtige Details untergehen oder ganz fehlen und die Konfigurationsdateien chaotisch sind. Und über die Man-Pages der OpenSSL-Werkzeuge kann man bestenfalls sagen, dass sie eine gute "Idiotenbremse" sind.
Nicht jede in diesem Howto gezeigte Einstellung ist auch nötig oder hundertprozentig korrekt. Die verwendeten Parameter ermöglichen aber eine schnelle und systematische Erzeugung der Zertifikate, und die Konfigurationsdateien sind lesbar.
< Tesladonnerstag: Shopping mit Hochspannung | gefährliche Angriffsmöglichkeit durch das OpenSSL-Debakel >
Freitag, 23. Mai 2008
eigene X.509-Zertifikats-Hierarchie mit OpenSSL (CA, Client & Server)
Howto: eigene X.509-Zertifikats-Hierarchie mit OpenSSL
Inhalt:
eine Warnung vorab
Vorbereitungen
Erzeugen der Zertifikatsautorität (CA)
Erzeugen eines Server-Zertifikats
Erzeugen eines Client-Zertifikats
abschließende Hinweise
eine Warnung vorab
Auf ausführliche Erklärungen verzichte ich hier. Doch ohne Verständnis von X.509 und PKI handelt man sich schnell komplexe Probleme ein, die je nach Anwendung schwer zu diagnostizieren sind. (ssldump könnte dabei nützlich sein!) Fies wird es, wenn auch noch Bugs hinzukommen, wie dieser hier:
Extensions in certificates are not transferred to certificate requests and vice versa.
Also: Wer einfach loslegt, und das Ergebnis dann in Produktivumgebungen einsetzt, ist doof.
Vorbereitungen
Man benötigt eine sinnvolle Verzeichnisstruktur, z.B. ein Verzeichnis ssl, und darin all, clients, server und CA (für Certificate Authority):
mkdir -p ssl/CA ssl/clients ssl/server ssl/all ssl/clients/pkcs;cd ssl
Alle Aktionen werden im Verzeichnis ssl ausgeführt, alle Konfigurationsdateien dort angelegt. Zunächst einmal müssen die Datei index.txt und eine initiale Seriennummer existieren:
touch index.txt
echo 123456 > serial
Erzeugen der Zertifikatsautorität (CA)
Präzise gesagt, erzeugt man das selbstsignierte Zertifikat und den Schlüssel der Zertifikatsautorität. Eigentlich muss man dies in einer besonders gesicherten Umgebung tun, hierfür gibt es gewisse Richtlinien. Im professionellen Einsatz muss die CA auf einem nicht-netzwerkfähigen, am besten von einem unveränderlichen Datenträger gestarteten, Rechner erzeugt und verwendet werden, zu dem nur besonders befugte Personen Zugang haben, und so weiter.
Man benötigt die Datei ca.cnf, die z.B. so aussehen kann:
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
database = $dir/index.txt
serial = $dir/serial
private_key = $dir/CA/myCA.key
certificate = $dir/CA/myCA.cert
default_days = 1825
default_md = sha1
new_certs_dir = $dir/all
policy = policy_match
certs = $dir/clients
unique_subject = no
name_opt = ca_default
cert_opt = ca_default
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Der Abschnitt [ ca ] enthält Einstellungen, die verwendet werden, wenn
openssl ca
aufgerufen wird. Er verweist auf einen weitergehenden Abschnitt.Dann legt man für den Signing-Request der CA eine Konfigurationsdatei ca_req.cnf an:
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ req ]
default_bits = 512
default_keyfile = myCA.key
string_mask = utf8only
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical,CA:true
keyUsage = cRLSign, keyCertSign
extendedKeyUsage = clientAuth, serverAuth
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = DE
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Germany
localityName = Locality Name (eg, city)
localityName_default = Guntershausen
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Bauna Ltd.
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Security Dept.
commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = Test Certificate Authority
Hier enthält der Abschnitt [ req ] zwei Verweise auf Abschnitte mit weitergehenden Einstellungen. Zu erwähnen sind insbesondere keyUsage und extendedKeyUsage im Abschnitt [ v3_ca ], die die alten Netscape-spezifischen Einstellungen ablösen. Der Abschnitt [ req_distinguished_name ] enthält Standard-Einstellungen, die während der Erzeugung des Requests nochmal abgefragt werden.
Mit den beiden Konfigurationsdateien kann man nun ein selbstsigniertes Zertifikat mit einer Gültigkeitsdauer von fünf Jahren erzeugen:
openssl req -new -x509 -config ca_req.cnf -days 1825 -out CA/myCA.cert -keyout CA/myCA.key
Und mit
openssl x509 -in CA/myCA.cert -noout -text
lässt man sich das Ergebnis in menschenlesbarer Form anzeigen.Soll das CA-Zertifikat von einem Browser importiert werden, so muss man es eventuell ins DER-Format umwandeln, was mit
openssl x509 -outform DER -in CA/myCA.cert -out CA/myCA.der
geht. Der aktuelle Firefox akzeptiert aber auch das cert-File.Die Zertifikatsautorität signiert Server- und Client-Zertifikate. Ist ihr Zertifikat in der Datenbank eines Browsers vorhanden, so akzeptiert dieser SSL-Verbindungen zu Webservern, deren Zertifikat von der CA signiert wurde, ohne Nachfrage. Ein Server hingegen kann mit dem CA-Zertifikat das von einem Client gelieferte prüfen und ggf. den Zugriff verweigern.
Erzeugen eines Server-Zertifikats
Eine Datei server.cnf mit den Einstellungen für den Signing-Request des Servers wird benötigt. Sie gleicht im Aufbau der Request-Konfiguration der CA, enthält aber einen oder mehrere Domainnamen, unter denen der Server zu erreichen ist:
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ req ]
default_bits = 512
default_keyfile = server.pem
string_mask = utf8only
distinguished_name = req_distinguished_name
req_extensions = server_cert
[ server_cert ]
subjectKeyIdentifier = hash
basicConstraints = critical,CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
#Vorsicht mit dem folgenden:
#subjectAltName = DNS:alternative.baunaltd.example,DNS:sec.baunaltd.example
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = DE
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Germany
localityName = Locality Name (eg, city)
localityName_default = Guntershausen
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Bauna Ltd.
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Security Dept.
commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = sec.baunaltd.example
Insbesondere über subjectAltName sollte man nachlesen und sich Gedanken machen, bevor man es verwendet. Damit kann man den Nutzen des Zertifikats sinnvoll ausdehnen — oder aber die Sicherheit komplett aushöhlen. Wer es nicht braucht oder das Risiko nicht kennt, lässt es weg. Dass der "commonName" dort an letzter Stelle wiederholt wird, ist kein Zufall, sondern erhöht die Browserkompatibilität.
Man erzeugt den Request und den privaten Schlüssel mit:
openssl req -new -nodes -config server.cnf -out server/server.csr -keyout server/server.pem
Dann erzeugt man mit der CA aus dem Request das Server-Zertifikat:
openssl ca -config ca.cnf -days 1095 -in server/server.csr -out server/server.cert -extfile server.cnf -extensions server_cert
Die letzten beiden Optionen dieses Aufrufs sorgen dafür, dass die Erweiterungen im Abschnitt [ server_cert ] der Konfigurationsdatei dem Zertifikat hinzugefügt werden. (Es gibt andere Möglichkeiten, die hier aber nicht diskutiert werden.) Dieses Zertifikat kann nun für Mail- oder Webserver verwendet werden. Mit
openssl x509 -in server/server.cert -noout -text
kann man schauen, ob das Ergebnis gefällt.Erzeugen eines Client-Zertifikats
Auch für Clients wird eine Konfigurationsdatei client.cnf mit Einstellungen für den Request angelegt:
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ req ]
default_bits = 512
default_keyfile = client.pem
string_mask = utf8only
distinguished_name = req_distinguished_name
req_extensions = client_cert
[ client_cert ]
subjectKeyIdentifier = hash
basicConstraints = critical,CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = DE
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Germany
localityName = Locality Name (eg, city)
localityName_default = Guntershausen
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Bauna Ltd.
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Security Dept.
commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = Hans Wurst
#emailAddress = Email Address
#emailAddress_max = 64
#emailAddress_default = wurst@baunaltd.example
Das Hinzufügen einer E-Mail-Adresse könnte für S/MIME nützlich sein, dazu ist außerdem emailProtection als zusätzlicher Wert für extendedKeyUsage einzutragen.
Wie beim Server erzeugt man mit
openssl req -new -nodes -config client.cnf -out clients/test.csr -keyout clients/test.pem
den Schlüssel und den Signing Request, und mit der CA das Zertifikat:
openssl ca -config ca.cnf -days 730 -in clients/test.csr -out clients/test.cert -extfile client.cnf -extensions client_cert
Im Unterverzeichnis clients liegt nun die (öffentliche) Zertifikatsdatei test.cert (nebst dem geheimen Schlüssel test.pem), diese kann aber von einem Browser oder E-Mail-Client noch nicht importiert werden. Dazu muss erst eine PKCS#12-Datei erzeugt werden:
openssl pkcs12 -export -clcerts -name "mein Test-Zertifikat" -in clients/test.cert -inkey clients/test.pem -out clients/pkcs/test.p12
Die PKCS#12-Datei enthält auch den privaten Schlüssel und wird deshalb mit einem Passwort geschützt. Allerdings sollte man sich auf diesen Schutz nicht verlassen, sondern Zertifikatsdateien nur auf sicheren Wegen übertragen.
abschließende Hinweise
Die Schlüsselgrößen von nur 512 Bit sind natürlich nur zum Ausprobieren geeignet. Wie groß man die Schlüssel tatsächlich macht, ist eine Frage der Anforderungen an die Sicherheit, der Rechenleistung der Server und Clients, des Vertrauens in OpenSSL und der jeweiligen Gesetzeslage...
Ausschnitt aus XKCDs 1337: Part 3 steht unter cc-by-nc-2.5-Lizenz, siehe http://xkcd.com/license.html.
datenritter blog am : verschlüsselte Mailinglisten mit Mailman-ssls