Expertus metuit
Создаём собственный CA и подписываем им сертификаты для своих ресурсов
Опубликовано 2010-02-16 в 22:36

В этой заметке в деталях описывается процесс создания собственного Центра сертификации и последующая генерация сопутствующих файлов: сертификатов, запросов на сертификат и так далее. Считаем, что работаем в терминале на линукс/юникс машине с установленным openssl.

Заметка является вольным переложением на русский язык вот этой статьи (плюс мой собственный материал). Здесь описываются базовые «низкоуровневые» команды для работы с сертификатами (x509, req и т.п.)

Больше о цифровых сертификатах в других постах:

Коротко о главном

Удостоверяющий центр (по-английски Certification authority, сокращённо CA) — это единый центр генерации цифровых сертификатов. У конечных клиентов (например, веб-браузеров) имеется база публичных ключей разных CA и они проверяют ими приходящие, например, от сайтов сертификаты. Нас интересуют сертификаты, используемые в сеансах, защищённых протоколом SSL/TLS.

Собственно, всю процедуру можно разбить на такие шаги:

  1. генерим приватный ключ (сильно случайный набор байтов);
  2. генерим на основе приватного ключа пару сертификатов для CA (публичный и приватный);
  3. генерим пару сертификатов для домена, подписанных созданным на прошлом шаге 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 или US
  • O — organization, название организации
  • OU — organization unit, отдел в организации
  • CN — common name, обычно это адрес веб-сайта
  • emailAddress — email

Создаём пару сертификатов для домена

Итак, у нас есть некий домен (к примеру, example.com) и мы хотим выписать для него SSL-сертификат, подписанный только что созданным CA. Сертификат дальше использовать в браузере. Шаги примерно такие же, как и в случае создания CA:

  1. создаём новый приватный ключ (нужен новый приватный ключ, тот, нельзя использовать тот, который мы делали для CA);
  2. создаём Certificate signing request (CSR), который потом нужно отправить CA;
  3. со стороны CA генерим сертификат на основе Certificate signing request;
  4. устанавливаем полученный сертификат на сервер.

Итак, генерим ключ (можете добавить -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-сертификатов.

Комментарии

Гость: Владимир | 2018-03-03 в 03:04

Спасибо. Написано просто хорошо!

Гость: Владимир | 2018-03-03 в 03:05

Спасибо. Ничего лишнего. Здорово

Гость: Sergey | 2014-02-15 в 23:26

Автор, спасибо тебе большое за эту статью, очень помогла и очень вовремя.

Гость: Егор | 2014-04-04 в 17:21

Автор молодец!

Гость: ReaGed | 2014-05-05 в 16:06

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

Гость: Габит | 2016-09-05 в 09:59

Здравствуйте !

Как решили ?

Гость: Читать невозможно. Весь текст волнами ~~~~~~~~~~. Такое впечатление, что буквы из разных шрифтов. | 2014-11-15 в 23:47

Читать невозможно. Весь текст волнами ~~~~~~~~~~. Такое впечатление, что буквы из разных шрифтов.

Гость: aprogrammer | 2015-01-14 в 02:06

Спасибо за статью. Правда, еще можно немного добавить команд по генерации csr,key и crt в разных ситуациях (на лету без вопросом, с готовым ключом, с ключом без пароля, и тп.), как пишут здесь - http://sysadm.pp.ua/internet/pound-apache-nginx-ssl-setup.html

Гость: Алексей | 2018-11-09 в 23:18

Подскажите если мне надо настроить SSL соиденение между одним сервером и множеством агентов, то при генерации ключа второй командой openssl req -new -key server.key -out server.csr вместо server.key указывать имя сервера-агента.key который будет стучатся к моему основному или же имя основного? Заранее спс

Sergey Stolyarov | 2018-11-10 в 18:52

Если я правильно понял вопрос, то нужно ключ сервера указывать.

Гость: Вася | 2019-09-26 в 17:44

Спасибо, очень помогло

Текст комментария (допустимая разметка: *курсив*, **полужирная**, [ссылка](http://example.com) или <http://example.com>) Посетители-анонимы, обратите внимение, что более чем одна гиперссылка в тексте (включая оную из поля «веб-сайт») приведёт к блокировке комментария для модерации. Зайдите на сайта с использованием аккаунта на twitter, например, чтобы посылать комментарии без этого ограничения.
Имя (обязательно, 50 символов или меньше)
Опциональный email, на который получать ответы (не будет опубликован)
Веб-сайт
© 2006—2024 Sergey Stolyarov | Работает на pyrengine