How to make browser trust localhost SSL certificate? [closed]
Asked Answered
M

3

15

Although, there are similar questions, and even good answers, they either don't concern themselves with localhost specifically, or ask about one particular option/solution (self-signed vs CA).

What are the options? How do they compare? Ho do I do this?

Myers answered 29/3, 2018 at 9:58 Comment(0)
M
31

tl;dr Generate a certificate issued by own CA (see the script below)

Here's what I've found. Correct me where I'm wrong.

There are CA's (certificate authorities). They issue certificates (sign CSR's) for other CA's (intermediate CA's), or servers (end entity certificates). Some of them are root authorities. They have self-signed certificates, issued by themselves. That is, usually there's a chain of trust that goes from server certificate to root certificate. And there's noone to vouch for a root certicate. As such, OS'es have a root certificate store (or trust policy store), a systemwide list of trusted root certificates. Browsers have their own lists of trusted certificates, which consist of systemwide list plus certificates trusted by the user.

In Chromium you manage certificates at chrome://settings/certificates. In Firefox, Preferences > Privacy & Security > Certificates > View Certificates. Both have Authorities tab, which is a list of trusted root certificates. And Servers tab, a list of trusted server certificates.

To obtain a certificate you create CSR (certificate signing request), send it to CA. CA signs the CSR, turning it into trusted certificate in the process.

Certificates and CSR's are a bunch of fields with information plus public key. Some of the fields are called extensions. CA certificate is a certificate with basicConstraints = CA:true.

You can inspect certificate errors in Chromium in Developer Tools > Security.

Trusting certificates systemwide

When you change OS' root certificate store, you've got to restart a browser. You change it with:

# trust anchor path/to/cert.crt
# trust anchor --remove path/to/cert.crt

trust puts CA certificates under "authority" category (trust list), or "other-entry" category otherwise. CA certificates appear in Authorities tab in browsers, or else in Servers tab.

Firefox doesn't trust server certificates from OS' root certificate store, as opposed to Chromium. Both trust CA certificates from OS' root certificate store.

Trusting certificates in a browser

In Chromium, and Firefox you can add (import) certificates to Authorities tab. If you try to import a non-CA certificate, you get "Not a Certificate Authority" message. After choosing a file, a dialog appears where you can specify trust settings (when to trust the certificate). The relevant setting for making a site work is "Trust this certificate for identifying websites."

In Chromium, you can add (import) certificates on Servers tab. But they end up either on Authorities tab (CA certificates, and you're not presented with trust settings dialog after choosing a file), or on Others tab (if non-CA certificate).

In Firefox, you can't exactly add a certificate to Servers tab. You add exceptions. And you can trust a certificate with no extensions at all (poor) there.

Self-signed certificate extensions

My system comes with the following default settings (extensions to be added) for certificates:

basicConstraints = critical,CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer

Taken from /etc/ssl/openssl.cnf, section v3_ca. More on it here.

Additionally, Chromium considers a certificate invalid, when it doesn't have subjectAltName = DNS:$domain.

Non-self-signed certificate extensions

From section [ usr_cert ] of /etc/ssl/openssl.cnf:

basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

When browsers trust a self-signed certificate

For Chromium to trust to a self-signed certificate it's got to have basicConstraints = CA:true, and subjectAltName = DNS:$domain. For Firefox not even this is enough:

basicConstraints = critical,CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
subjectAltName = DNS:$domain

When browsers trust a certificate issued by own CA

Firefox needs no extensions, but Chromium requires subjectAltName.

openssl cheat sheet

openssl genpkey -algorithm RSA -out "$domain".key - generate private key (man)

openssl req -x509 -key "$domain".key -out "$domain".crt - generate self-signed certificate (man)

Without -subj it will ask questions regarding distinguished name (DN), like common name (CN), organization (O), locality (L). You can answer them "in advance": -subj "/CN=$domain/O=$org".

To add subjectAltName extension, you've got to either have a config where it all is specified, or add a section to config and tell openssl its name with -extensions switch:

    -config <(cat /etc/ssl/openssl.cnf - <<END
[ x509_ext ]
basicConstraints = critical,CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
subjectAltName = DNS:$domain
END
    ) -extensions x509_ext

openssl req -new -key "$domain".key -out "$domain".csr - generate CSR, it can take -subj option (man)

openssl x509 -req -in "$domain".csr -days 365 -out "$domain".crt \ -CA ca.crt -CAkey ca.key -CAcreateserial - sign CSR (man)

Doesn't work without -CAcreateserial. It creates a ca.srl file, where it keeps serial number of the last generated certificate. To add subjectAltName, you're gonna need -extfile switch:

    -extfile <(cat <<END
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = DNS:$domain
END
    )

openssl req -in $domain.csr -text -noout - view CSR (man)

openssl x509 -in $domain.crt -text -noout - view certificate (man)

Generate self-signed certificate

(you're gonna need an exception in Firefox for it to work)

#!/usr/bin/env bash
set -eu
org=localhost
domain=localhost

sudo trust anchor --remove "$domain".crt || true

openssl genpkey -algorithm RSA -out "$domain".key
openssl req -x509 -key "$domain".key -out "$domain".crt \
    -subj "/CN=$domain/O=$org" \
    -config <(cat /etc/ssl/openssl.cnf - <<END
[ x509_ext ]
basicConstraints = critical,CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
subjectAltName = DNS:$domain
END
    ) -extensions x509_ext

sudo trust anchor "$domain".crt

Generate a certificate issued by own CA

#!/usr/bin/env bash
set -eu
org=localhost-ca
domain=localhost

sudo trust anchor --remove ca.crt || true

openssl genpkey -algorithm RSA -out ca.key
openssl req -x509 -key ca.key -out ca.crt \
    -subj "/CN=$org/O=$org"

openssl genpkey -algorithm RSA -out "$domain".key
openssl req -new -key "$domain".key -out "$domain".csr \
    -subj "/CN=$domain/O=$org"

openssl x509 -req -in "$domain".csr -days 365 -out "$domain".crt \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -extfile <(cat <<END
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = DNS:$domain
END
    )

sudo trust anchor ca.crt

Webserver configuration

Nginx:

server {
    listen  443  ssl;
    ssl_certificate  ssl/localhost.crt;
    ssl_certificate_key  ssl/localhost.key;
    ...

Morbo:

carton exec morbo --listen='https://*:3000?cert=localhost.crt&key=localhost.key' \
    site.pl

P.S. I'm running Chromium 65.0.3325.162, Firefox 59.0, and openssl-1.1.0.g.

Windows

Apparently, Windows doesn't have trust utility. Under Windows one has two stores: Local Machine and Current User Certificate stores. No point in using Local Machine Certificate Store, since we're making it work just for our current user. Then, there are substores. With two predefined of them being of most interest: Trusted Root Certification Authorities and Intermediate Certification Authorities Stores. Commonly referred in command line as root and CA.

You can access Chrome's Certificate Manager by following chrome://settings/?search=Manage%20certificates, then clicking Manage certificates. Of most interest are Trusted Root Certification Authorities and Intermediate Certification Authorities tabs.

One way to manager certificates is via command line:

>rem list Current User > Trusted Root Certification Authorities store
>certutil.exe -store -user root

>rem list Local Machine > Intermediate Certification Authorities store
>certutil.exe -store -enterprise CA

>rem GUI version of -store command
>certutil.exe -viewstore -user CA

>rem add certificate to Current User > Trusted Root Certification Authorities store
>certutil.exe -addstore -user root path\to\file.crt

>rem delete certificate from Current User > Trusted Root Certification Authorities store by serial number
>certutil.exe -delstore -user root 03259fa1

>rem GUI version of -delstore command
>certutil.exe -viewdelstore -user CA

The results are as follows (for both Local Machine and Current User Certificate stores):

root
    localhost.crt
        error
    ca.crt
        appears in Trusted Root Certification Authorities tab
CA
    localhost.crt
        doesn't work, appears in Other People tab
    ca.crt
        doesn't work, appears in Intermediate Certification Authorities tab

Other options would be double-clicking on a certificate in Explorer, importing certificates from Chrome's Certificate Manager, using Certificates MMC Snap-in (run certmgr.msc), or using CertMgr.exe.

For those who have grep installed, here's how to quickly check where is the certificate:

>certutil.exe -store -user root | grep "localhost\|^root\|^CA" ^
& certutil.exe -store -user CA | grep "locahost\|^root\|^CA" ^
& certutil.exe -store -enterprise root | grep "localhost\|^root\|^CA" ^
& certutil.exe -store -enterprise CA | grep "localhost\|^root\|^CA"

So, installing CA certificate into Current User > Trusted Root Certification Authorities store seems like the best option. And make sure not to forget to restart your browser.

Additional reading

OpenSSL
genpkey
req
x509
OpenSSL Certificate Authority
Certificates for localhost
iamaCA - Become your own certificate authority and dispense certifications
Firefox and Self-Signed Certs
Bypassing certificate error page in Chrome

Myers answered 29/3, 2018 at 10:6 Comment(4)
Thanks for your work. Have I right understand that now impossible to create single self-signed cert which satisfied both Firefox and Chrome?Illicit
@OlegNeumyvakin In "When browsers trust a self-signed certificate" it says that Chrome can trust a self-signed certificate. And for Firefox you can add an exception, if my memory serves me right. So that might be possible. Also, you might find interesting easy-rsa project. I've run into it setting up OpenVPN. It must simplify becoming a CA (creating CA and server certificates, in particular). Haven't tried though.Myers
This gist is useful too.Sleepyhead
This is a well thought-out, excellent answer. Certain parts just did not seem to work on my system (Debian 11). Getting the extensions and SAN on the certificate output were particularly troublesome. Some of the answers posted here did work, and might be useful to others: https://mcmap.net/q/35970/-how-to-get-ssl-certificate-to-work-with-localhost-on-firefoxMidway
S
4

On chrome, one can browse to chrome://flags/#allow-insecure-localhost and enable

Allow invalid certificates for resources loaded from localhost. option

Sutter answered 20/6, 2020 at 16:57 Comment(1)
This is merely a work-around or quickfix for those who don't have time. I would advise to turn to the accepted answer here since it is more specific and secure and learns you how to do it properly.Cataldo
S
0

You can add Root CA Certificate in Windows through Microsoft Management Console. Kindly follow the below steps to do add it.

  • Login to Windows Server.

  • Open MMC.

  • Choose File > Add/Remove Snap-ins.

  • Choose Certificates, then choose Add.

  • Choose My user account.

  • Choose Add again and this time select Computer Account.

  • Move the new certificate from the Certificates-Current User > Trusted Root Certification Authorities into Certificates (Local Computer) > Trusted Root Certification Authorities.

Snaffle answered 16/3, 2022 at 11:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.