With the recent upgrade of Firefox 54, my self-signed localhost
SSL certificate stopped being trusted.
I've been using a Firefox AutoConfigure script to install this certificate, and the technique has been working successfully for several years. Firefox uses its own certificate store, cert8.db
which contains the certificate, verified using Firefox Preferences, Advanced, Certificates, View Certificates, Authorities.
This is reproducible on both MacOS as well as Windows. I've attached a sample certificate for reference. This is identical to one we would install.
What changed in Firefox 54? I've reviewed the changelog and can't find anything specific to how it trusts certificates.
Edit: Link to Firefox bug that most likely introduced this change: firefox
#1294580
-----BEGIN CERTIFICATE-----
MIID/DCCAuSgAwIBAgIEDZj+fTANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC
VVMxCzAJBgNVBAgTAk5ZMRIwEAYDVQQHEwlDYW5hc3RvdGExGzAZBgNVBAoTElFa
IEluZHVzdHJpZXMsIExMQzEbMBkGA1UECxMSUVogSW5kdXN0cmllcywgTExDMRww
GgYJKoZIhvcNAQkBFg1zdXBwb3J0QHF6LmlvMRIwEAYDVQQDEwlsb2NhbGhvc3Qw
HhcNMTcwMjEyMDMzMjEwWhcNMzcwMjEyMDMzMjEwWjCBmjELMAkGA1UEBhMCVVMx
CzAJBgNVBAgTAk5ZMRIwEAYDVQQHEwlDYW5hc3RvdGExGzAZBgNVBAoTElFaIElu
ZHVzdHJpZXMsIExMQzEbMBkGA1UECxMSUVogSW5kdXN0cmllcywgTExDMRwwGgYJ
KoZIhvcNAQkBFg1zdXBwb3J0QHF6LmlvMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCemwdWhvytOwhsRyEo/9ck3nKP
oBvMdkaiXKbMWlYZfYyb/EsJzw/LiEqGGhflWjneQLcgq0nuTtRaA9cm/vgPtVRX
OHewJeYBI2C4avJyjdFfQYHJKxuLi3nwmZ5JwcDm04H6SADwdyQuYB4AFr32uY5D
3id0gyDV+EX9sSOPThtdBpEbaBcFmAdAGdQUCzSJyi4Yu6UkIs7OPBHp9lOvm8VQ
r6ZVnqdFEXmxgpgMS0sQwDwZnBB3hFcVmE/sYy+2gV/h+yvRUjgqwC/SoLh9f4D0
eG19E3OEmsSyFM9K2Wl4ltOE/Aq1KFm7dPw34nDKxYcVDpm6JczWycbCi4zjAgMB
AAGjSDBGMCUGA1UdEQQeMByCCWxvY2FsaG9zdIIPbG9jYWxob3N0LnF6LmlvMB0G
A1UdDgQWBBT3Qs6/qQSmunLIGKQxz3GBO+RgIzANBgkqhkiG9w0BAQsFAAOCAQEA
lVI3sWr6wTtVtc7gsV9Kk99xNOUm5W2kp/Ot5CHvUIw68Ar1WIiouWT9BbjkvFc+
QpbtqKhluTdHI1/JP44r7A8qMApyYQLhw3AS/WTzRoOBOECJk3hYgGBIxAaoqvKY
HKCOULTqkoX8pgNhYobebn/BpeoSvXW+oxT21y7ElE01eMtrLsqXKaN5FODxVzJq
7jatxCaRZCy2Ki3R0cB5ZMIVvWSDeT1TLgh5UKWdldNsTdTNhbQSdm8ayU0uj4fH
tKqwh9lKvrBJiawghmADjZjeNEQzIJfjznF/soqVZnRNZO/phDH327lDE2UcD1IN
k4BqNRJmz5lrQeYz8GcfYA==
-----END CERTIFICATE-----
What you'll probably want to do is generate another self-signed certificate with the same subject, issuer, and public key as the one you're trying to trust. However, instead of end-entity extensions, you'll want to specify that it's a CA certificate with "basicConstraints:cA" and that it can issue certificates with "keyUsage:cRLSign,keyCertSign". It might also be a good idea to add a nameConstraints extension to restrict it to only apply to a certain set of domains. If you add that certificate to Firefox's trust DB, everything should work as before.
Inspired by the answer of @tresf and based largely on the blogpost How to Create Your Own SSL Certificate Authority for Local HTTPS Development by Brad Touesnard, I created a set of commands using
openssl
.How to use these files
1. Let your CA be trusted by your browser/keychain
Add
myCa.pem
to your browser/keychain to trust certificates signed by your new root certificate2. Sign requests with your certificate
Add
example.com.crt
andexample.com.key
to the configuration of your webserver to sign requests to your domainTo mimic the CA-chain requirements mandated by Firefox 54, the following is required:
To illustrate how this is done with Java
keytool
including the steps to create private keystores:Once this is done, only the Root-CA certificate needs to be trusted by Firefox, and can be imported using the GUI or via AutoConfig script.
The SSL server must be restarted using the new SSL private keystore, which will contain the chain of trust to work via SSL.
Since
my-ssl.jks
contains the entire chain of trustmy-ca.jks
,my-ca.crt
,my-ssl.crt
andmy-ssl.csr
can all safely be deleted (assumingmy-ca.crt
has been imported properly)As @tresf and @Zombaya have stated, Firefox requires two certificates:
The authority certificate is used to sign the development certificate. The development certificate is bound to an HTTP port. The web server listens to that port for requests.
Windows Development Environment
Other answers explain what to do in Java and Unix environments. Here's what I do in my Windows development environment. This creates certificates trusted by Firefox, Chrome, and Internet Explorer:
Override DNS with an entry in C:\Windows\System32\drivers\etc\hosts file.
Create the authority and development certificates and store them in the local machine certificate store using PowerShell. Substitute "Brainstorm" with your company name and DNS entry. Run PowerShell as an administrator.
Grant developer permission to host a website and service at specific URLs and ports (via IIS Express). Use standard SSL port for website, use another port for service. Why? IIS Express cannot simultaneously host two applications on same port differentiated by host name. They must use different ports.
If you need to remove developer permission to host website at URL:
List the certificates in Local Computer store.
Copy the thumbprint of the development certificate (not the authority certificate).
List the certificates bound to HTTP ports. (IIS Express configures ports 44300 - 44399 with its own SSL certificate.)
Copy the Application ID (it's the same for all IIS Express ports 44300 - 44399). Replace the website and service ports already bound by IIS Express with our development certificate (the certhash is the thumbprint from above). You may need to run netsh first, then enter http command, then enter add sslcert... command.
If you need to unbind certificates from HTTP ports:
In Visual Studio, configure the service's launchSettings.json file (in Properties folder):
In Visual Studio, configure the website's launchSettings.json file (in Properties folder):
Configure IIS Express (in hidden .vs/config folder):
In Firefox, navigate to about:config and set the security.enterprise_roots.enabled parameter to true.