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

52

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

Вместо этого требуется использование 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.

bcardarella
источник

Ответы:

62

Мое решение:

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

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

bcardarella
источник
2
отличное использование subshell. Я думаю, что вы можете немного упростить это:-config <(cat /System/Library/OpenSSL/openssl.cnf ; printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')
jrwren
1
Я больше не получаю ошибку Subject Alt Name, но теперь я получаю ошибку об общем имени, и установка загруженного сертификата на «всегда доверять» не работает. есть идеи? @bcardarella
регберт
2
При обновлении до Chrome 59 сертификат показывает ошибку, подобную этой: существуют проблемы с цепочкой сертификатов сайта (net :: ERR_CERT_COMMON_NAME_INVALID).
TheHarh
1
Я изменился dev.company.nameна, localhostи это сработало для обслуживания локального сайта разработки с localhost. В macOS мне также пришлось добавить сертификат в связку ключей и установить SSL «Всегда доверять».
Даниэль М.
1
Это, безусловно, самое простое решение, и оно не требует использования sslconf или установки CA.
пн.
16

В 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
STWilson
источник
13

Вот решение, которое работает для меня:

Создать ключ 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'

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

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

Для Apache2 добавьте следующее в site-file, HTTP (port 80) section

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

binary.koala
источник
Идти по пути корневого центра сертификации, который позже подписывает отдельные сертификаты, - это единственный способ, с помощью которого я могу получить полную аутентификацию chrome; также имеет то преимущество, что мне нужно было только заставить людей установить один сертификат. Спасибо
Джефф
4
Может кто-нибудь объяснить мне, почему все в этой области, кажется, используют bashisms, -config <( cat server_rootCA.csr.cnf )а не просто -config server_rootCA.csr.cnf?
Цезарь,
Можете ли вы обновить свой ответ, касающийся заголовков apache, которые могут обойти проблему (я не против, что это только для локальных сайтов для разработки, и я хотел бы получить общее решение без необходимости каждый раз создавать новые сертификаты). Можете ли вы указать, где внутри определения виртуального хоста они должны идти. Я пробовал несколько альтернатив и до сих пор не могу получить доступ к сайтам через https. Спасибо
Никос М.
12

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

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

Если вы сгенерируете запрос сертификата с помощью этой команды и проверите результат, Subject Alt Name будет присутствовать:

$ 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 и проверите результат, Subt Alt Name будет отсутствовать:

$ 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
Pavon
источник
2
Это единственное объяснение, которое помогло мне понять, почему сертификат вышел без SAN (в моем случае мне нужно было включить x509_extensions в файл конфигурации)
Даниэль Бердсмор
2

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

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

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

Патрик Мевзек
источник
1

Скрипт Bash с конфигом запекается в

В качестве сценария оболочки, который должен работать на разных платформах с bash. Предполагается, что HOSTNAMEenv установлен для оболочки или укажите имя хоста по вашему выбору, например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 включено extra, чтобы упростить тестирование через localhost. Удалите этот лишний бит из скрипта, если он вам не нужен.

кредит

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

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

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

Контрольная работа

Для способа тестирования импортируйте данные test.cert.pemв органы управления Chrome в 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
JPvRiel
источник