Generating a self-signed cert with openssl that works in Chrome 58

As of Chrome 58 it no longer accepts self-signed certs that rely on Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category$3ACanary%7Csort:relevance%7Cspell:false

Instead it requires using Subject Alt Name. I have been previously following this guide on how to generate a self-signed cert: https://devcenter.heroku.com/articles/ssl-certificate-self which worked great because I required the server.crt and server.key files for what I'm doing. I now need to generate new certs that include the SAN however all of my attempts to do so have not worked with Chrome 58.

Here is what I've done:

I followed the steps on the above mentioned Heroku article to generate the key. I then wrote a new OpenSSL config file:

[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = san
extensions          = san
[ req_distinguished_name ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

Then generated the server.crt with the following command:

openssl req \
-new \
-key server.key \
-out server.csr \
-config config.cnf \
-sha256 \
-days 3650

I'm on a Mac, so I opened the server.crt file with Keychain, added it to my System Certificates. I then set it to Always Trust.

With the exception of the config file to set the SAN value these were similar steps I used in prior versions of Chrome to generate and trust the self-signed cert.

However, after this I still get the ERR_CERT_COMMON_NAME_INVALID in Chrome 58.


My solution:

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.key \
    -new \
    -out server.crt \
    -subj /CN=dev.mycompany.com \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')) \
    -sha256 \
    -days 3650

Status: Works for me


Here is a solution that works for me:

Create CA key and cert

# openssl genrsa -out server_rootCA.key 2048
# openssl req -x509 -new -nodes -key server_rootCA.key -sha256 -days 3650 -out server_rootCA.pem

Create server_rootCA.csr.cnf

# server_rootCA.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=DE
ST=Berlin
L=NeuKoelln
O=Weisestrasse
OU=local_RootCA
[email protected]
CN = server.berlin

Create v3.ext configuration file

# v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server.berlin

Create server key

# openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server_rootCA.csr.cnf )

Create server cert

# openssl x509 -req -in server.csr -CA server_rootCA.pem -CAkey server_rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext

Add cert and key to Apache2 site-file, HTTPS (port 443) section

SSLCertificateFile    /etc/apache2/ssl/server.crt
SSLCertificateKeyFile    /etc/apache2/ssl/server.key

Copy server_rootCA.pem from the server to your machine..

# scp [email protected]:~/server_rootCA.pem .

.. and add it to Chromium browser

Chromium -> Setting -> (Advanced) Manage Certificates -> Import -> 'server_rootCA.pem'

YOU ARE ALL DONE!

P.S. Instead of creating a functional CA & server cert pair (per the instructions above) you could simply disable HSTS headers in your HTTP server config. This will prevent Chromium from enforcing HTTPS and will allow users to click “Advanced → proceed to your.url (unsafe)” without having to obtain and install your custom CA (server_rootCA.pem) certificate. In other words – having to disable HSTS will allow your site to be publicly viewed over HTTP and/or insecure HTTPS connection (beware!).

For Apache2 add the following to site-file, HTTP (port 80) section

Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=0;includeSubDomains"

Tested on Debian/Apache2.4 + Debian/Chromium 59

https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58