В этой заметке в деталях описывается процесс создания собственного Центра сертификации и последующая генерация сопутствующих файлов: сертификатов, запросов на сертификат и так далее. Считаем, что работаем в терминале на линукс/юникс машине с установленным openssl.
Заметка является вольным переложением на русский язык вот этой статьи (плюс мой собственный материал). Здесь описываются базовые «низкоуровневые» команды для работы с сертификатами (x509, req и т.п.)
Больше о цифровых сертификатах в других постах:
Коротко о главном¶
Удостоверяющий центр (по-английски Certification authority, сокращённо CA) — это единый центр генерации цифровых сертификатов. У конечных клиентов (например, веб-браузеров) имеется база публичных ключей разных CA и они проверяют ими приходящие, например, от сайтов сертификаты. Нас интересуют сертификаты, используемые в сеансах, защищённых протоколом SSL/TLS.
Собственно, всю процедуру можно разбить на такие шаги:
- генерим приватный ключ (сильно случайный набор байтов);
- генерим на основе приватного ключа пару сертификатов для CA (публичный и приватный);
- генерим пару сертификатов для домена, подписанных созданным на прошлом шаге CA.
Создаём CA¶
Для начала сгенерим приватный ключ (файл ca.key), если хотите зашифровать приватный ключ с паролем, добавьте аргумент -des3
:
$ openssl genrsa -out ca.key 4096
Теперь сгенерим пару сертификатов для нашего CA (вместо 365 можно подставить любое другое значение, это срок годности пары сертификатов в днях):
$ openssl req -new -x509 -days 365 -key ca.key -out ca.crt
Вводим пароль к ключу (если ключ был зашифрован) и затем аккуратно заполняем поля субъекта (subject). По этим данным можно будет потом идентифицировать публичный сертификат среди списка других, например. На выходе получаем файл ca.crt — это публичный сертификат нашего CA.
Можно создать ключ и сертификат одной командой, причём в эту же команду можно включить параметры субъекта:
$ openssl req -x509 -newkey rsa:2048 -keyout ca.key -nodes -out ca.crt -subj '/CN=example.com/L=Novosibirsk/C=RU'
К сожалению, эта команда генерит невалидный ключ. Openssl и основанные на этой библиотеке приложения его понимает корректно, однако другие программы могут его не принять. Решается это такой командой (мы просто считываем и снова записываем файл):
$ openssl rsa -in ca.key -out ca.key
Содержимое параметра -subj состоит из сегментов вида /$KEY=$VALUE
, где $KEY
может принимать такие значения:
L
— locality, обычно это городST
— state, обычно это регион, область, район и т.д.C
— country, двухбуквенный код страны, например, RU или USO
— organization, название организацииOU
— organization unit, отдел в организацииCN
— common name, обычно это адрес веб-сайтаemailAddress
— email
Создаём пару сертификатов для домена¶
Итак, у нас есть некий домен (к примеру, example.com) и мы хотим выписать для него SSL-сертификат, подписанный только что созданным CA. Сертификат дальше использовать в браузере. Шаги примерно такие же, как и в случае создания CA:
- создаём новый приватный ключ (нужен новый приватный ключ, тот, нельзя использовать тот, который мы делали для CA);
- создаём Certificate signing request (CSR), который потом нужно отправить CA;
- со стороны CA генерим сертификат на основе Certificate signing request;
- устанавливаем полученный сертификат на сервер.
Итак, генерим ключ (можете добавить -des3
, чтобы зашифровать ключ паролем):
$ openssl genrsa -out server.key 4096
Приватный ключ хранится на стороне владельца сервера и не должен никогда никому отдаваться. На базе приватного ключа server.key генерится так называемый запрос на подпись сертификата (по-английски certificate signing request (csr)), в запросе заполняются параметры субъекта (имя, адрес, домены итп), затем этот файл отправляется CA и тот создаёт сертификат на основе данных из CSR, подписывает его своим приватным ключом, в результате получаем подписанный публичный сертификат.
Вот простейший способ создать csr:
$ openssl req -new -key server.key -out server.csr
В процессе работы нужно ответить на несколько вопросов (страна, город, имя домена итп), в результате получится csr-файл, который можно отправлять CA. Однако у такого способа есть несколько существенных недостатков — запрос данных идёт по заранее заданному шаблону, в который не входят некоторые важные поля, например, subjectAltName (это расширение для включения нескольких DNS-имён в сертификат).
Единственный мне известный способ указать расширение subjectAltName — это воспользоваться собственным конфигом для openssl. Вот, например, таким:
###############################################
# Remaining options below should not be edited
###############################################
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = RU
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Russia
localityName = Locality Name (eg, city)
localityName_default = Irkutsk
organizationName = Organization Name (eg, company)
organizationName_default = Example, Co.
commonName = Common Name (eg, YOUR name or FQDN)
commonName_max = 64
[ req_ext ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
###############################################
# Edit this line to set subjectAltName contents
###############################################
subjectAltName = DNS:example.com, DNS:www.example.com, DNS:example.net
Сохраните его в файл openssl-csr.cnf и отредактируйте (нужно прописать в поле subjectAltName
свои домены, если вы в конфиге openssl разбираетесь, то можно и другие опции изменить/добавить), после чего выполните вот такую команду:
openssl req -new -key server.key -config openssl-csr.cnf -reqexts req_ext -out server.csr
Полученный файл server.csr теперь нужно «отправить» CA, чтобы там его подписали. Поскольку CA наш собственный, то подписывать будем сами. И здесь тоже есть нюанс, связанный с X509v3-расширениями — команда создания сертификата по умолчанию не включает расширения, указанные в csr (то есть указанные в csr значения для subjectAltName в сертификат не попадут). Мы пойдём по самому простому пути — будем использовать тот же конфиг (openssl-csr.cnf), что и для генерации csr, из него нам понадобится только секция [ req_ext ]
:
$ openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key -set_serial 01 -extfile openssl-csr.cnf -extensions req_ext -in server.csr -out server.crt
В данном случае «срок годности» сертификата устанавливаем в один год (365 дней).
Теперь у нас есть практически полный комплект всех нужных сертификатов. Иногда в сервере нужно использовать незашифрованный ключ, вот как его можно вытащить в файл server.key.insecure, если в server.key лежит зашифрованный ключ:
$ openssl rsa -in server.key -out server.key.insecure
Для удобства использования можно немного переименовать файлы:
$ mv server.key server.key.secure
$ mv server.key.insecure server.key
Используем сертификаты¶
Для начала полезные команды, позволяющие «посмотреть» сертификаты и csr:
$ openssl rsa -noout -text -in server.key
$ openssl req -noout -text -in server.csr
$ openssl rsa -noout -text -in ca.key
$ openssl x509 -noout -text -in ca.crt
Теперь нужно положить сгенерированные сертификаты (server.crt и server.key) в нужное место на сервере. Конкретные детали уже выходят за рамки заметки.
Чтобы браузер не ругался на сертификат, нужно добавить в его репозиторий CA только что созданный CA, а именно файл ca.crt, импортируем, смотрим, что в списке он появился. Также можно сертификат положить в общесистемный репозиторий CA-сертификатов.
Спасибо. Написано просто хорошо!
Спасибо. Ничего лишнего. Здорово
Автор, спасибо тебе большое за эту статью, очень помогла и очень вовремя.
Автор молодец!
openssl req -new -key server.key -config /etc/ssl/openssl-csr.cnf -reqexts req_ext -out server.csr
Выдает: Error opening Private Key server.key 24749:error:02001002:system library:fopen:No such file or directory:bss_file.c:356:fopen('server.key','r') 24749:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:358: unable to load Private Key
Здравствуйте !
Как решили ?
Читать невозможно. Весь текст волнами ~~~~~~~~~~. Такое впечатление, что буквы из разных шрифтов.
Спасибо за статью. Правда, еще можно немного добавить команд по генерации csr,key и crt в разных ситуациях (на лету без вопросом, с готовым ключом, с ключом без пароля, и тп.), как пишут здесь - http://sysadm.pp.ua/internet/pound-apache-nginx-ssl-setup.html
Подскажите если мне надо настроить SSL соиденение между одним сервером и множеством агентов, то при генерации ключа второй командой openssl req -new -key server.key -out server.csr вместо server.key указывать имя сервера-агента.key который будет стучатся к моему основному или же имя основного? Заранее спс
Если я правильно понял вопрос, то нужно ключ сервера указывать.
Спасибо, очень помогло