Firefox 54 прекратил доверять самоподписанным сертификатам

С недавним обновлением Firefox 54 мой самоподписанный SSL-сертификат localhost перестает доверять.

Я использую скрипт Firefox AutoConfigure для установки этого сертификата, и этот метод успешно работает уже несколько лет. Firefox использует свое собственное хранилище сертификатов, cert8.db которое содержит сертификат, проверено с помощью настроек Firefox, Advanced, Certificates, View Certificates, Authorities.

Это воспроизводится как на MacOS, так и на Windows. Я приложил образец сертификата для справки. Это идентично тому, который мы установили.

Что изменилось в Firefox 54? Я просмотрел журнал изменений и не могу найти ничего конкретного, как он доверяет сертификатам.

Изменить: Ссылка на ошибку 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-----

Ответы

Ответ 1

Чтобы имитировать требования CA-цепи, установленные Firefox 54, требуется следующее:

  1. Keypair, помеченный как 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 должен быть доверен Firefox и может быть импортирован с использованием графического интерфейса или с помощью сценария AutoConfig.

Сервер SSL должен быть перезапущен с использованием нового закрытого хранилища ключей SSL, которое будет содержать цепочку доверия для работы через SSL.

Поскольку my-ssl.jks содержит всю цепочку доверия my-ca.jks, my-ca.crt, my-ssl.crt и my-ssl.csr можно безопасно удалить (при условии, что my-ca.crt был импортирован должным образом)

Ответ 2

Вдохновленный ответом @tresf и основанный в основном на blogpost Как создать свой собственный центр сертификации SSL для локальной разработки HTTPS Брэдом Туеснаром, я создал набор команд с помощью 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 доверяют ваш браузер /keychain

Добавьте myCa.pem в свой браузер /keychain, чтобы доверять сертификатам, подписанным вашим новым корневым сертификатом

2. Подпишите запросы с вашим сертификатом

Добавьте example.com.crt и example.com.key в конфигурацию вашего веб-сервера, чтобы подписывать запросы в ваш домен.

Ответ 3

Как сообщают @tresf и @Zombaya, Firefox требует два сертификата:

  • Сертификат полномочий
  • Сертификат разработки

Сертификат полномочий используется для подписи сертификата разработки. Сертификат разработки связан с портом HTTP. Веб-сервер прослушивает этот порт для запросов.

Среда разработки Windows

Другие ответы объясняют, что делать в среде Java и Unix. Вот что я делаю в среде разработки Windows. Это создает сертификаты, которым доверяют Firefox, Chrome и Internet Explorer:

Переопределите DNS с записью в файле C:\Windows\System32\drivers\etc\hosts.

127.0.0.1  dev.brainstorm.com

Создайте сертификаты полномочий и разработки и сохраните их в хранилище сертификатов локального компьютера с помощью PowerShell. Замените "Мозговой штурм" на название вашей компании и запись в 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 настраивает порты 44300 - 44399 с собственным сертификатом SSL).

netsh http show sslcert

Скопируйте идентификатор приложения (он одинаковый для всех портов IIS Express 44300 - 44399). Замените веб-сайт и сервисные порты, уже связанные с IIS Express, нашим сертификатом разработки (certhash - это отпечаток сверху). Возможно, сначала вам нужно запустить netsh, а затем ввести команду http, а затем ввести команду 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 (в папке "Свойства"):

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

В Visual Studio настройте файл веб-сайта launchSettings.json (в папке "Свойства"):

{
  "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.

Ответ 4

То, что вы, вероятно, захотите сделать, - это создать еще один самозаверяющий сертификат с тем же предметом, эмитентом и открытым ключом, которым вы доверяете. Однако вместо расширений конечных сущностей вы хотите указать, что это сертификат CA с "basicConstraints: cA" и что он может выдавать сертификаты с помощью "keyUsage: cRLSign, keyCertSign". Также может быть хорошей идеей добавить расширение nameConstraints, чтобы ограничить его только применимым к определенному набору доменов. Если вы добавите этот сертификат в базу данных доверия Firefox, все должно работать по-прежнему.