FreeBSD Certificate Authority

Lizenz: Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)

Verfasser: Markus Kohlmeyer | Letzte Aktualisierung: | Veröffentlicht:

Beitragende: Stefan H. Holek

Einleitung

Dieses HowTo setzt ein wie in FreeBSD Remote Installation beschriebenes, installiertes und konfiguriertes FreeBSD Basissystem und OpenSSL 1.0.2 (oder neuer) aus den FreeBSD Ports voraus.

Folgende Punkte sind in diesem HowTo zu beachten.

  • Alle Konfigurationen sind selbstständig auf notwendige individuelle Anpassungen zu kontrollieren.
  • Die Domain des Servers lautet example.com und ist selbstständig durch die eigene Domain zu ersetzen.
  • Der Hostname des Servers lautet devnull und ist selbstständig durch den eigenen Hostnamen zu ersetzen (FQDN=devnull.example.com).
  • Es werden die FQDNs devnull.example.com, mail.example.com, pki.example.com und www.example.com verwendet und sind selbstständig im DNS zu registrieren.

Vorbereitungen

Verzeichnisstruktur anlegen und RANDFILE sowie EC-Params und DH-Params erzeugen.

/bin/mkdir -p /data/pki/{ca,certs,crl,etc,newcerts,private,revoked}
/bin/chmod 0700 /data/pki/private
/usr/bin/openssl rand -out /data/pki/private/.rand 65536

/usr/bin/openssl genpkey -genparam -algorithm DH -pkeyopt 'dh_paramgen_prime_len:2048' -out /data/pki/certs/dh_params.pem
/usr/bin/openssl genpkey -genparam -algorithm EC -pkeyopt 'ec_paramgen_curve:secp384r1' -out /data/pki/certs/ec_params.pem

OpenSSL

OpenSSL konfigurieren

Sofern noch nicht während der FreeBSD Remote Installation erledigt, müssen folgende Optionen in der /etc/ssl/openssl.cnf im Abschnitt [ req_distinguished_name ] angepasst beziehungsweise ergänzt werden.

countryName_default             = DE
stateOrProvinceName_default     = Bundesland
localityName_default            = Ort
0.organizationName_default      = Example Corporation
organizationalUnitName_default  = Certification Authority
emailAddress_default            = admin@example.com

Folgende Optionen müssen im Abschnitt [ CA_default ] angepasst werden.

default_days            = 730
default_md              = sha384

Folgende Optionen müssen im Abschnitt [ req ] angepasst werden.

default_bits            = 2048
string_mask             = utf8only

OpenSSL CA

Root CA erstellen

In der etc/root-ca.conf müssen noch ein paar Anpassungen vorgenommen werden:

  1. Im Abschnitt [ default ] muss die Option base_url auf den URL gesetzt werden, unter dem später die Certs, CRLs und Chains veröffentlicht werden sollen.
  2. Im Abschnitt [ ca_dn ] muss die Option countryName auf das internationale zweibuchstabige Länderkürzel des Betreibers der Root CA gesetzt werden.
  3. Im Abschnitt [ ca_dn ] muss die Option organizationName auf den Firmennamen des Betreibers der Root CA gesetzt werden.
  4. Im Abschnitt [ ca_dn ] muss die Option organizationalUnitName auf den zuständigen Abteilungsnamen des Betreibers der Root CA gesetzt werden.
  5. Im Abschnitt [ ca_dn ] muss die Option commonName auf den Namen der Root CA (im Regelfall "Firmenname Root CA") gesetzt werden.
  6. Im Abschnitt [ additional_oids ] müssen die OIDs entsprechend der eigenen registrierten OIDs ersetzt werden.
cd /data/pki

/bin/cat > etc/root-ca.conf << "EOF"
#
# Example Corporation Root CA
#

[ default ]
ca                              = root-ca
base_url                        = http://pki.example.com
aia_url                         = $base_url/$ca.cer
crl_url                         = $base_url/$ca.crl
name_opt                        = multiline,-esc_msb,utf8
openssl_conf                    = openssl_init

[ ca ]
default_ca                      = root_ca

[ root_ca ]
dir                             = .
certs                           = $dir/ca/$ca/certs
crl_dir                         = $dir/ca/$ca/crl
database                        = $dir/ca/$ca/index.txt
new_certs_dir                   = $dir/ca/$ca/newcerts
certificate                     = $dir/ca/$ca/cacert.pem
serial                          = $dir/ca/$ca/serial
crlnumber                       = $dir/ca/$ca/crlnumber
crl                             = $dir/ca/$ca/crl.pem
private_key                     = $dir/ca/$ca/private/cakey.pem
RANDFILE                        = $dir/ca/$ca/private/.rand
unique_subject                  = no
default_days                    = 1826
default_md                      = sha384
digests                         = sha384
policy                          = match_pol
email_in_dn                     = no
preserve                        = no
name_opt                        = $name_opt
cert_opt                        = ca_default
copy_extensions                 = none
x509_extensions                 = intermediate_ca_ext
default_crl_days                = 30
crl_extensions                  = crl_ext

[ match_pol ]
countryName                 = match
stateOrProvinceName         = optional
localityName                = optional
organizationName            = match
organizationalUnitName      = optional
commonName                  = supplied

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

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = ca_dn
req_extensions              = ca_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = no
SET-ex3                     = SET extension number 3

[ ca_dn ]
countryName                 = "DE"
organizationName            = "Example Corporation"
organizationalUnitName      = "Certification Authority"
commonName                  = "Example Corporation Root CA"

[ ca_reqext ]
basicConstraints            = critical, CA:TRUE
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash

[ root_ca_ext ]
basicConstraints            = critical, CA:TRUE
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always

[ intermediate_ca_ext ]
basicConstraints            = critical, CA:TRUE
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssurance, mediumAssuranceDevice

[ crl_ext ]
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info

[ issuer_info ]
caIssuers;URI.0             = $aia_url

[ crl_info ]
URI.0                       = $crl_url

[ openssl_init ]
oid_section                 = additional_oids

[ additional_oids ]
mediumAssurance             = Medium Assurance, 1.3.6.1.4.1.0.1.7.8
mediumAssuranceDevice       = Medium Device Assurance, 1.3.6.1.4.1.0.1.7.9
"EOF"

Verzeichnisstruktur anlegen, RANDFILE erzeugen, zufälligen Startwert für die späteren Serialnummern festlegen und Indexfile anlegen.

/bin/mkdir -p ca/root-ca/{certs,crl,newcerts,private,revoked}
/bin/chmod 0700 ca/root-ca/private
/usr/bin/openssl rand -out ca/root-ca/private/.rand 65536
/bin/echo `/usr/bin/openssl rand -hex 8 | /usr/bin/tr '[[:lower:]]' '[[:upper:]]'` > ca/root-ca/serial
/bin/cp ca/root-ca/serial ca/root-ca/crlnumber
/usr/bin/touch ca/root-ca/index.txt ca/root-ca/index.txt.attr

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > ca/root-ca/private/root-ca.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out ca/root-ca/private/cakey.pem \
    -pass file:ca/root-ca/private/root-ca.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/root-ca.conf \
    -new \
    -out ca/root-ca/careq.pem \
    -key ca/root-ca/private/cakey.pem \
    -passin file:ca/root-ca/private/root-ca.pwd

Durch die Root CA selbstsigniertes Zertifikat für die Root CA erzeugen. Die Gültigkeitsdauer wird auf 5 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/root-ca.conf \
    -batch \
    -selfsign \
    -in ca/root-ca/careq.pem \
    -out ca/root-ca/cacert.pem \
    -extensions root_ca_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+5y '+%Y%m01000000Z'` \
    -passin file:ca/root-ca/private/root-ca.pwd

Initiale CRL der Root CA erzeugen.

/usr/bin/openssl ca \
    -config etc/root-ca.conf \
    -gencrl \
    -out ca/root-ca/crl.pem \
    -passin file:ca/root-ca/private/root-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl x509 \
    -in ca/root-ca/cacert.pem \
    -out ca/root-ca.cer \
    -outform DER

CRL in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl \
    -in ca/root-ca/crl.pem \
    -out ca/root-ca.crl \
    -outform DER

Network / Intermediate CA erstellen

In der etc/network-ca.conf müssen noch ein paar Anpassungen vorgenommen werden:

  1. Im Abschnitt [ default ] muss die Option base_url auf den URL gesetzt werden, unter dem später die Certs, CRLs und Chains veröffentlicht werden sollen.
  2. Im Abschnitt [ ca_dn ] muss die Option countryName auf das internationale zweibuchstabige Länderkürzel des Betreibers der Network CA gesetzt werden.
  3. Im Abschnitt [ ca_dn ] muss die Option organizationName auf den Firmennamen des Betreibers der Network CA gesetzt werden.
  4. Im Abschnitt [ ca_dn ] muss die Option organizationalUnitName auf den zuständigen Abteilungsnamen des Betreibers der Network CA gesetzt werden.
  5. Im Abschnitt [ ca_dn ] muss die Option commonName auf den Namen der Network CA (im Regelfall "Firmenname Network CA") gesetzt werden.
  6. Im Abschnitt [ additional_oids ] müssen die OIDs entsprechend der eigenen registrierten OIDs ersetzt werden.
cd /data/pki

/bin/cat > etc/network-ca.conf << "EOF"
#
# Example Corporation Network CA
#

[ default ]
ca                              = network-ca
base_url                        = http://pki.example.com
aia_url                         = $base_url/$ca.cer
crl_url                         = $base_url/$ca.crl
name_opt                        = multiline,-esc_msb,utf8
openssl_conf                    = openssl_init

[ ca ]
default_ca                      = network_ca

[ network_ca ]
dir                             = .
certs                           = $dir/ca/$ca/certs
crl_dir                         = $dir/ca/$ca/crl
database                        = $dir/ca/$ca/index.txt
new_certs_dir                   = $dir/ca/$ca/newcerts
certificate                     = $dir/ca/$ca/cacert.pem
serial                          = $dir/ca/$ca/serial
crlnumber                       = $dir/ca/$ca/crlnumber
crl                             = $dir/ca/$ca/crl.pem
private_key                     = $dir/ca/$ca/private/cakey.pem
RANDFILE                        = $dir/ca/$ca/private/.rand
unique_subject                  = no
default_days                    = 1826
default_md                      = sha384
digests                         = sha384
policy                          = match_pol
email_in_dn                     = no
preserve                        = no
name_opt                        = $name_opt
cert_opt                        = ca_default
copy_extensions                 = none
x509_extensions                 = signing_ca_ext
default_crl_days                = 30
crl_extensions                  = crl_ext

[ match_pol ]
countryName                 = match
stateOrProvinceName         = optional
localityName                = optional
organizationName            = match
organizationalUnitName      = optional
commonName                  = supplied

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

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = ca_dn
req_extensions              = ca_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = no
SET-ex3                     = SET extension number 3

[ ca_dn ]
countryName                 = "DE"
organizationName            = "Example Corporation"
organizationalUnitName      = "Certification Authority"
commonName                  = "Example Corporation Network CA"

[ ca_reqext ]
basicConstraints            = critical, CA:TRUE
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash

[ intermediate_ca_ext ]
basicConstraints            = critical, CA:TRUE
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssurance, mediumAssuranceDevice

[ signing_ca_ext ]
basicConstraints            = critical, CA:TRUE, pathLen:0
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssurance, mediumAssuranceDevice

[ crl_ext ]
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info

[ issuer_info ]
caIssuers;URI.0             = $aia_url

[ crl_info ]
URI.0                       = $crl_url

[ openssl_init ]
oid_section                 = additional_oids

[ additional_oids ]
mediumAssurance             = Medium Assurance, 1.3.6.1.4.1.0.1.7.8
mediumAssuranceDevice       = Medium Device Assurance, 1.3.6.1.4.1.0.1.7.9
"EOF"

Verzeichnisstruktur anlegen, RANDFILE erzeugen, zufälligen Startwert für die späteren Serialnummern festlegen und Indexfile anlegen.

/bin/mkdir -p ca/network-ca/{certs,crl,newcerts,private,revoked}
/bin/chmod 0700 ca/network-ca/private
/usr/bin/openssl rand -out ca/network-ca/private/.rand 65536
/bin/echo `/usr/bin/openssl rand -hex 8 | /usr/bin/tr '[[:lower:]]' '[[:upper:]]'` > ca/network-ca/serial
/bin/cp ca/network-ca/serial ca/network-ca/crlnumber
/usr/bin/touch ca/network-ca/index.txt ca/network-ca/index.txt.attr

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > ca/network-ca/private/network-ca.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out ca/network-ca/private/cakey.pem \
    -pass file:ca/network-ca/private/network-ca.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/network-ca.conf \
    -new \
    -out ca/network-ca/careq.pem \
    -key ca/network-ca/private/cakey.pem \
    -passin file:ca/network-ca/private/network-ca.pwd

Durch die Root CA signiertes Zertifikat für die Network CA erzeugen. Die Gültigkeitsdauer wird auf 5 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/root-ca.conf \
    -batch \
    -in ca/network-ca/careq.pem \
    -out ca/network-ca/cacert.pem \
    -extensions intermediate_ca_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+5y '+%Y%m01000000Z'` \
    -passin file:ca/root-ca/private/root-ca.pwd

Initiale CRL der Network CA erzeugen.

/usr/bin/openssl ca \
    -config etc/network-ca.conf \
    -gencrl \
    -out ca/network-ca/crl.pem \
    -passin file:ca/network-ca/private/network-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl x509 \
    -in ca/network-ca/cacert.pem \
    -out ca/network-ca.cer \
    -outform DER

CRL in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl \
    -in ca/network-ca/crl.pem \
    -out ca/network-ca.crl \
    -outform DER

Chain der Network CA erzeugen.

/bin/cat ca/network-ca/crl.pem ca/root-ca/crl.pem > ca/network-ca-crl-chain.pem
/bin/cat ca/network-ca/cacert.pem ca/root-ca/cacert.pem > ca/network-ca-chain.pem

Chain der Network CA in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl2pkcs7 \
    -nocrl \
    -certfile ca/network-ca-chain.pem \
    -out ca/network-ca-chain.p7c \
    -outform DER

Identity Signing CA erstellen

In der etc/identity-ca.conf müssen noch ein paar Anpassungen vorgenommen werden:

  1. Im Abschnitt [ default ] muss die Option base_url auf den URL gesetzt werden, unter dem später die Certs, CRLs und Chains veröffentlicht werden sollen.
  2. Im Abschnitt [ ca_dn ] muss die Option countryName auf das internationale zweibuchstabige Länderkürzel des Betreibers der Identity CA gesetzt werden.
  3. Im Abschnitt [ ca_dn ] muss die Option organizationName auf den Firmennamen des Betreibers der Identity CA gesetzt werden.
  4. Im Abschnitt [ ca_dn ] muss die Option organizationalUnitName auf den zuständigen Abteilungsnamen des Betreibers der Identity CA gesetzt werden.
  5. Im Abschnitt [ ca_dn ] muss die Option commonName auf den Namen der Identity CA (im Regelfall "Firmenname Identity CA") gesetzt werden.
  6. Im Abschnitt [ additional_oids ] müssen die OIDs entsprechend der eigenen registrierten OIDs ersetzt werden.
cd /data/pki

/bin/cat > etc/identity-ca.conf << "EOF"
#
# Example Corporation Identity CA
#

[ default ]
ca                              = identity-ca
base_url                        = http://pki.example.com
aia_url                         = $base_url/$ca.cer
crl_url                         = $base_url/$ca.crl
name_opt                        = multiline,-esc_msb,utf8
openssl_conf                    = openssl_init

[ ca ]
default_ca                      = identity_ca

[ identity_ca ]
dir                             = .
certs                           = $dir/ca/$ca/certs
crl_dir                         = $dir/ca/$ca/crl
database                        = $dir/ca/$ca/index.txt
new_certs_dir                   = $dir/ca/$ca/newcerts
certificate                     = $dir/ca/$ca/cacert.pem
serial                          = $dir/ca/$ca/serial
crlnumber                       = $dir/ca/$ca/crlnumber
crl                             = $dir/ca/$ca/crl.pem
private_key                     = $dir/ca/$ca/private/cakey.pem
RANDFILE                        = $dir/ca/$ca/private/.rand
unique_subject                  = no
default_days                    = 730
default_md                      = sha384
digests                         = sha384
policy                          = match_pol
email_in_dn                     = no
preserve                        = no
name_opt                        = $name_opt
cert_opt                        = ca_default
copy_extensions                 = copy
x509_extensions                 = identity_ca_ext
default_crl_days                = 30
crl_extensions                  = crl_ext

[ match_pol ]
countryName                 = match
stateOrProvinceName         = optional
localityName                = optional
organizationName            = match
organizationalUnitName      = optional
commonName                  = supplied

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

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = ca_dn
req_extensions              = ca_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = no
SET-ex3                     = SET extension number 3

[ ca_dn ]
countryName                 = "DE"
organizationName            = "Example Corporation"
organizationalUnitName      = "Certification Authority"
commonName                  = "Example Corporation Identity CA"

[ ca_reqext ]
basicConstraints            = critical, CA:TRUE, pathLen:0
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash

[ identity_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, emailProtection, clientAuth, msSmartcardLogin
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssurance

[ encryption_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, keyEncipherment
extendedKeyUsage            = critical, emailProtection, msEFS
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssurance

[ crl_ext ]
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info

[ issuer_info ]
caIssuers;URI.0             = $aia_url

[ crl_info ]
URI.0                       = $crl_url

[ openssl_init ]
oid_section                 = additional_oids

[ additional_oids ]
mediumAssurance             = Medium Assurance, 1.3.6.1.4.1.0.1.7.8
mediumAssuranceDevice       = Medium Device Assurance, 1.3.6.1.4.1.0.1.7.9
"EOF"

Verzeichnisstruktur anlegen, RANDFILE erzeugen, zufälligen Startwert für die späteren Serialnummern festlegen und Indexfile anlegen.

/bin/mkdir -p ca/identity-ca/{certs,crl,newcerts,private,revoked}
/bin/chmod 0700 ca/identity-ca/private
/usr/bin/openssl rand -out ca/identity-ca/private/.rand 65536
/bin/echo `/usr/bin/openssl rand -hex 8 | /usr/bin/tr '[[:lower:]]' '[[:upper:]]'` > ca/identity-ca/serial
/bin/cp ca/identity-ca/serial ca/identity-ca/crlnumber
/usr/bin/touch ca/identity-ca/index.txt ca/identity-ca/index.txt.attr

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > ca/identity-ca/private/identity-ca.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out ca/identity-ca/private/cakey.pem \
    -pass file:ca/identity-ca/private/identity-ca.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/identity-ca.conf \
    -new \
    -out ca/identity-ca/careq.pem \
    -key ca/identity-ca/private/cakey.pem \
    -passin file:ca/identity-ca/private/identity-ca.pwd

Durch die Network CA signiertes Zertifikat für die Identity CA erzeugen. Die Gültigkeitsdauer wird auf 5 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/network-ca.conf \
    -batch \
    -in ca/identity-ca/careq.pem \
    -out ca/identity-ca/cacert.pem \
    -extensions signing_ca_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+5y '+%Y%m01000000Z'` \
    -passin file:ca/network-ca/private/network-ca.pwd

Initiale CRL der Identity CA erzeugen.

/usr/bin/openssl ca \
    -config etc/identity-ca.conf \
    -gencrl \
    -out ca/identity-ca/crl.pem \
    -passin file:ca/identity-ca/private/identity-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl x509 \
    -in ca/identity-ca/cacert.pem \
    -out ca/identity-ca.cer \
    -outform DER

CRL in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl \
    -in ca/identity-ca/crl.pem \
    -out ca/identity-ca.crl \
    -outform DER

Chain der Identity CA erzeugen.

/bin/cat ca/identity-ca/crl.pem ca/network-ca/crl.pem > ca/identity-ca-crl-chain.pem
/bin/cat ca/identity-ca/cacert.pem ca/network-ca/cacert.pem > ca/identity-ca-chain.pem

Chain der Identity CA in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl2pkcs7 \
    -nocrl \
    -certfile ca/identity-ca-chain.pem \
    -out ca/identity-ca-chain.p7c \
    -outform DER

Component Signing CA erstellen

In der etc/component-ca.conf müssen noch ein paar Anpassungen vorgenommen werden:

  1. Im Abschnitt [ default ] muss die Option base_url auf den URL gesetzt werden, unter dem später die Certs, CRLs und Chains veröffentlicht werden sollen.
  2. !!! Wird derzeit nicht verwendet !!! Im Abschnitt [ default ] muss die Option ocsp_url auf den URL gesetzt werden, unter dem später der OCSP-Responder erreichbar sein wird.
  3. Im Abschnitt [ ca_dn ] muss die Option countryName auf das internationale zweibuchstabige Länderkürzel des Betreibers der Component CA gesetzt werden.
  4. Im Abschnitt [ ca_dn ] muss die Option organizationName auf den Firmennamen des Betreibers der Component CA gesetzt werden.
  5. Im Abschnitt [ ca_dn ] muss die Option organizationalUnitName auf den zuständigen Abteilungsnamen des Betreibers der Component CA gesetzt werden.
  6. Im Abschnitt [ ca_dn ] muss die Option commonName auf den Namen der Component CA (im Regelfall "Firmenname Component CA") gesetzt werden.
  7. Im Abschnitt [ additional_oids ] müssen die OIDs entsprechend der eigenen registrierten OIDs ersetzt werden.
cd /data/pki

/bin/cat > etc/component-ca.conf << "EOF"
#
# Example Corporation Component CA
#

[ default ]
ca                              = component-ca
base_url                        = http://pki.example.com
ocsp_url                        = http://pki.example.com/ocsp
aia_url                         = $base_url/$ca.cer
crl_url                         = $base_url/$ca.crl
name_opt                        = multiline,-esc_msb,utf8
openssl_conf                    = openssl_init

[ ca ]
default_ca                      = component_ca

[ component_ca ]
dir                             = .
certs                           = $dir/ca/$ca/certs
crl_dir                         = $dir/ca/$ca/crl
database                        = $dir/ca/$ca/index.txt
new_certs_dir                   = $dir/ca/$ca/newcerts
certificate                     = $dir/ca/$ca/cacert.pem
serial                          = $dir/ca/$ca/serial
crlnumber                       = $dir/ca/$ca/crlnumber
crl                             = $dir/ca/$ca/crl.pem
private_key                     = $dir/ca/$ca/private/cakey.pem
RANDFILE                        = $dir/ca/$ca/private/.rand
unique_subject                  = no
default_days                    = 730
default_md                      = sha384
digests                         = sha384
policy                          = match_pol
email_in_dn                     = no
preserve                        = no
name_opt                        = $name_opt
cert_opt                        = ca_default
copy_extensions                 = copy
x509_extensions                 = server_ext
default_crl_days                = 30
crl_extensions                  = crl_ext

[ match_pol ]
countryName                 = match
stateOrProvinceName         = optional
localityName                = optional
organizationName            = match
organizationalUnitName      = optional
commonName                  = supplied

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

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = ca_dn
req_extensions              = ca_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = no
SET-ex3                     = SET extension number 3

[ ca_dn ]
countryName                 = "DE"
organizationName            = "Example Corporation"
organizationalUnitName      = "Certification Authority"
commonName                  = "Example Corporation Component CA"

[ ca_reqext ]
basicConstraints            = critical, CA:TRUE, pathLen:0
keyUsage                    = critical, keyCertSign, cRLSign
subjectKeyIdentifier        = hash

[ server_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature, keyEncipherment
extendedKeyUsage            = critical, serverAuth, clientAuth
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
#authorityInfoAccess         = @ocsp_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssuranceDevice

[ client_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, clientAuth
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
#authorityInfoAccess         = @ocsp_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssuranceDevice

[ timestamp_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, timeStamping
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
crlDistributionPoints       = @crl_info
certificatePolicies         = mediumAssuranceDevice

[ ocspsign_ext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, OCSPSigning
subjectKeyIdentifier        = hash
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info
noCheck                     = null
certificatePolicies         = mediumAssuranceDevice

[ crl_ext ]
authorityKeyIdentifier      = keyid:always
authorityInfoAccess         = @issuer_info

[ ocsp_info ]
caIssuers;URI.0             = $aia_url
OCSP;URI.0                  = $ocsp_url

[ issuer_info ]
caIssuers;URI.0             = $aia_url

[ crl_info ]
URI.0                       = $crl_url

[ openssl_init ]
oid_section                 = additional_oids

[ additional_oids ]
mediumAssurance             = Medium Assurance, 1.3.6.1.4.1.0.1.7.8
mediumAssuranceDevice       = Medium Device Assurance, 1.3.6.1.4.1.0.1.7.9
"EOF"

Verzeichnisstruktur anlegen, RANDFILE erzeugen, zufälligen Startwert für die späteren Serialnummern festlegen und Indexfile anlegen.

/bin/mkdir -p ca/component-ca/{certs,crl,newcerts,private,revoked}
/bin/chmod 0700 ca/component-ca/private
/usr/bin/openssl rand -out ca/component-ca/private/.rand 65536
/bin/echo `/usr/bin/openssl rand -hex 8 | /usr/bin/tr '[[:lower:]]' '[[:upper:]]'` > ca/component-ca/serial
/bin/cp ca/component-ca/serial ca/component-ca/crlnumber
/usr/bin/touch ca/component-ca/index.txt ca/component-ca/index.txt.attr

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > ca/component-ca/private/component-ca.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out ca/component-ca/private/cakey.pem \
    -pass file:ca/component-ca/private/component-ca.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/component-ca.conf \
    -new \
    -out ca/component-ca/careq.pem \
    -key ca/component-ca/private/cakey.pem \
    -passin file:ca/component-ca/private/component-ca.pwd

Durch die Network CA signiertes Zertifikat für die Component CA erzeugen. Die Gültigkeitsdauer wird auf 5 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/network-ca.conf \
    -batch \
    -in ca/component-ca/careq.pem \
    -out ca/component-ca/cacert.pem \
    -extensions signing_ca_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+5y '+%Y%m01000000Z'` \
    -passin file:ca/network-ca/private/network-ca.pwd

Initiale CRL der Component CA erzeugen.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -gencrl \
    -out ca/component-ca/crl.pem \
    -passin file:ca/component-ca/private/component-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl x509 \
    -in ca/component-ca/cacert.pem \
    -out ca/component-ca.cer \
    -outform DER

CRL in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl \
    -in ca/component-ca/crl.pem \
    -out ca/component-ca.crl \
    -outform DER

Chain der Component CA erzeugen.

/bin/cat ca/component-ca/crl.pem ca/network-ca/crl.pem > ca/component-ca-crl-chain.pem
/bin/cat ca/component-ca/cacert.pem ca/network-ca/cacert.pem > ca/component-ca-chain.pem

Chain der Component CA in ein veröffentlichbares Format exportieren.

/usr/bin/openssl crl2pkcs7 \
    -nocrl -certfile ca/component-ca-chain.pem \
    -out ca/component-ca-chain.p7c \
    -outform DER

CRLs und Chains erneuern

Die CRLs und Chains sollten regelmässig (spätestens alle 30 Tage) aktualisiert und veröffentlicht werden, da sie ansonsten ungültig werden und manche Clients deshalb auch die Zertifikate als ungültig einstufen.

Um diesen Zustand gar nicht erst entstehen zu lassen, legen wir uns ein passendes Script an und automatisieren dessen Ausführung (täglich 06:00 Uhr) per cron.

cd /data/pki

/bin/cat > update-crls-chains.sh << "EOF"
#!/bin/sh

cd /data/pki

/usr/bin/openssl ca \
    -config etc/root-ca.conf \
    -gencrl \
    -out ca/root-ca/crl.pem \
    -passin file:ca/root-ca/private/root-ca.pwd
/usr/bin/openssl ca \
    -config etc/network-ca.conf \
    -gencrl \
    -out ca/network-ca/crl.pem \
    -passin file:ca/network-ca/private/network-ca.pwd
/usr/bin/openssl ca \
    -config etc/identity-ca.conf \
    -gencrl \
    -out ca/identity-ca/crl.pem \
    -passin file:ca/identity-ca/private/identity-ca.pwd
/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -gencrl \
    -out ca/component-ca/crl.pem \
    -passin file:ca/component-ca/private/component-ca.pwd

/usr/bin/openssl crl \
    -in ca/root-ca/crl.pem \
    -out ca/root-ca.crl \
    -outform DER
/usr/bin/openssl crl \
    -in ca/network-ca/crl.pem \
    -out ca/network-ca.crl \
    -outform DER
/usr/bin/openssl crl \
    -in ca/identity-ca/crl.pem \
    -out ca/identity-ca.crl \
    -outform DER
/usr/bin/openssl crl \
    -in ca/component-ca/crl.pem \
    -out ca/component-ca.crl \
    -outform DER

/bin/cat ca/network-ca/crl.pem ca/root-ca/crl.pem > ca/network-ca-crl-chain.pem
/bin/cat ca/identity-ca/crl.pem ca/network-ca-crl-chain.pem > ca/identity-ca-crl-chain.pem
/bin/cat ca/component-ca/crl.pem ca/network-ca-crl-chain.pem > ca/component-ca-crl-chain.pem

/bin/cat ca/network-ca/cacert.pem ca/root-ca/cacert.pem > ca/network-ca-chain.pem
/bin/cat ca/identity-ca/cacert.pem ca/network-ca/cacert.pem > ca/identity-ca-chain.pem
/bin/cat ca/component-ca/cacert.pem ca/network-ca/cacert.pem > ca/component-ca-chain.pem

/usr/bin/openssl crl2pkcs7 \
    -nocrl \
    -certfile ca/network-ca-chain.pem \
    -out ca/network-ca-chain.p7c \
    -outform DER
/usr/bin/openssl crl2pkcs7 \
    -nocrl \
    -certfile ca/identity-ca-chain.pem \
    -out ca/identity-ca-chain.p7c \
    -outform DER
/usr/bin/openssl crl2pkcs7 \
    -nocrl \
    -certfile ca/component-ca-chain.pem \
    -out ca/component-ca-chain.p7c \
    -outform DER

/bin/cp ca/root-ca.cer /data/www/vhosts/pki.example.com/data/root-ca.cer
/bin/cp ca/network-ca.cer /data/www/vhosts/pki.example.com/data/network-ca.cer
/bin/cp ca/identity-ca.cer /data/www/vhosts/pki.example.com/data/identity-ca.cer
/bin/cp ca/component-ca.cer /data/www/vhosts/pki.example.com/data/component-ca.cer

/bin/cp ca/root-ca.crl /data/www/vhosts/pki.example.com/data/root-ca.crl
/bin/cp ca/network-ca.crl /data/www/vhosts/pki.example.com/data/network-ca.crl
/bin/cp ca/identity-ca.crl /data/www/vhosts/pki.example.com/data/identity-ca.crl
/bin/cp ca/component-ca.crl /data/www/vhosts/pki.example.com/data/component-ca.crl

/bin/cp ca/network-ca-chain.p7c /data/www/vhosts/pki.example.com/data/network-ca-chain.p7c
/bin/cp ca/identity-ca-chain.p7c /data/www/vhosts/pki.example.com/data/identity-ca-chain.p7c
/bin/cp ca/component-ca-chain.p7c /data/www/vhosts/pki.example.com/data/component-ca-chain.p7c

/bin/chmod 0440 /data/www/vhosts/pki.example.com/data/*.cer
/bin/chmod 0440 /data/www/vhosts/pki.example.com/data/*.crl
/bin/chmod 0440 /data/www/vhosts/pki.example.com/data/*.p7c

/bin/chown www:www /data/www/vhosts/pki.example.com/data/*.cer
/bin/chown www:www /data/www/vhosts/pki.example.com/data/*.crl
/bin/chown www:www /data/www/vhosts/pki.example.com/data/*.p7c

service dovecot restart
service postfix restart
service apache24 restart
"EOF"

/bin/chmod 0755 update-crls-chains.sh

Cronjob für update-crls-chains.sh anlegen.

/bin/cat >> /etc/crontab << "EOF"
0       6       *       *       *       root    /data/pki/update-crls-chains.sh
"EOF"

OpenSSL Zertifikate

Identity Certificate erstellen

cd /data/pki

/bin/cat > etc/identity.conf << "EOF"
# Identity certificate request

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = identity_dn
req_extensions              = identity_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

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

[ identity_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, emailProtection, clientAuth
subjectKeyIdentifier        = hash
subjectAltName              = email:move
"EOF"

/bin/cat > etc/encryption.conf << "EOF"
# Encryption certificate request

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = encryption_dn
req_extensions              = encryption_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

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

[ encryption_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, keyEncipherment
extendedKeyUsage            = critical, emailProtection
subjectKeyIdentifier        = hash
subjectAltName              = email:move
"EOF"

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/admin-id.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/admin-id.key \
    -pass file:private/admin-id.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/identity.conf \
    -new \
    -out certs/admin-id.csr \
    -key private/admin-id.key \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=Administrator/emailAddress=admin@example.com \
    -passin file:private/admin-id.pwd

Durch die Identity CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/identity-ca.conf \
    -batch \
    -in certs/admin-id.csr \
    -out certs/admin-id.crt \
    -extensions identity_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/identity-ca/private/identity-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl pkcs12 \
    -export \
    -aes256 \
    -inkey private/admin-id.key \
    -certfile ca/identity-ca-chain.pem \
    -name "Administrator (System Administration)" \
    -caname "Example Corporation Identity CA" \
    -caname "Example Corporation Network CA" \
    -caname "Example Corporation Root CA" \
    -in certs/admin-id.crt \
    -out certs/admin-id.p12 \
    -passin file:private/admin-id.pwd

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/admin-enc.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/admin-enc.key \
    -pass file:private/admin-enc.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/encryption.conf \
    -new \
    -out certs/admin-enc.csr \
    -key private/admin-enc.key \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=Administrator/emailAddress=admin@example.com \
    -passin file:private/admin-enc.pwd

Durch die Identity CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/identity-ca.conf \
    -batch \
    -in certs/admin-enc.csr \
    -out certs/admin-enc.crt \
    -extensions encryption_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/identity-ca/private/identity-ca.pwd

Zertifikat in ein veröffentlichbares Format exportieren.

/usr/bin/openssl pkcs12 \
    -export \
    -aes256 \
    -inkey private/admin-enc.key \
    -certfile ca/identity-ca-chain.pem \
    -name "Administrator (System Administration)" \
    -caname "Example Corporation Identity CA" \
    -caname "Example Corporation Network CA" \
    -caname "Example Corporation Root CA" \
    -in certs/admin-enc.crt \
    -out certs/admin-enc.p12 \
    -passin file:private/admin-enc.pwd

TLS Client Certificate erstellen

cd /data/pki

/bin/cat > etc/tls-client.conf << "EOF"
# TLS client certificate request

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = no
distinguished_name          = client_dn
req_extensions              = client_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

[ client_dn ]
countryName                 = Country Name (2 letter code)
countryName_min             = 2
countryName_max             = 2
stateOrProvinceName         = State or Province Name (full name)
localityName                = Locality Name (eg, city)
organizationName            = Organization Name (eg, company)
organizationalUnitName      = Organizational Unit Name (eg, section)
commonName                  = Common Name (e.g. server FQDN)
commonName_max              = 64

[ client_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, clientAuth
subjectKeyIdentifier        = hash
"EOF"

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/workstation.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/workstation.key \
    -pass file:private/workstation.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/tls-client.conf \
    -new \
    -out certs/workstation.csr \
    -key private/workstation.key \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=Workstation \
    -passin file:private/workstation.pwd

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/workstation.csr \
    -out certs/workstation.crt \
    -extensions client_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

TLS Server Certificate erstellen

In der etc/tls-server.conf müssen noch ein paar Anpassungen vorgenommen werden:

  1. Im Abschnitt [ default ] muss die Option SAN auf den Domainnamen (ohne Subdomain) des Serverbetreibers gesetzt werden.
cd /data/pki

/bin/cat > etc/tls-server.conf << "EOF"
# TLS server certificate request

[ default ]
SAN                         = DNS:example.com

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = yes
distinguished_name          = server_dn
req_extensions              = server_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

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

[ server_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature, keyEncipherment
extendedKeyUsage            = critical, serverAuth, clientAuth
subjectKeyIdentifier        = hash
subjectAltName              = $ENV::SAN
1.3.6.1.5.5.7.1.24          = DER:30:03:02:01:05
"EOF"

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/devnull.example.com.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/devnull.example.com.key.enc \
    -pass file:private/devnull.example.com.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

setenv SAN "DNS:devnull.example.com"
/usr/bin/openssl req \
    -config etc/tls-server.conf \
    -new \
    -out certs/devnull.example.com.csr \
    -key private/devnull.example.com.key.enc \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=devnull.example.com \
    -passin file:private/devnull.example.com.pwd
unsetenv SAN

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/devnull.example.com.csr \
    -out certs/devnull.example.com.crt \
    -extensions server_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

Eine passwortlose Kopie des privaten Schlüssels anlegen, wie sie zum problemlosen Starten von Diensten wie Webserver, Mailserver, etc benötigt wird.

/usr/bin/openssl pkey \
    -in private/devnull.example.com.key.enc \
    -out private/devnull.example.com.key \
    -passin file:private/devnull.example.com.pwd

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/mail.example.com.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/mail.example.com.key.enc \
    -pass file:private/mail.example.com.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

setenv SAN "DNS:mail.example.com"
/usr/bin/openssl req \
    -config etc/tls-server.conf \
    -new \
    -out certs/mail.example.com.csr \
    -key private/mail.example.com.key.enc \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=mail.example.com \
    -passin file:private/mail.example.com.pwd
unsetenv SAN

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/mail.example.com.csr \
    -out certs/mail.example.com.crt \
    -extensions server_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

Eine passwortlose Kopie des privaten Schlüssels anlegen, wie sie zum problemlosen Starten von Diensten wie Webserver, Mailserver, etc benötigt wird.

/usr/bin/openssl pkey \
    -in private/mail.example.com.key.enc \
    -out private/mail.example.com.key \
    -passin file:private/mail.example.com.pwd

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/www.example.com.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/www.example.com.key.enc \
    -pass file:private/www.example.com.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

setenv SAN "DNS:www.example.com,DNS:example.com"
/usr/bin/openssl req \
    -config etc/tls-server.conf \
    -new \
    -out certs/www.example.com.csr \
    -key private/www.example.com.key.enc \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=www.example.com \
    -passin file:private/www.example.com.pwd
unsetenv SAN

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/www.example.com.csr \
    -out certs/www.example.com.crt \
    -extensions server_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

Eine passwortlose Kopie des privaten Schlüssels anlegen, wie sie zum problemlosen Starten von Diensten wie Webserver, Mailserver, etc benötigt wird.

/usr/bin/openssl pkey \
    -in private/www.example.com.key.enc \
    -out private/www.example.com.key \
    -passin file:private/www.example.com.pwd

Time-stamping Certificate erstellen

cd /data/pki

/bin/cat > etc/timestamping.conf << "EOF"
# Time-stamping certificate request

[ req ]
default_bits                = 2048
default_md                  = sha384
digests                     = sha384
encrypt_key                 = no
distinguished_name          = timestamp_dn
req_extensions              = timestamp_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

[ timestamp_dn ]
countryName                 = Country Name (2 letter code)
countryName_min             = 2
countryName_max             = 2
stateOrProvinceName         = State or Province Name (full name)
localityName                = Locality Name (eg, city)
organizationName            = Organization Name (eg, company)
organizationalUnitName      = Organizational Unit Name (eg, section)
commonName                  = Common Name (e.g. server FQDN)
commonName_max              = 64

[ timestamp_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature
extendedKeyUsage            = critical, timeStamping
subjectKeyIdentifier        = hash
"EOF"

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/timestamping.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/timestamping.key \
    -pass file:private/timestamping.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/timestamping.conf \
    -new \
    -out certs/timestamping.csr \
    -key private/timestamping.key \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=Example\ Corporation\ Timestamping\ Service \
    -passin file:private/timestamping.pwd

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/timestamping.csr \
    -out certs/timestamping.crt \
    -extensions timestamp_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

OCSP-Signing Certificate erstellen

cd /data/pki

/bin/cat > etc/ocspsigning.conf << "EOF"
# OCSP-signing certificate request

[ req ]
default_bits                = 2048
default_md                  = sha384
encrypt_key                 = no
distinguished_name          = ocspsign_dn
req_extensions              = ocspsign_reqext
string_mask                 = utf8only
utf8                        = yes
prompt                      = yes
SET-ex3                     = SET extension number 3

[ ocspsign_dn ]
countryName                 = Country Name (2 letter code)
countryName_min             = 2
countryName_max             = 2
stateOrProvinceName         = State or Province Name (full name)
localityName                = Locality Name (eg, city)
organizationName            = Organization Name (eg, company)
organizationalUnitName      = Organizational Unit Name (eg, section)
commonName                  = Common Name (e.g. server FQDN)
commonName_max              = 64

[ ocspsign_reqext ]
basicConstraints            = CA:FALSE
keyUsage                    = critical, digitalSignature, keyEncipherment
extendedKeyUsage            = critical, serverAuth, clientAuth
subjectKeyIdentifier        = hash
"EOF"

Zufälliges, sicheres Passwort für das Zertifikat erzeugen und zur späteren (automatisierten) Verwendung in der .pwd speichern.

/usr/bin/openssl rand -hex 16 | \
    /usr/bin/openssl passwd -1 -stdin | \
    /usr/bin/tr -cd '[[:alnum:]]' \
    > private/ocspresponder.pwd

Privaten Schlüssel (RSA mit 2048 Bit Länge und AES256 verschlüsselt) zum Signieren des Zertifikats erzeugen.

/usr/bin/openssl genpkey \
    -aes-256-cbc \
    -algorithm RSA \
    -pkeyopt 'rsa_keygen_bits:2048' \
    -out private/ocspresponder.key \
    -pass file:private/ocspresponder.pwd

Zertifikatsanforderung erzeugen und mit dem privaten Schlüssel signieren.

/usr/bin/openssl req \
    -config etc/ocspsigning.conf \
    -new \
    -out certs/ocspresponder.csr \
    -key private/ocspresponder.key \
    -subj /C=DE/ST=State/L=Locality/O=Example\ Corporation/OU=System\ Administration/CN=Example\ Corporation\ OCSP\ Responder \
    -passin file:private/ocspresponder.pwd

Durch die Component CA signiertes Zertifikat erzeugen. Die Gültigkeitsdauer wird auf 2 Jahre ab dem 1. des aktuellen Monats festgelegt.

/usr/bin/openssl ca \
    -config etc/component-ca.conf \
    -batch \
    -in certs/ocspresponder.csr \
    -out certs/ocspresponder.crt \
    -extensions ocspsign_ext \
    -startdate `date -j -u '+%Y%m01000000Z'` \
    -enddate `date -j -u -v+2y '+%Y%m01000000Z'` \
    -passin file:ca/component-ca/private/component-ca.pwd

FIXME: Work in progress basierend auf dem OpenSSL PKI Tutorial v1.1 (Stand: 05.04.2017) (für Erläuterungen bitte auch dort nachsehen).

Wie geht es weiter?

Natürlich mit dem FreeBSD Web Hosting System.