Getting Chrome to accept self-signed localhost certificate
Getting Chrome to accept self-signed localhost certificate
Question
I have created a self-signed SSL certificate for the localhost CN. Firefox accepts this certificate after initially complaining about it, as expected. Chrome and IE, however, refuse to accept it, even after adding the certificate to the system certificate store under Trusted Roots. Even though the certificate is listed as correctly installed when I click "View certificate information" in Chrome's HTTPS popup, it still insists the certificate cannot be trusted.
What am I supposed to do to get Chrome to accept the certificate and stop complaining about it?
Accepted Answer
2020-05-22: With only 5 openssl
commands, you can accomplish this.
Please do not change your browser security settings.
With the following code, you can (1) become your own CA, (2) then sign your SSL certificate as a CA. (3) Then import the CA certificate (not the SSL certificate, which goes onto your server) into Chrome/Chromium. (Yes, this works even on Linux.)
######################
# Become a Certificate Authority
######################
# Generate private key
openssl genrsa -des3 -out myCA.key 2048
# Generate root certificate
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 825 -out myCA.pem
######################
# Create CA-signed certs
######################
NAME=mydomain.com # Use your own domain name
# Generate a private key
openssl genrsa -out $NAME.key 2048
# Create a certificate-signing request
openssl req -new -key $NAME.key -out $NAME.csr
# Create a config file for the extensions
>$NAME.ext cat <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = $NAME # Be sure to include the domain name here because Common Name is not so commonly honoured by itself
DNS.2 = bar.$NAME # Optionally, add additional domains (I've added a subdomain here)
IP.1 = 192.168.0.13 # Optionally, add an IP address (if the connection which you have planned requires it)
EOF
# Create the signed certificate
openssl x509 -req -in $NAME.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial \
-out $NAME.crt -days 825 -sha256 -extfile $NAME.ext
To recap:
- Become a CA
- Sign your certificate using your CA cert+key
- Import
myCA.pem
as an Authority in your Chrome settings (Settings > Manage certificates > Authorities > Import) - Use the
.crt
and.key
files in your server
Extra steps (for Mac, at least):
- Import the CA cert at "File > Import file", then also find it in the list, right click it, expand "> Trust", and select "Always"
- Add
extendedKeyUsage=serverAuth,clientAuth
belowbasicConstraints=CA:FALSE
, and make sure you set the "CommonName" to the same as$NAME
when it's asking for setup
You can check your work
openssl verify -CAfile myCA.pem -verify_hostname bar.mydomain.com mydomain.com.crt
Popular Answer
For localhost
only:
Simply paste this in your chrome:
chrome://flags/#allow-insecure-localhost
You should see highlighted text saying: Allow invalid certificates for resources loaded from localhost
Click Enable
.
Read more… Read less…
This worked for me:
- Using Chrome, hit a page on your server via HTTPS and continue past the red warning page (assuming you haven't done this already).
- Open up
Chrome Settings > Show advanced settings > HTTPS/SSL > Manage Certificates
. - Click the
Authorities
tab and scroll down to find your certificate under the Organization Name that you gave to the certificate. - Select it, click Edit (NOTE: in recent versions of Chrome, the button is now "Advanced" instead of "Edit"), check all the boxes and click OK. You may have to restart Chrome.
You should get the nice green lock on your pages now.
EDIT: I tried this again on a new machine and the certificate did not appear on the Manage Certificates window just by continuing from the red untrusted certificate page. I had to do the following:
- On the page with the untrusted certificate (
https://
is crossed out in red), click the lock > Certificate Information. NOTE: on newer versions of chrome, you have to openDeveloper Tools > Security
, and selectView certificate
. - Click the
Details tab > Export
. ChoosePKCS #7, single certificate
as the file format. - Then follow my original instructions to get to the Manage Certificates page. Click the
Authorities tab > Import
and choose the file to which you exported the certificate, and make sure to choosePKCS #7, single certificate
as the file type. - If prompted certification store, choose Trusted Root Certificate Authorities
- Check all boxes and click OK. Restart Chrome.
UPDATE FOR CHROME 58+ (RELEASED 2017-04-19)
As of Chrome 58, the ability to identify the host using only commonName
was removed. Certificates must now use subjectAltName
to identify their host(s). See further discussion here and bug tracker here. In the past, subjectAltName
was used only for multi-host certs so some internal CA tools don't include them.
If your self-signed certs worked fine in the past but suddenly started generating errors in Chrome 58, this is why.
So whatever method you are using to generate your self-signed cert (or cert signed by a self-signed CA), ensure that the server's cert contains a subjectAltName
with the proper DNS
and/or IP
entry/entries, even if it's just for a single host.
For openssl, this means your OpenSSL config (/etc/ssl/openssl.cnf
on Ubuntu) should have something similar to the following for a single host:
[v3_ca] # and/or [v3_req], if you are generating a CSR
subjectAltName = DNS:example.com
or for multiple hosts:
[v3_ca] # and/or [v3_req], if you are generating a CSR
subjectAltName = DNS:example.com, DNS:host1.example.com, DNS:*.host2.example.com, IP:10.1.2.3
In Chrome's cert viewer (which has moved to "Security" tab under F12) you should see it listed under Extensions
as Certificate Subject Alternative Name
:
Click anywhere on the page and type a BYPASS_SEQUENCE
"thisisunsafe
" is a BYPASS_SEQUENCE for Chrome version 65
"badidea
" Chrome version 62 - 64.
"danger
" used to work in earlier versions of Chrome
You don't need to look for input field, just type it. It feels strange but it is working.
I tried it on Mac High Sierra.
To double check if they changed it again go to Latest chromium Source Code
To look for BYPASS_SEQUENCE, at the moment it looks like that:
var BYPASS_SEQUENCE = window.atob('dGhpc2lzdW5zYWZl');
Now they have it camouflaged, but to see the real BYPASS_SEQUENCE you can run following line in a browser console.
console.log(window.atob('dGhpc2lzdW5zYWZl'));
On the Mac, you can use the Keychain Access utility to add the self-signed certificate to the System keychain, and Chrome will then accept it. I found the step-by-step instructions here:
Google Chrome, Mac OS X and Self-Signed SSL Certificates
Basically:
- double-click the lock icon with an X and drag-and-drop the certificate icon to the desktop,
- open this file (ending with a .cer extension); this opens the keychain application which allows you to approve the certificate.
On the Mac, you can create a certificate that's fully trusted by Chrome and Safari at the system level by doing the following:
# create a root authority cert
./create_root_cert_and_key.sh
# create a wildcard cert for mysite.com
./create_certificate_for_domain.sh mysite.com
# or create a cert for www.mysite.com, no wildcards
./create_certificate_for_domain.sh www.mysite.com www.mysite.com
The above uses the following scripts, and a supporting file v3.ext
, to avoid subject alternative name missing errors
If you want to create a new self signed cert that's fully trusted using your own root authority, you can do it using these scripts.
create_root_cert_and_key.sh
#!/usr/bin/env bash
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem
create_certificate_for_domain.sh
#!/usr/bin/env bash
if [ -z "$1" ]
then
echo "Please supply a subdomain to create a certificate for";
echo "e.g. www.mysite.com"
exit;
fi
if [ ! -f rootCA.pem ]; then
echo 'Please run "create_root_cert_and_key.sh" first, and try again!'
exit;
fi
if [ ! -f v3.ext ]; then
echo 'Please download the "v3.ext" file and try again!'
exit;
fi
# Create a new private key if one doesnt exist, or use the xeisting one if it does
if [ -f device.key ]; then
KEY_OPT="-key"
else
KEY_OPT="-keyout"
fi
DOMAIN=$1
COMMON_NAME=${2:-*.$1}
SUBJECT="/C=CA/ST=None/L=NB/O=None/CN=$COMMON_NAME"
NUM_OF_DAYS=825
openssl req -new -newkey rsa:2048 -sha256 -nodes $KEY_OPT device.key -subj "$SUBJECT" -out device.csr
cat v3.ext | sed s/%%DOMAIN%%/"$COMMON_NAME"/g > /tmp/__v3.ext
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days $NUM_OF_DAYS -sha256 -extfile /tmp/__v3.ext
# move output files to final filenames
mv device.csr "$DOMAIN.csr"
cp device.crt "$DOMAIN.crt"
# remove temp file
rm -f device.crt;
echo
echo "###########################################################################"
echo Done!
echo "###########################################################################"
echo "To use these files on your server, simply copy both $DOMAIN.csr and"
echo "device.key to your webserver, and use like so (if Apache, for example)"
echo
echo " SSLCertificateFile /path_to_your_files/$DOMAIN.crt"
echo " SSLCertificateKeyFile /path_to_your_files/device.key"
v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = %%DOMAIN%%
One more step - How to make the self signed certs fully trusted in Chrome/Safari
To allow the self signed certificates to be FULLY trusted in Chrome and Safari, you need to import a new certificate authority into your Mac. To do so follow these instructions, or the more detailed instructions on this general process on the mitmproxy website:
You can do this one of 2 ways, at the command line, using this command which will prompt you for your password:
$ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain rootCA.pem
or by using the Keychain Access
app:
- Open Keychain Access
- Choose "System" in the "Keychains" list
- Choose "Certificates" in the "Category" list
- Choose "File | Import Items..."
- Browse to the file created above, "rootCA.pem", select it, and click "Open"
- Select your newly imported certificate in the "Certificates" list.
- Click the "i" button, or right click on your certificate, and choose "Get Info"
- Expand the "Trust" option
- Change "When using this certificate" to "Always Trust"
- Close the dialog, and you'll be prompted for your password.
- Close and reopen any tabs that are using your target domain, and it'll be loaded securely!
and as a bonus, if you need java clients to trust the certificates, you can do so by importing your certs into the java keystore. Note this will remove the cert from the keystore if it already exists, as it needs to to update it in case things change. It of course only does this for the certs being imported.
import_certs_in_current_folder_into_java_keystore.sh
KEYSTORE="$(/usr/libexec/java_home)/jre/lib/security/cacerts";
function running_as_root()
{
if [ "$EUID" -ne 0 ]
then echo "NO"
exit
fi
echo "YES"
}
function import_certs_to_java_keystore
{
for crt in *.crt; do
echo prepping $crt
keytool -delete -storepass changeit -alias alias__${crt} -keystore $KEYSTORE;
keytool -import -file $crt -storepass changeit -noprompt --alias alias__${crt} -keystore $KEYSTORE
echo
done
}
if [ "$(running_as_root)" == "YES" ]
then
import_certs_to_java_keystore
else
echo "This script needs to be run as root!"
fi