Mit Zertifikaten wird die Kommunikation zwischen Rechnern abgesichert. Bildlich gesprochen bestätigen sie, dass der Rechner auch der ist, für den er sich ausgibt. Die Echtheit von Zertifikaten wird typischerweise von einem weiteren Zertifikat bestätigt. Das Ganze bildet eine Kette von Vertrauen (Chain of Trust), die in sogenannten Root-Zertifikaten gründet, denen von vornherein vertraut wird. Diese Root-Zertifikate stammen normalerweise von großen Firmen und man muss in aller Regel dafür bezahlen, wenn einem diese Firmen bestätigen sollen, dass der Rechner ‚testserver.meine-domain.de‘ eine bestimmte Adresse hat. Diese Root-Zertifikate sind selbst unterzeichnet und begründen das Vertrauen, das in sie gesetzt wird eigentlich durch das Renommé, das deren Aussteller geniessen.
Es gibt mit Openssl aber auch die Möglichkeit, selbst ein Zertifikat auszustellen – im einfachsten Fall ebenfalls selbst unterzeichnet. Man kann mit so einem Zertifikat dann ein ganzes Netz von Vertrauensbeziehungen selbst erstellen. Für die Kommunikation von Rechnern in einem internen Netzwerk ist das vollkommen in Ordnung. Damit das funktioniert, muss das selbst erstelle Root-Zertifikat von den Rechnern des internen Netzwerks als gültig angesehen werden, dann sind Zertifikate, die davon unterzeichnet wurden, genauso gut verwendbar wie kommerziell erstellte Zertifikate.
Wenn man das in die Tat umsetzen möchte, steht hier, wie man das machen kann. Diese Installation verlangt, dass die Datei /etc/ssl/openssl.cnf bestimmte Inhalte hat. Damit lassen sich dann Zertifikate für bestimmte Zweck erstellen.
Das Erstellen von Zertifikaten umfasst 3 Schritte – zunächst einen Schlüssel erstellen, dann einen Request erstellen und zuletzt das Unterzeichnen des Zertifikats durch das Root-Zertifikat.
In dem Zertifikat steht der CommonName – das ist der Name, für den es gilt,
der Zweck (wofür es benutzt werden kann)
die Gültigkeitsdauer (von-bis)
und der Verweis auf das Root-Zertifikat – also wer das Zertifikat ausgestellt hat bzw. die Richtigkeit garantiert.
In der Praxis empfiehlt sich, den commonName auszuweiten; Apple hat seit 2019 sogar die Erfordernis, dass der Name, für den das Zertifikat gelten soll auch in den sogenannten SANs (Subject Alternate Names) aufgeführt wird.(https://support.apple.com/de-de/HT210176).
Soweit so gut – aber: wie macht man das konkret?
Zunächst der Inhalt der Datei /etc/ssl/openssl.cnf:
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
# Extra OBJECT IDENTIFIER info:
#oid_file = $ENV::HOME/.oid
oid_section = new_oids
# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)
[ new_oids ]
# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6
# Policies used by the TSA examples.
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7
# 1.3.6.1.5.5.7.3.1 für mac ios etc - id-kp-serverAuth OID
# das ist extendedKeyUsage = serverAuth
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = /root/ca # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
new_certs_dir = $dir/newcerts # default place for new certs.
database = $dir/index.txt # database index file.
serial = $dir/serial # The current serial number
RANDFILE = $dir/private/.rand # private random number file
#unique_subject = no # Set to 'no' to allow creation of
# several certs with same subject.
###### the root key and root certificate #################################
private_key = $dir/private/myca.key # The private key
certificate = $dir/certs/myca.crt # The CA certificate
#### obiges ist root zertifikat - zu dem gehen wir jetzt wieder zurück - keine 2stufige CA mehr
#private_key = $dir/private/wil.key.pem # The private key
#certificate = $dir/certs/wil.crt # The CA certificate
###### For certificate revocation lists ##################################
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
crl_extensions = crl_ext
default_crl_days = 30
######################################################################
default_md = sha256 # use SHA-2
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 1461 # how long to certify for
preserve = no # keep passed DN ordering
copy_extensions = copy
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
#policy = policy_strict
#####################################################
################# 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
################## match ###########################
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
################## loose #############################
[ 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
################## anything #########################
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 2048
#default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
string_mask = utf8only
#attributes = req_attributes
x509_extensions = v3_ca # The extensions to add to the self signed cert
# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret
###################################################################
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
emailAddress = Email Address
commonName = Common Name
############# defaults for the above ################
countryName_default = DE
stateOrProvinceName_default = BaWue
localityName_default = Ellwangen
0.organizationName_default = myorg
organizationalUnitName_default = IT
emailAddress_default = webmaster@myxy.de
####################### optional #####################
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
#commonName_max = 64
#emailAddress_max = 64
######################## schrott ############################
#[ req_attributes ]
#challengePassword = A challenge password
#challengePassword_min = 4
#challengePassword_max = 20
#unstructuredName = An optional company name
########################################################################
# The next few sections are extensions that can be applied when
# signing certificates. For example, passing the -extensions
# v3_ca command-line argument will apply the options set in [ v3_ca ]
########################################################################
[ v3_ca ]
# Extensions for a typical CA
# PKIX recommendation.
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
# Some might want this also
# nsCertType = sslCA, emailCA
# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy
# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF
########################################################################
[ 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 ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
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, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
#subjectAltName = @alt_names
[ alt_names ]
DNS.1 = www.myxy.de
DNS.2 = cms.myxy.de
DNS.3 = server.myxy.de
DNS.4 = server.myxz.de
IP.1 = 10.36.16.10
IP.2 = 10.37.18.10
##########################################################################
[ crl_ext ]
# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
# issuerAltName=issuer:copy
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
Darin ist auch eine intermediate CA enthalten, also eine Zwischen CA, die dann die eigentlichen Zertifikate unterzeichnet und von der Root-CA bestätigt ist. Das habe ich der Einfachheit halber weggelassen. Zum Verständnis der Syntax dieser Konfigurationsdatei: die Begriffe in [ eckigen Klammern ] fassen bestimmte Funktionen zusammen. Sie werden wirksam, dadurch dass man beim Aufruf der Zertifikatsunterzeichnung diesen Abschnitt mit -extensions = server_cert aktiviert. Unter dem gerade geenannten Abschnitt gibt es einen weiteren Abschnitt [ alt_names ]. Der würde aktiviert werden, wenn man das Kommentarzeichen vor ’subjectAltName = @alt_names‘ entfernt – dann würde @alt_names wirksam werden und den Block einbinden. Das ist die erste Möglichkeit, wie man solche SANs einbinden kann – dazu müsste man natürlich den Inhalt in der Konfigurationsdatei entsprechend anpassen.