How to create multi-domain certificates using config files

openssl can make life easy be creating its keys, CSRs and certificates on the basis of config files. Creating these config files, however, is not easy! This page is the result of my quest to to generate a certificate signing requests for multi-domain certificates.

This is a working configuration which is explained below:

# OpenSSL configuration to generate a new key with signing requst for a x509v3 
# multi-domain certificate
#
# openssl req -config bla.cnf -new | tee csr.pem
# or
# openssl req -config bla.cnf -new -out csr.pem
[ req ]
default_bits       = 4096
default_md         = sha512
default_keyfile    = key.pem
prompt             = no
encrypt_key        = no

# base request
distinguished_name = req_distinguished_name

# extensions
req_extensions     = v3_req

# distinguished_name
[ req_distinguished_name ]
# the CN the only thing that gets included into a domain-validated certificate (like Let's Encrypt) 
commonName             = "example.com"            # CN=
# EV certificates:
countryName            = "DE"                     # C=
stateOrProvinceName    = "Hessen"                 # ST=
localityName           = "Keller"                 # L=
postalCode             = "424242"                 # L/postalcode=
streetAddress          = "Crater 1621"            # L/street=
organizationName       = "apfelboymschule"        # O=
organizationalUnitName = "IT Department"          # OU=
emailAddress           = "webmaster@example.com"  # CN/emailAddress=

# req_extensions
[ v3_req ]
# The subject alternative name extension allows various literal values to be 
# included in the configuration file
# http://www.openssl.org/docs/apps/x509v3_config.html
subjectAltName  = DNS:www.example.com,DNS:www2.example.com # multi-domain certificate

# vim:ft=config
The quotes are not strictly neccessary, but without them strange things happen if the value contains e.g. an apostrophe.

req / [ req ]

openssl req creates and processes certificate requests. It reads the [ req ] section of the config file.

Some of the available options:

Section distinguished_name

In the default mode with prompting, the user is asked for the values. Default values can be defined by duplicating the option and appending _default to the name. This is what is in the examples all over the web, and it's annoying if all you want is to define a certain CSR for later use. If prompt is set to yes, the value will be taken directly from the option which defined the prompt in interactive mode. The _default-options are no longer valid. This is documented in openssl-req. (But where are the valid options in this section documented?)

The order of the definitions is relevant. If for example postalCode is directly under CN, the result will be CN=…/postalCode=…. If postalCode is under countryName the result will bm C=…/postalCode=…. The order in the example is modelled after a certificate bought from a real CA.

Section req_extensions

This option defines a section for X.509 v3 extension. Valid options documented in man openssl-x509v3_config. Note that half of the man page only affects CA actions.

Requests for multi-domain certificates are done by requesting a Subject Alternative Name x509v3 extensions with the DNS literal.

Result

This is what that CSR looks like
mori@apfelboymchen:/tmp $ openssl req -config bla.cnf -new | openssl req -text -noout
Generating a 512 bit RSA private key
.++++++++++++
............++++++++++++
writing new private key to 'key.pem'
-----
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=DE, ST=Hessen, L=Keller/postalCode=424242/street=Crater 1621, O=apfelboymschule, OU=IT Department, CN=example.com/emailAddress=webmaster@example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (512 bit)
                Modulus:
                    00:9b:9a:de:a2:29:5c:d2:50:80:af:6e:d4:43:f9:
                    63:58:ec:b5:b0:9f:8b:40:89:88:ce:14:ff:47:ec:
                    a4:18:81:33:fa:47:8f:c8:58:92:00:b4:89:27:0c:
                    71:d3:0f:e5:83:5c:e3:ad:41:d5:30:38:5d:a5:3d:
                    58:a4:27:ac:17
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name: 
                DNS:www.example.com, DNS:www2.example.com
    Signature Algorithm: sha1WithRSAEncryption
        08:94:37:9c:ac:03:07:aa:ca:ae:69:ed:38:db:57:0f:da:92:
        78:06:45:bd:24:9d:05:d7:76:92:49:b6:f3:9b:5c:c1:77:c5:
        e0:c4:a7:6b:63:82:01:44:48:f2:63:73:fb:2b:e9:14:45:56:
        a1:d4:e3:54:8a:2f:fb:53:06:34

Multiple CNs

I once bought a certificate where I defined the multi-domains in a browser textfield instead of the CSR. The certificate that came back not only had the X.509 extension, but also multiple CNs. The following distinguished_name-snippet reproduces this. I don't know if this is neccessary or even a good idea though. The certificate also had the domain from the CN duplicated in the extension, which doesn't look right either and makes me suspicious of the whole thing.
[ req_distinguished_name ]
countryName            = "DE"                             # C=
stateOrProvinceName    = "Hessen"                         # ST=
localityName           = "Keller"                         # L=
postalCode             = "424242"                         # L/postalCode=
streetAddress          = "Crater 1621"                    # L/street=
organizationName       = "apfelboymschule"                # O=
organizationalUnitName = "IT Department                   # OU=
0.commonName           = "example.com"                    # CN=
emailAddress           = "netzwerk@example.com"           # CN/emailAddress=
1.commonName           = "www.example.com"                # CN=
2.commonName           = "www2.example.com"               # CN=
3.commonName           = "www3.example.com"               # CN=

multi-domain certificates as a CA

So now I have a CSR with multi-domain request. What I couldn't get to work yet was to automatically use this information as the signing CA.

See also

A man page giving a generic overview of the configuration seems to have been axed. It's not on my system or on www.openssl.org, but I saved what seems to be one of the the last copies into the wayback machine: man openssl.cnf.

Licensed under the Creative Commons Attribution-Share Alike 3.0 License.