There are several great answers that give examples of how to get this working,
but none that explain where things went wrong in your attempt. OpenSSL can be
pretty non-intuitive some times so it is worth walking through.
First, as an aside, OpenSSL defaults to ignoring any distinguished name values
you provide in the config. If you want to use them you must add prompt = no
to your config. In addition, the command as written only generates a certificate
request not a certificate itself, so the -days
command does nothing.
If you generate your certificate request using this command you gave and inspect
the result, the Subject Alt Name is present:
$ openssl req -new -key server.key -out server.csr -config config.cnf -sha256
$ openssl req -text -noout -in server.csr
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
...
Exponent: 65537 (0x10001)
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:dev.mycompany.com
Signature Algorithm: sha256WithRSAEncryption
...
But then if you generate the certificate using the command in heroku link and
inspect the result, the Subject Alt Name is missing:
$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
$ openssl x509 -text -noout -in server.crt
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
89:fd:75:26:43:08:04:61
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = Massachusetts, L = Boston, O = MyCompany
Validity
Not Before: Jan 21 04:27:21 2018 GMT
Not After : Jan 21 04:27:21 2019 GMT
Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
...
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
...
The reason is that by default OpenSSL does not copy extensions from the request
to the certificate. Normally, the certificate would be created/signed by a CA
based on a request from a customer, and some extensions could grant the
certificate more power than the CA was intending if they were to blindly trust
the extensions defined in the request.
There are ways to tell OpenSSL to copy the extensions, but IMHO it is more
work than just providing the extensions in a config file when you generate the
certificate.
If you were to attempt to use your existing config file, it won't work because
the top level section is marked [req]
so those settings only apply to the req command not the x509 command. It isn't necessary to have a top-level section marker, so you can just remove that first line, and then it will work fine for both generating requests or certificate.
$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt -extfile config.cnf
Alternately, you can use the -x509
argument to the req
command to generate
a self-signed certificate in a single command, rather than first creating a
request and then a certificate. In this case it isn't necessary to remove the
[req]
section line, as that section is read and used by the req command.
$ openssl req -x509 -sha256 -days 365 -key server.key -out server.crt -config config.cnf
To recap, here is the modified config file used in the above commands:
default_bits = 2048
distinguished_name = dn
x509_extensions = san
req_extensions = san
extensions = san
prompt = no
[ dn ]
countryName = US
stateOrProvinceName = Massachusetts
localityName = Boston
organizationName = MyCompany
[ san ]
subjectAltName = DNS:dev.mycompany.com