Firefox 54 停止信任自签名证书

Firefox 54 Stopped Trusting Self-Signed Certs

最近升级了 Firefox 54,我的自签名 localhost SSL 证书不再受信任。

我一直在使用 Firefox AutoConfigure script 安装此证书,该技术已成功运行多年。 Firefox 使用自己的证书库,cert8.db 其中包含证书,使用 Firefox 首选项、高级、证书、查看证书、授权机构进行验证。

这在 MacOS 和 Windows 上都可以重现。我已附上样本证书以供参考。这与我们要安装的相同。

Firefox 54 有什么变化?我查看了 changelog,但找不到任何关于它如何信任证书的具体信息。

编辑: Link 最有可能引入此更改的 Firefox 错误: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-----

您可能想要生成另一个与您尝试信任的证书具有相同主题、颁发者和 public 密钥的自签名证书。但是,您需要指定它是 "basicConstraints:cA" 的 CA 证书,并且它可以颁发 "keyUsage:cRLSign,keyCertSign" 的证书,而不是最终实体扩展。添加 nameConstraints 扩展以将其限制为仅适用于特定的一组域也可能是个好主意。如果将该证书添加到 Firefox 的信任数据库,一切都应该像以前一样工作。

要模仿 Firefox 54 规定的 CA 链要求,需要满足以下要求:

  1. 标记为 Root-CA 的密钥对,能够生成 SSL 证书。
  2. 标记为 SSL 的第二个密钥对从 Root-CA 获得链式证书

说明如何使用 Java keytool 完成此操作,包括创建私有密钥库的步骤:

# Create a Root-CA private keystore capable of issuing SSL certificates
keytool -genkeypair -noprompt -alias my-ca -keyalg RSA -keysize 2048 -dname CN=localhost -validity 3650 -keystore .\my-ca.jks -storepass pass77 -keypass pass77 -ext ku:critical=cRLSign,keyCertSign -ext bc:critical=ca:true,pathlen:1

# Export the Root-CA certificate, to be used in the final SSL chain
keytool -exportcert -alias my-ca -keystore .\my-ca.jks -storepass pass77 -keypass pass77 -file .\my-ca.crt -rfc -ext ku:critical=cRLSign,keyCertSign -ext bc:critical=ca:true,pathlen:1

# Create a container SSL private keystore (external localhost.foo.bar dns entry optional:IE11 domain intranet policy)
keytool -genkeypair -noprompt -alias my-ssl -keyalg RSA -keysize 2048 -dname CN=localhost -validity 3650 -keystore .\my-ssl.jks -storepass pass77 -keypass pass77 -ext ku:critical=digitalSignature,keyEncipherment -ext eku=serverAuth,clientAuth -ext san=dns:localhost,dns:localhost.foo.bar -ext bc:critical=ca:false

# Create a certificate signing request (CSR) from our SSL private keystore
keytool -certreq -keyalg RSA -alias my-ssl -file .\my-ssl.csr -keystore .\my-ssl.jks -keypass pass77 -storepass pass77

# Issue an SSL certificate from the Root-CA private keystore in response to the request (external localhost.foo.bar dns entry optional)
keytool -keypass pass77 -storepass pass77 -validity 3650 -keystore .\my-ca.jks -gencert -alias my-ca -infile .\my-ssl.csr -ext ku:critical=digitalSignature,keyEncipherment -ext eku=serverAuth,clientAuth -ext san=dns:localhost,dns:localhost.foo.bar -ext bc:critical=ca:false -rfc -outfile .\my-ssl.crt

# Import Root-CA certificate into SSL private keystore
keytool  -noprompt -import -trustcacerts -alias my-ca -file my-ca.crt -keystore my-ssl.jks -keypass pass77 -storepass pass77

# Import an SSL (chained) certificate into keystore
keytool -import -trustcacerts -alias my-ssl -file my-ssl.crt -keystore my-ssl.jks -keypass pass77 -storepass pass77 -noprompt

完成后,Firefox 只需要信任 Root-CA 证书,并且可以使用 GUI 或通过 AutoConfig 脚本导入。

必须使用新的 SSL 私钥库重新启动 SSL 服务器,它将包含通过 SSL 工作的信任链。

由于 my-ssl.jks 包含整个信任链 my-ca.jksmy-ca.crtmy-ssl.crtmy-ssl.csr 都可以安全删除(假设 my-ca.crt 已正确导入)

受@tresf 的回答启发,主要基于博文How to Create Your Own SSL Certificate Authority for Local HTTPS Development Brad Touesnard,我使用 openssl.

创建了一组命令
# Generate the root key
openssl genrsa -des3 -out myCA.key 2048

# Generate a root-certificate based on the root-key
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.pem

# Generate a new private key
openssl genrsa -out example.com.key 2048

# Generate a Certificate Signing Request (CSR) based on that private key
openssl req -new -key example.com.key -out example.com.csr

# Create a configuration-file
echo \
"authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
"> example.com.conf

# Create the certificate for the webserver to serve
openssl x509 -req -in example.com.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial \
-out example.com.crt -days 1825 -sha256 -extfile example.com.conf

如何使用这些文件

1。让您的 CA 受到您 browser/keychain

的信任

myCa.pem 添加到您的 browser/keychain 以信任由您的新根证书签署的证书

2。使用您的证书签署请求

example.com.crtexample.com.key 添加到您的网络服务器配置中以签署对您域的请求

正如@tresf 和@Zombaya 所说,Firefox 需要两个证书:

  • 权威证书
  • 开发证书

权威证书用于签署开发证书。开发证书绑定到 HTTP 端口。 Web 服务器侦听该端口的请求。

Windows 开发环境

其他答案解释了在 Java 和 Unix 环境中要做什么。这是我在 Windows 开发环境中所做的。这将创建受 Firefox、Chrome 和 Internet Explorer 信任的证书:

用 C:\Windows\System32\drivers\etc\hosts 文件中的条目覆盖 DNS。

127.0.0.1  dev.brainstorm.com

创建权限和开发证书,并使用 PowerShell 将它们存储在本地计算机证书库中。将 "Brainstorm" 替换为您的公司名称和 DNS 条目。 运行 PowerShell 作为管理员。

# Create authority certificate.
# TextExtension adds the Server Authentication enhanced key usage and the CA basic contraint.
$authorityCert = New-SelfSignedCertificate `
    -Subject "CN=Brainstorm CA,OU=IT,O=Brainstorm Certificate Authority,C=US" `
    -KeyAlgorithm RSA `
    -KeyLength 4096 `
    -KeyUsage CertSign, CRLSign, DigitalSignature, KeyEncipherment, DataEncipherment `
    -KeyExportPolicy Exportable `
    -NotBefore (Get-Date) `
    -NotAfter (Get-Date).AddYears(10) `
    -HashAlgorithm SHA256 `
    -CertStoreLocation "Cert:\LocalMachine\My" `
    -FriendlyName "Brainstorm CA" `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1", "2.5.29.19={critical}{text}ca=1")


# Create development certificate.
# Sign it with authority certificate.
# TextExtension adds the Server Authentication enhanced key usage.
$devCert = New-SelfSignedCertificate `
    -Subject "CN=Brainstorm,OU=Application Development,O=Brainstorm,C=US" `
    -DnsName dev.brainstorm.com `
    -KeyAlgorithm RSA `
    -KeyLength 4096 `
    -KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `
    -KeyExportPolicy Exportable `
    -NotBefore (Get-Date) `
    -NotAfter (Get-Date).AddYears(10) `
    -HashAlgorithm SHA256 `
    -CertStoreLocation "Cert:\LocalMachine\My" `
    -FriendlyName "Brainstorm" `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1") `
    -Signer $authorityCert

# Export authority certificate to file.
$directory = "C:\Users\Erik\Documents\Temp\Certificates\"
if(!(test-path $directory))
{
New-Item -ItemType Directory -Force -Path $directory
}
$authorityCertPath = 'Cert:\LocalMachine\My\' + ($authorityCert.ThumbPrint)
$authorityCertFilename = $directory + "Authority.cer"
Export-Certificate -Cert $authorityCertPath -FilePath $authorityCertFilename

# Import authority certificate from file to Trusted Root store.
Import-Certificate -FilePath $authorityCertFilename -CertStoreLocation "Cert:\LocalMachine\Root"

# Delete authority certificate file.
Remove-Item -Path $authorityCertFilename

授予开发人员在特定 URL 和端口(通过 IIS Express)托管网站和服务的权限。网站使用标准 SSL 端口,服务使用另一个端口。为什么? IIS Express 不能同时在同一个端口上托管两个应用程序,以主机名区分。他们必须使用不同的端口。

netsh http add urlacl url=https://dev.brainstorm.com:443/ user="Erik"
netsh http add urlacl url=https://dev.brainstorm.com:44300/ user="Erik"

如果您需要取消开发人员在 URL 托管网站的权限:

netsh http delete urlacl url=https://dev.brainstorm.com:443/
netsh http delete urlacl url=https://dev.brainstorm.com:44300/

列出本地计算机存储中的证书。

Get-ChildItem -path "Cert:\LocalMachine\My"

复制开发证书(不是授权证书)的指纹。

列出绑定到 HTTP 端口的证书。 (IIS Express 使用自己的 SSL 证书配置端口 44300 - 44399。)

netsh http show sslcert

复制应用程序 ID(所有 IIS Express 端口 44300 - 44399 都相同)。用我们的开发证书替换IIS Express已经绑定的网站和服务端口(certhash是上面的指纹)。您可能需要先 运行 netsh,然后输入 http 命令,然后输入 add sslcert... 命令。

netsh http add sslcert hostnameport=dev.brainstorm.com:443 certhash=FE035397A4C44AB591A1D9D4DC0B44074D0F95BA appid={214124cd-d05b-4309-9af9-9caa44b2b74a} certstore=my
netsh http add sslcert hostnameport=dev.brainstorm.com:44300 certhash=FE035397A4C44AB591A1D9D4DC0B44074D0F95BA appid={214124cd-d05b-4309-9af9-9caa44b2b74a} certstore=my

如果您需要从 HTTP 端口解除绑定证书:

netsh http delete sslcert hostnameport=dev.brainstorm.com:443
netsh http delete sslcert hostnameport=dev.brainstorm.com:44300

在 Visual Studio 中,配置服务的 launchSettings.json 文件(在 Properties 文件夹中):

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "https://dev.brainstorm.com:44300/",
      "sslPort": 44300
    }
  },
  "profiles": {
    "Default": {
      "commandName": "IISExpress",
      "use64Bit": true
    }
  }
}

在 Visual Studio 中,配置网站的 launchSettings.json 文件(在 Properties 文件夹中):

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "https://dev.brainstorm.com/",
      "sslPort": 443
    }
  },
  "profiles": {
    "Default": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "use64Bit": true
    }
  }
}

配置 IIS Express(在隐藏的 .vs/config 文件夹中):

<sites>
  <site name="Website" id="1" serverAutoStart="true">
    <application path="/">
      <virtualDirectory path="/" physicalPath="%IIS_SITES_HOME%\WebSite" />
    </application>
    <bindings>
      <binding protocol="https" bindingInformation="*:443:dev.brainstorm.com" />
    </bindings>
  </site>
  <site name="Service" id="2">
    <application path="/">
      <virtualDirectory path="/" physicalPath="%IIS_SITES_HOME%\IIS Service" />
    </application>
    <bindings>
      <binding protocol="https" bindingInformation="*:44300:dev.brainstorm.com" />
    </bindings>
  </site>
  <siteDefaults>
    <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
    <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
  </siteDefaults>
  <applicationDefaults applicationPool="Clr4IntegratedAppPool" />
  <virtualDirectoryDefaults allowSubDirConfig="true" />
</sites>

在 Firefox 中,导航到 about:config 并将 security.enterprise_roots.enabled 参数设置为 true。