Назад | Перейти на главную страницу

Создание самозаверяющего сертификата с помощью openssl, который работает в Chrome 58

Начиная с Chrome 58, он больше не принимает самозаверяющие сертификаты, которые полагаются на Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category$ 3ACanary% 7Csort: актуальность% 7Cspell: false

Вместо этого требуется использовать Subject Alt Name. Ранее я следовал этому руководству по созданию самозаверяющего сертификата: https://devcenter.heroku.com/articles/ssl-certificate-self который отлично работал, потому что мне требовался server.crt и server.key файлы для того, что я делаю. Теперь мне нужно создать новые сертификаты, включающие SAN однако все мои попытки сделать это не сработали с Chrome 58.

Вот что я сделал:

Я выполнил шаги из вышеупомянутой статьи Heroku, чтобы сгенерировать ключ. Затем я написал новый файл конфигурации OpenSSL:

[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = san
extensions          = san
[ req_distinguished_name ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

Затем сгенерировал server.crt с помощью следующей команды:

openssl req \
-new \
-key server.key \
-out server.csr \
-config config.cnf \
-sha256 \
-days 3650

У меня Mac, поэтому я открыл server.crt файл с Keychain, добавил его в мои системные сертификаты. Затем я установил его на Always Trust.

За исключением файла конфигурации для установки значения SAN, это были те же шаги, которые я использовал в предыдущих версиях Chrome для создания самозаверяющего сертификата и доверия к нему.

Однако после этого я все еще получаю ERR_CERT_COMMON_NAME_INVALID в Chrome 58.

Мое решение:

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.key \
    -new \
    -out server.crt \
    -subj /CN=dev.mycompany.com \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')) \
    -sha256 \
    -days 3650

Статус: работает у меня

В Windows сохраните этот сценарий в папке SSL как makeCERT.bat. Он создаст эти файлы: example.cnf, example.crt, example.key

@echo off

REM IN YOUR SSL FOLDER, SAVE THIS FILE AS: makeCERT.bat
REM AT COMMAND LINE IN YOUR SSL FOLDER, RUN: makecert
REM IT WILL CREATE THESE FILES: example.cnf, example.crt, example.key
REM IMPORT THE .crt FILE INTO CHROME Trusted Root Certification Authorities
REM REMEMBER TO RESTART APACHE OR NGINX AFTER YOU CONFIGURE FOR THESE FILES

REM PLEASE UPDATE THE FOLLOWING VARIABLES FOR YOUR NEEDS.
SET HOSTNAME=example
SET DOT=com
SET COUNTRY=US
SET STATE=KS
SET CITY=Olathe
SET ORGANIZATION=IT
SET ORGANIZATION_UNIT=IT Department
SET EMAIL=webmaster@%HOSTNAME%.%DOT%

(
echo [req]
echo default_bits = 2048
echo prompt = no
echo default_md = sha256
echo x509_extensions = v3_req
echo distinguished_name = dn
echo:
echo [dn]
echo C = %COUNTRY%
echo ST = %STATE%
echo L = %CITY%
echo O = %ORGANIZATION%
echo OU = %ORGANIZATION_UNIT%
echo emailAddress = %EMAIL%
echo CN = %HOSTNAME%.%DOT%
echo:
echo [v3_req]
echo subjectAltName = @alt_names
echo:
echo [alt_names]
echo DNS.1 = *.%HOSTNAME%.%DOT%
echo DNS.2 = %HOSTNAME%.%DOT%
)>%HOSTNAME%.cnf

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout %HOSTNAME%.key -days 3560 -out %HOSTNAME%.crt -config %HOSTNAME%.cnf

Вот решение, которое мне подходит:

Создать ключ CA и сертификат

# openssl genrsa -out server_rootCA.key 2048
# openssl req -x509 -new -nodes -key server_rootCA.key -sha256 -days 3650 -out server_rootCA.pem

Создайте server_rootCA.csr.cnf

# server_rootCA.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=DE
ST=Berlin
L=NeuKoelln
O=Weisestrasse
OU=local_RootCA
emailAddress=ikke@server.berlin
CN = server.berlin

Создайте файл конфигурации v3.ext

# v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server.berlin

Создать ключ сервера

# openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server_rootCA.csr.cnf )

Создать сертификат сервера

# openssl x509 -req -in server.csr -CA server_rootCA.pem -CAkey server_rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext

Добавить сертификат и ключ в файл сайта Apache2, раздел HTTPS (порт 443)

SSLCertificateFile    /etc/apache2/ssl/server.crt
SSLCertificateKeyFile    /etc/apache2/ssl/server.key

Скопируйте server_rootCA.pem с сервера на свой компьютер ..

# scp you@server.berlin:~/server_rootCA.pem .

.. и добавьте его в браузер Chromium

Chromium -> Setting -> (Advanced) Manage Certificates -> Import -> 'server_rootCA.pem'

ВЫ ВСЕ СДЕЛАНО!

P.S. Вместо создания функциональной пары сертификатов CA и сервера (согласно приведенным выше инструкциям) вы можете просто отключить заголовки HSTS в конфигурации вашего HTTP-сервера. Это предотвратит использование Chromium HTTPS и позволит пользователям нажимать «Дополнительно → перейти к your.url (небезопасно)» без необходимости получать и устанавливать собственный сертификат CA (server_rootCA.pem). Другими словами, отключение HSTS позволит публично просматривать ваш сайт через HTTP и / или небезопасное соединение HTTPS (будьте осторожны!).

Для Apache2 добавьте следующее в файл сайта, раздел HTTP (порт 80)

Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=0;includeSubDomains"

Протестировано на Debian / Apache2.4 + Debian / Chromium 59

https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58

Есть несколько отличных ответов, которые дают примеры того, как заставить это работать, но ни один из них не объясняет, где что-то пошло не так в вашей попытке. OpenSSL иногда может быть довольно неинтуитивным, поэтому стоит пройтись по нему.

Во-первых, в стороне, OpenSSL по умолчанию игнорирует любые значения отличительных имен, которые вы указываете в config. Если вы хотите их использовать, вы должны добавить prompt = no в вашу конфигурацию. Кроме того, написанная команда генерирует только сертификат. запрос не сертификат, поэтому -days команда ничего не делает.

Если вы сгенерируете запрос на сертификат, используя эту команду, которую вы дали, и проверите результат, присутствует альтернативное имя субъекта:

$ openssl req -new -key server.key -out server.csr -config config.cnf -sha256
$ openssl req -text -noout -in server.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:dev.mycompany.com
    Signature Algorithm: sha256WithRSAEncryption
         ...

Но затем, если вы сгенерируете сертификат с помощью команды в ссылке heroku и проверите результат, альтернативное имя субъекта отсутствует:

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
$ openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            89:fd:75:26:43:08:04:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Validity
            Not Before: Jan 21 04:27:21 2018 GMT
            Not After : Jan 21 04:27:21 2019 GMT
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ...

Причина в том, что по умолчанию OpenSSL не копирует расширения из запроса в сертификат. Обычно сертификат создается / подписывается ЦС на основе запроса от клиента, и некоторые расширения могут предоставить сертификату большую мощность, чем предполагал ЦС, если они будут слепо доверять расширениям, определенным в запросе.

Есть способы указать OpenSSL скопировать расширения, но IMHO это больше, чем просто предоставление расширений в файле конфигурации при создании сертификата.

Если вы попытаетесь использовать существующий файл конфигурации, это не сработает, потому что раздел верхнего уровня отмечен [req] поэтому эти настройки применяются только к команде req, а не к команде x509. Маркер раздела верхнего уровня не обязательно, поэтому вы можете просто удалить эту первую строку, и тогда она будет работать как для запросов, так и для сертификатов.

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt -extfile config.cnf

В качестве альтернативы вы можете использовать -x509 аргумент к req для создания самозаверяющего сертификата с помощью одной команды вместо создания сначала запроса, а затем сертификата. В этом случае нет необходимости снимать [req] строка раздела, поскольку этот раздел читается и используется командой req.

$ openssl req -x509 -sha256 -days 365 -key server.key -out server.crt -config config.cnf

Напомним, вот модифицированный файл конфигурации, используемый в приведенных выше командах:

default_bits        = 2048
distinguished_name  = dn
x509_extensions     = san
req_extensions      = san
extensions          = san
prompt              = no
[ dn ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

Мое решение - оставить главное openssl.cnf как есть и просто в конце добавить новый раздел вроде [ cert_www.example.com ] где www.example.com - это веб-сайт, для которого я хочу создать сертификат, и в нем укажите subjectAltName Мне бы понадобилось (и все остальное). Конечно, раздел можно называть как угодно.

После этого я могу запустить openssl req как и раньше, просто добавив -extensions cert_www.example.com чтобы его содержание было подобрано, и я добавляю -subj чтобы добавить непосредственно всю информацию DN.

Не забудьте проверить содержимое сертификата после его создания и перед его использованием с помощью openssl x509 -text

Bash-скрипт с запеченной конфигурацией

Как сценарий оболочки, который должен работать на разных платформах с bash. Предполагает HOSTNAME env для оболочки или укажите имя хоста по вашему выбору, например self_signed_cert.sh test

set -e

if [ -z "$1" ]; then
  hostname="$HOSTNAME"
else
  hostname="$1"
fi
    
local_openssl_config="
[ req ]
prompt = no
distinguished_name = req_distinguished_name
x509_extensions = san_self_signed
[ req_distinguished_name ]
CN=$hostname
[ san_self_signed ]
subjectAltName = DNS:$hostname, DNS:localhost
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth, timeStamping
"
    
openssl req \
  -newkey rsa:2048 -nodes \
  -keyout "$hostname.key.pem" \
  -x509 -sha256 -days 3650 \
  -config <(echo "$local_openssl_config") \
  -out "$hostname.cert.pem"
openssl x509 -noout -text -in "$hostname.cert.pem"

Вышеупомянутое более или менее вводит минимальную информацию о конфигурационном файле, необходимую openssl.

Примечание, включены дополнительные DNS:localhost в качестве SAN, чтобы упростить тестирование через localhost. Удалите этот лишний бит из сценария, если он вам не нужен.

Кредит

bcardarella ответ отличный (не могу комментировать / голосовать за недостаточную репутацию). Однако в ответе используется существующее расположение файла конфигурации openssl, которое зависит от платформы ... следовательно:

Работает для меня

Очевидно, что нужно просто найти файл конфигурации openssl для вашей собственной платформы и указать его правильное местоположение.

Тест

Чтобы проверить, импортируйте test.cert.pem в авторитеты хрома в chrome://settings/certificates, и:

openssl s_server -key test.key.pem -cert test.cert.pem -accept 20443 -www &
openssl_pid=$!
google-chrome https://localhost:20443

И после тестирования

kill $openssl_pid