OpenSSL

Siehe auch

Verwandte Artikel

Der Parameter -nodes steht für „No DES“ und erstellt Keys ohne Passwörter (Keys sind also nicht encrypted). Seit OpenSSL 3.0 (RHEL 9+) ist -nodes zugunsten von -noenc deprecated, funktioniert aber weiterhin.

Warnung

Das auf RHEL 7 vorhandene Shell-Script /etc/pki/tls/certs/make-dummy-cert erstellt Zertifikate mit X509v3 Basic Constraints: CA:TRUE Extension, also ein CA-Zertifikat. CA-Zertifikate lassen sich in Apache nicht (mehr) als Zertifikat für einen Virtual Host nutzen, der Apache bricht dann je nach Version den Reload mit SSL-Fehlern ab (AH01906: localhost:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)).

Diese Art Zertifikate entstehen, wenn folgende Parameter verwendet werden:

openssl req \
    -days 365 \
    -keyout /etc/pki/tls/private/test.key \
    -newkey rsa:2048 \
    -nodes \
    -out /etc/pki/tls/certs/test.pem \
    -x509

(sehr viele Anleitungen im Internet nutzen OpenSSL genau so). Unsere Anleitung unten zeigt, wie man „echte“ self-signed Server-Zertifikate erzeugt.

DH Key erstellen

Wird für diverse Software wie OpenVPN & Co. benötigt. DH-Schlüssel werden zur Secret-Aushandlung über eine unsichere Verbindung verwendet, und können und sollten beispielsweise 1x pro Monat automatisch neu generiert werden.

openssl dhparam -out dh4096.pem 4096

openssl.cnf

Beispiel:

openssl.cnf
[ CA_default ]
dir              = /etc/pki/CA
certs            = $dir/certs
crl_dir          = $dir/crl
new_certs_dir    = $dir/newcerts
database         = $dir/index.txt
serial           = $dir/serial
crlnumber        = $dir/crlnumber
crl              = $dir/crl.pem
default_crl_days = 30
default_md       = sha384
policy           = policy_any
x509_extensions  = v3_server

[ policy_any ]
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional

[ crl_ext ]
authorityKeyIdentifier = keyid:always

[ req ]
default_bits       = 4096
default_md         = sha384
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName                    = Country Name (2 letter code)
countryName_default            = CH
stateOrProvinceName            = State or Province Name (full name)
stateOrProvinceName_default    = Zurich
localityName                   = Locality Name (eg, city)
localityName_default           = Zurich
organizationName               = Organization Name (eg, company)
organizationName_default       = Linuxfabrik
organizationalUnitName         = Organizational Unit Name (eg, section)
organizationalUnitName_default = IT
commonName                     = Common Name (e.g. server FQDN)
commonName_default             = server.example.com

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

[ v3_server ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints       = critical, CA:false
keyUsage               = critical, digitalSignature, keyEncipherment
extendedKeyUsage       = serverAuth
subjectAltName         = @alt_names

[ alt_names ]
# must match the commonName above; add further names as DNS.2, DNS.3, ...
DNS.1 = server.example.com

Die Abschnitte [ v3_ca ] und [ v3_server ] definieren die Extensions für das CA- bzw. das Server-Zertifikat. Der subjectAltName (SAN) im Abschnitt [ alt_names ] ist Pflicht: Moderne Clients (Browser, Java-Anwendungen usw.) ignorieren den Common Name und prüfen ausschliesslich den SAN.

Die Beispiele unten übergeben den DN direkt via -subj und vermeiden so die interaktive Abfrage. Wird -subj weggelassen, fragt OpenSSL die Felder anhand der _default-Werte interaktiv ab. Für einen rein dateibasierten Ablauf (z.B. zur Automatisierung) im Abschnitt [ req ] zusätzlich prompt = no setzen und die Werte fest hinterlegen:

openssl.cnf
[ req ]
default_bits       = 4096
default_md         = sha384
distinguished_name = dn
prompt             = no
utf8               = yes

[ dn ]
C  = CH
ST = Zurich
L  = Zurich
O  = Linuxfabrik
OU = IT
CN = server.example.com

Der subjectAltName lässt sich nicht über -subj setzen und muss in jedem Fall im Abschnitt [ alt_names ] gepflegt werden.

Self-signed root-Zertifikat (CA Certificate) erstellen

Das hier erstellte CA-Zertifikat gilt 5 Jahre (1825 days). Die Extensions stammen aus dem Abschnitt [ v3_ca ], der Common Name wird via -subj gesetzt und sollte sich vom späteren Server-Zertifikat unterscheiden.

openssl req \
    -config openssl.cnf \
    -days 1825 \
    -extensions v3_ca \
    -keyout /etc/pki/tls/private/rootCA.key \
    -newkey rsa:4096 \
    -nodes \
    -out /etc/pki/tls/certs/rootCA.pem \
    -sha384 \
    -subj "/C=CH/ST=Zurich/O=Linuxfabrik/CN=Linuxfabrik Internal CA" \
    -utf8 \
    -x509

chmod 0400 /etc/pki/tls/private/rootCA.key
chown root:root /etc/pki/tls/private/rootCA.key

Self-Signed Zertifikat erstellen

Self-Signed Zertifikat erstellen, und von eigener CA signieren lassen.

Das Zertifikat kommt ohne Passwort daher, sinnvoll z.B. für einen Web- oder DB-Server.

1.) Private Key (RSA 4096 bit) und CSR erstellen. Zuvor in der openssl.cnf im Abschnitt [ alt_names ] den DNS.1-Eintrag (und bei Bedarf weitere) auf den FQDN des Servers setzen:

SERVERNAME='server.example.com'
SUBJECT="/C=CH/ST=Zurich/O=Linuxfabrik/CN=$SERVERNAME"

openssl req \
    -config openssl.cnf \
    -keyout /etc/pki/tls/private/$SERVERNAME.key \
    -new \
    -newkey rsa:4096 \
    -nodes \
    -out $SERVERNAME.csr \
    -sha384 \
    -subj "$SUBJECT" \
    -utf8

chmod 0400 /etc/pki/tls/private/$SERVERNAME.key
chown root:root /etc/pki/tls/private/$SERVERNAME.key

2.) Zertifikat mit 90 Tagen Laufzeit von der eigenen CA signieren lassen. Wichtig: -extfile und -extensions v3_server übernehmen die Extensions (allen voran den subjectAltName) ins Zertifikat. Ohne sie entsteht ein Zertifikat ohne SAN, das moderne Clients ablehnen:

openssl x509 \
    -CA /etc/pki/tls/certs/rootCA.pem \
    -CAcreateserial \
    -CAkey /etc/pki/tls/private/rootCA.key \
    -days 90 \
    -extensions v3_server \
    -extfile openssl.cnf \
    -in $SERVERNAME.csr \
    -out /etc/pki/tls/certs/$SERVERNAME.pem \
    -req \
    -sha384

Zertifikate überprüfen/ansehen

CA(-Chain) überprüfen:

CAFILE=/path/to/chain.pem

openssl verify $CAFILE

Zertifikat gegen die eigene CA prüfen:

openssl verify \
    -CAfile /etc/pki/tls/certs/rootCA.pem \
    /etc/pki/tls/certs/server.example.com.pem

Zertifikat überprüfen:

CERT=/path/to/mycert.pem

openssl x509 \
    -in $CERT \
    -noout \
    -text

Private Key überprüfen:

PRIVKEY=/path/to/priv.key

openssl rsa \
    -check \
    -in $PRIVKEY

CSR überprüfen:

CERT=/path/to/mycert.pem

openssl req \
    -in $CERT \
    -nameopt sep_multiline \
    -noout \
    -verify

PKCS12-Zertifikat überprüfen:

CERT=/path/to/mycert.pfx

openssl pkcs12 \
    -in $CERT \
    -info \
    -nodes

Zertifikate umwandeln

PEM-Zertifikat mit Key in ein PKCS#12 (.pfx) ohne Passwort umwandeln:

openssl pkcs12 \
    -certfile /etc/pki/tls/certs/rootCA.pem \
    -export \
    -in /etc/pki/tls/certs/$SERVERNAME.pem \
    -inkey /etc/pki/tls/private/$SERVERNAME.key \
    -out /etc/pki/tls/private/$SERVERNAME.pfx \
    -passin pass: \
    -passout pass:

PKCS#12 (.pfx) in PEM-Format exportieren:

openssl pkcs12 \
    -in /etc/pki/tls/private/$SERVERNAME.pfx \
    -info \
    -nodes

# if you get errors like "Error outputting keys and certificates, envelope default library context, Algorithm (RC2-40-CBC : 0), Properties ()"
openssl pkcs12 \
    -in /etc/pki/tls/private/$SERVERNAME.pfx \
    -info \
    -legacy \
    -nodes

PEM-Key in das PKCS#8-Format umwandeln (wird von Java-basierter Software wie Graylog, Elasticsearch oder Kafka benötigt):

openssl pkcs8 \
    -in /etc/pki/tls/private/$SERVERNAME.key \
    -nocrypt \
    -out /etc/pki/tls/private/$SERVERNAME.pkcs8.key \
    -topk8

CRL ausstellen

openssl ca \
    -gencrl \
    -out crl.pem \
    -utf8