05.a — Mit OpenSSL eine lokale Zertifizierungsstelle für SSL-Zertifikate einrichten

Zuletzt geändert: 21. Oktober 2020
Geschätzte Lesezeit: 5 min

Sowas hätte ich gerne für meine Entwick­lung­sumge­bung unter OS X, um für die Entwick­lung­sumge­bung mit ihren ver­schiede­nen *.local.web Domains SSL Zer­ti­fikate erstellen zu kön­nen. Ausser­dem ist es mal span­nend zu sehen wie so eine CA aufge­baut wird.

Als Zer­ti­fizierungsstelle (CA) zu fungieren bedeutet, mit kryp­tographis­chen Paaren aus pri­vat­en Schlüs­seln und öffentlichen Zer­ti­fikat­en umzuge­hen. Das allererste kryp­tographis­che Paar, das ich erstelle, ist das Root-Paar. Dieses beste­ht aus dem Wurzelschlüs­sel (ca.key.pem) und dem Wurzelz­er­ti­fikat (ca.cert.pem). Dieses Paar bildet die Iden­tität der CA.

Nor­maler­weise sig­niert die Root-CA Serv­er- oder Client-Zer­ti­fikate nicht direkt. Die Root-CA wird immer nur dazu ver­wen­det, eine oder mehrere Zwis­chen-CAs zu erstellen, denen die Root-CA ver­traut, Zer­ti­fikate in ihrem Namen zu sig­nieren. Dies ist die beste Prax­is. Das ermöglicht, den Root-Schlüs­sel offline und so weit wie möglich unbe­nutzt zu hal­ten, da jede Kom­pro­mit­tierung des Root-Schlüs­sels katas­trophal ist.

Es ist bewährte Prax­is, das Wurzel­paar in ein­er sicheren Umge­bung zu erstellen. Ide­al­er­weise sollte das auf einem voll­ständig ver­schlüs­sel­ten Com­put­er geschehen, der per­ma­nent vom Inter­net getren­nt ist. Ent­ferne die Wire­less-Karte und fülle den Eth­er­net-Anschluss mit Kleb­stoff!

Arbeitsverzeichnis erstellen

…und darin eine Zer­ti­fizierungsstelle und ein Sternz­er­ti­fikat erstellen.

mkdir -p /usr/local/opt/ca cd /usr/local/opt/ca mkdir -p certs crl newcerts private chmod 700 private mkdir -p intermediate/certs intermediate/crl intermediate/newcerts intermediate/private intermediate/csr

 Einige weit­ere Dateien erstellen, die OpenSSL zur Erstel­lung von Zer­ti­fikat­en benötigt.

touch index.txt echo 1000 > serial touch intermediate/index.txt echo 1000 > intermediate/serial

OpenSSL-Konfiguration erstellen

Eine benutzerdefinierte OpenSSL-Kon­fig­u­ra­tion (openssl.cnf) erstellen, die für die Erstel­lung ein­er Zer­ti­fizierungsstelle (Root-SSL-Zer­ti­fikat) geeignet ist.

  1. Der Abschnitt [ ca ] ist oblig­a­torisch. Hier weisen wir OpenSSL an, die Optio­nen aus der Sek­tion [ CA_default ] zu ver­wen­den.
  2. Der Abschnitt [ CA_default ] enthält eine Rei­he von Stan­dard­e­in­stel­lun­gen. Stelle sich­er, dass du das Verze­ich­nis deklar­i­erst, das du zuvor gewählt hast (/usr/local/opt/ca).
  3. Wende policy_strict für alle Root-CA-Sig­na­turen an, da die Root-CA nur zur Erstel­lung von Zwis­chen-CAs ver­wen­det wird.
  4. Wende policy_loose für alle Zwis­chen-CA-Sig­na­turen an, da die Zwis­chen-CA Serv­er- und Client-Zer­ti­fikate sig­niert, die von ein­er Vielzahl von Drit­tan­bi­etern stam­men kön­nen.
  5. Optio­nen aus dem Abschnitt [ req ] wer­den bei der Erstel­lung von Zer­ti­fikat­en oder Zer­ti­fikatssig­nierungsan­forderun­gen angewen­det.
  6. Der Abschnitt [ req_distinguished_name ] deklar­i­ert die Infor­ma­tio­nen, die nor­maler­weise in ein­er Zer­ti­fikat­sun­terze­ich­nungsan­forderung erforder­lich sind. Gib option­al einige Stan­dard­w­erte an.
  7. Die näch­sten Abschnitte sind Erweiterun­gen, die beim Sig­nieren von Zer­ti­fikat­en angewen­det wer­den kön­nen. Wenn du beispiel­sweise das Befehlszeile­nar­gu­ment -extensions v3_ca übergib­st, wer­den die in [ v3_ca ] fest­gelegten Optio­nen angewen­det. Ich wende die Erweiterung v3_ca an, wenn ich das Stam­mz­er­ti­fikat erstelle.
  8. Ich wende die Erweiterung v3_ca_intermediate an, wenn ich das Zwis­chen­z­er­ti­fikat erstelle. pathlen:0 stellt sich­er, dass es keine weit­eren Zer­ti­fizierungsstellen unter­halb der Zwis­chen-CA geben kann.
  9. Ich wende die Erweiterung usr_cert an, wenn ich Client-Zer­ti­fikate sig­niere, wie sie z.B. für die Remote-Benutzer­authen­tifizierung ver­wen­det wer­den.
  10. Ich wende die Erweiterung server_cert beim Sig­nieren von Serv­er-Zer­ti­fikat­en, wie sie beispiel­sweise für Web­serv­er ver­wen­det wer­den, an.
  11. Die Erweiterung crl_ext wird bei der Erstel­lung von Zer­ti­fikatswider­ruf­s­lis­ten automa­tisch angewen­det.
  12. Ich wende die ocsp — Erweiterung bei der Unterze­ich­nung des OCSP-Zer­ti­fikats (Online Cer­tifi­cate Sta­tus Pro­to­col) an.
cat << 'EOL' > openssl.cnf # OpenSSL root CA configuration file. # Copy to `/usr/local/opt/ca/openssl.cnf`. # # This file is based on the instructions found in https://jamielinux.com/docs/openssl-certificate-authority/index.html [ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = /usr/local/opt/ca certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/index.txt serial = $dir/serial RANDFILE = $dir/private/.rand # The root key and root certificate. private_key = $dir/private/ca.key.pem certificate = $dir/certs/ca.cert.pem # For certificate revocation lists. crlnumber = $dir/crlnumber crl = $dir/crl/ca.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 name_opt = ca_default cert_opt = ca_default default_days = 375 preserve = no policy = policy_strict [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. x509_extensions = v3_ca [ req_distinguished_name ] # See . countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address # Optionally, specify some defaults. countryName_default = DE stateOrProvinceName_default = NRW localityName_default = Bergisch Gladbach 0.organizationName_default = Carsten Nichte organizationalUnitName_default = Software-Entwicklung emailAddress_default = mail@adresse.de [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth crlDistributionPoints = URI:http://www.local.web/intermediate.crl.pem [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning [ san_env ] subjectAltName=DNS:local.web,DNS:*.local.web EOL

Zertifizierungsstelle schaffen

Alle Zer­ti­fikate wer­den mit einem Pass­wort ver­schlüs­selt. Ich set­ze hier 123456 ein. Hier bitte ein eigenes nehmen und merken.

export CERTIFICATE_PASSWORD=123456 brew install openssl export PATH=$(brew --prefix openssl):$PATH cd /usr/local/opt/ca

Einen pri­vat­en Schlüs­sel erzeu­gen

openssl genrsa -aes256 -passout pass:$CERTIFICATE_PASSWORD -out private/ca.key.pem 4096

Wichtig: Ein Back­up des pri­vat­en Schlüs­sels machen (und gut sich­ern, zB. auf einem USB-Stick). Wenn der ver­loren geht, ist das SSL-Zer­ti­fikat wert­los.

Einen Cer­tifi­cate Sign­ing Request (CSR) erzeu­gen:

openssl req -config openssl.cnf \ -key private/ca.key.pem -passin pass:$CERTIFICATE_PASSWORD \ -new -x509 -days 7300 -sha256 -extensions v3_ca \ -subj "/CN=macOS Dev Box Root CA/O=Carsten Nichte/OU=Software-Entwicklung/C=CY/ST=NRW/L=Bergisch Gladbach" \ -out certs/ca.cert.pem

Zwischenzertifizierungsstelle einrichten

Jet­zt das selbe nochmal für die Zwis­chen­stelle:

cat << 'EOL' > intermediate/openssl.cnf # OpenSSL root CA configuration file. # # This file is based on the instructions found in https://jamielinux.com/docs/openssl-certificate-authority/index.html [ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = /usr/local/opt/ca/intermediate certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/index.txt serial = $dir/serial RANDFILE = $dir/private/.rand # The root key and root certificate. private_key = $dir/private/intermediate.key.pem certificate = $dir/certs/intermediate.cert.pem # For certificate revocation lists. crlnumber = $dir/crlnumber crl = $dir/crl/intermediate.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 name_opt = ca_default cert_opt = ca_default default_days = 375 preserve = no policy = policy_loose [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. x509_extensions = v3_ca [ req_distinguished_name ] # See . countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address # Optionally, specify some defaults. countryName_default = DE stateOrProvinceName_default = NRW localityName_default = Bergisch Gladbach 0.organizationName_default = Carsten Nichte organizationalUnitName_default = Software-Entwicklung emailAddress_default = mail@adresse.de [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning [ san_env ] subjectAltName=DNS:local.web,DNS:*.local.web EOL
cd /usr/local/opt/ca openssl genrsa -aes256 \ -passout pass:$CERTIFICATE_PASSWORD \ -out intermediate/private/intermediate.key.pem 4096
openssl req -config intermediate/openssl.cnf -new -sha256 \ -key intermediate/private/intermediate.key.pem \ -passin pass:$CERTIFICATE_PASSWORD \ -subj "/CN=macOS Dev Box Intermediate CA/O=Carsten Nichte/OU=Software-Entwicklung/C=CY/ST=NRW/L=Bergisch Gladbach" \ -out intermediate/csr/intermediate.csr.pem
openssl ca -config openssl.cnf -extensions v3_intermediate_ca -batch \ -passin pass:abakus \ -days 3650 -notext -md sha256 \ -in intermediate/csr/intermediate.csr.pem \ -out intermediate/certs/intermediate.cert.pem
cat intermediate/certs/intermediate.cert.pem \ certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem

SSL-Zertifikat für den Entwicklungsserver erstellen

…und alles, nach /usr/local/etc/httpd/ssl kopieren.

cd /usr/local/opt/ca
openssl genrsa -aes256 \ -passout pass:$CERTIFICATE_PASSWORD \ -out intermediate/private/local.web.key.pem 2048
openssl req -config /usr/local/opt/ca/intermediate/openssl.cnf \ -key intermediate/private/local.web.key.pem \ -extensions san_env \ -passin pass:$CERTIFICATE_PASSWORD \ -subj "/CN=*.local.web/O=Carsten Nichte/OU=Software-Entwicklung/C=CY/ST=NRW/L=Bergisch Gladbach" \ -new -sha256 -out intermediate/csr/local.web.csr.pem
openssl ca -config intermediate/openssl.cnf -batch \ -extensions server_cert -extensions san_env \ -days 1835 -notext -md sha256 \ -in intermediate/csr/local.web.csr.pem \ -passin pass:$CERTIFICATE_PASSWORD \ -out intermediate/certs/local.web.cert.pem

Hier stecke ich momen­tan fest, es gibt ne unschöne Fehler­mel­dung in der Art: unable to load cer­ti­fi­cat, … , Expect­ing: TRUSTED CERTIFICATE

mkdir /usr/local/etc/httpd/ssl cp intermediate/certs/ca-chain.cert.pem /usr/local/etc/httpd/ssl
openssl rsa -in intermediate/private/local.web.key.pem \ -out /usr/local/etc/httpd/ssl/local.web.key \ -passin pass:$CERTIFICATE_PASSWORD
cp intermediate/certs/local.web.cert.pem /usr/local/etc/httpd/ssl/local.web.crt

SSL-Unterstützung im Apache aktivieren

codi­um /usr/local/etc/httpd/httpd.conf

Finde Zeile

Listen 80

Eine weit­ere Zeile hinzufü­gen, damit Apache auch auf dem Stan­dard-HTTPS-Port, lauscht (443).

Listen 80 Listen 443

HTTPS-Unter­stützung im Apache aktivieren. Die fol­gen­den Zeilen suchen und das # davor ent­fer­nen.

#LoadModule ssl_module lib/httpd/modules/mod_ssl.so #LoadModule http2_module lib/httpd/modules/mod_http2.so

Wird fort­ge­set­zt.…

War der Artikel hilfreich?
Nich so 0 0 von 0 fanden den Artikel hilfreich.
Ansichten: 24
Vorheriger Artikel: 05 — Apache
Nächster Artikel: 06 — PHP