Application: OpenSSL, Nginx, Apache2.
Здесь простейшая шпаргалка процедуры подготовки к приобретению SSL/TLS-сертификата, проверки его корректности и применения в web-сервисе, расширенная некоторыми пояснениями.
Генерируем закрытый и открытый ключи.
Работы с компонентами сертификата очень желательно проводить в месте, закрытом от доступа посторонних:
$ mkdir -p ./make-cert
Прежде всего необходимо создать "закрытый" (он же "приватный") и "открытый" (он же "публичный") RSA-ключи шифрования, которые в дальнейшем будут использоваться при создании всех остальных компонентов сертификата и подтверждения подлинности такового на стороне web-сервера:
$ cd ./make-cert
$ openssl genrsa -des3 -out ./example.net.key 2048
$ openssl genrsa -des3 -out ./example.net.key 2048
Мешанина символов, которую мы видим в текстовом файле ключей на самом деле представляет собой контейнер обфусцированного набора блоков сгенерированных в соответствии с алгоритмом RSA уникальных шифров, и один из этих блоков - "modulus" - является "открытым" ключём связки асимметричного шифрования, используемым во всех компонентах сертификата. Всё остальное содержимое - "закрытый" ключ.
Для ознакомления с содержимым блоков контейнера ключей его код можно раскрыть в более структурированном виде:
$ openssl rsa -noout -text -in ./example.net.key
Ключ (закрытый) шифрования по определению самое секретное, что есть в компонентах SSL-сертификата - потому по умолчанию он защищается паролем. Обязательно запоминаем введённый по запросу утилиты генерации пароль, он нам понадобится.
Надо отметить, что на практике, когда SSL-сертфикат применяется всего лишь для перевода на HTTPS ряда сайтов, большинство предпочитает не возиться с запароленным контейнером ключей, а сразу освобождает его от этой защиты, создавая рядом ещё один - "беспарольный":
$ cd ./make-cert
$ openssl rsa -in ./example.net.key -out ./example.net.key.decrypt
$ openssl rsa -in ./example.net.key -out ./example.net.key.decrypt
Создаем запрос на выпуск X.509-сертификата (CSR).
Сама по себе подсистема защиты потока трафика посредством SSL/TLS обычно реализуется на сессионных симметричных ключах, вырабатываемых web-сервером и браузером клиента при первичном согласовании соединения, и какие-то особые предустановленные ключи шифрования для этого не требуются (хотя и облегчают процедуру согласования - DH-key, например). Сертификат же (стандарта X.509), набор компонентов которого мы здесь поэтапно формируем, предназначен для своего рода подтверждения подлинности web-ресурса в интернет-инфраструктуре, где условно доверенный центр сертификации гарантирует связь указанных в сертификате "открытого" ключа и описания ресурса посредством электронной подписи содержимого такового.
Для передачи центру сертификации нашего "публичного" ключа (не всего содержимого "приватного" ключа, а лишь его блока "modulus"!) и сведений о ресурсе, подлинность которого мы подтверждаем, предназначен специальный CSR-контейнер (Certificate Signing Request). Создаём его, указывая в качестве источника "открытого" ключа контейнер таковых:
$ cd ./make-cert
$ openssl req -new -key ./example.net.key -out ./example.net.csr
$ openssl req -new -key ./example.net.key -out ./example.net.csr
В процессе потребуется указать данные о собственнике ресурса, для которого запрашивается сертификат, такие как:
"Country Name" - двухсимвольный код страны согласно ISO-3166 (RU - для России);
"State or Province Name" - название области или региона;
"Locality Name" - название города или населённого пункта;
"Organization Name" - название организации;
"Organizational Unit Name" - название подразделения (необязательное поле);
"Common Name" - полностью определённое доменное имя ресурса (FQDN), для которого запрашивается сертификат;
"Email Address" - контактный e-mail адрес администратора доменного имени (необязательное поле);
"A challenge password" - (необязательное поле, не заполняется);
"An optional company name" - альтернативное имя компании (необязательное поле, не заполняется).
"State or Province Name" - название области или региона;
"Locality Name" - название города или населённого пункта;
"Organization Name" - название организации;
"Organizational Unit Name" - название подразделения (необязательное поле);
"Common Name" - полностью определённое доменное имя ресурса (FQDN), для которого запрашивается сертификат;
"Email Address" - контактный e-mail адрес администратора доменного имени (необязательное поле);
"A challenge password" - (необязательное поле, не заполняется);
"An optional company name" - альтернативное имя компании (необязательное поле, не заполняется).
Обращаю внимание, что если действие сертификата должно распространяться на поддомены удостоверяемого ресурса, то FQDN в поле "Common Name" потребуется дополнить маской "*." ("*.example.net" - например).
Любопытствующие могут посмотреть, что скрыто в коде CSR-контейнера:
$ openssl req -noout -text -in ./example.net.csr
CSR-файл "example.net.csr" отправляем в удостоверяющий центр, у которого мы приобретаем сертификат.
Приобретение SSL/TLS-сертификата (X.509).
Нюансы выбора поставщика сертификата, процедуры оформления заказа и оплаты здесь не рассматриваются, это не технический вопрос. Один из немаловажных моментов - не пропустить выбор между сертификатом предназначенным для одного домена и "wildcard", покрывающий своими гарантиями все поддомены следующего уровня.
Генерирование самоподписанного X.509-сертификата (опционально).
Как вариант, для использования исключительно в локальной сети, можно создать требуемый сертификат самостоятельно, подписав его своим "закрытым" ключём вместо доверенного центра сертификации - так называемый "self-signed" (самоподписанный):
$ cd ./make-cert
$ openssl x509 -req -days 1095 -in ./example.net.csr -signkey ./example.net.key -out ./example.net.crt
$ openssl x509 -req -days 1095 -in ./example.net.csr -signkey ./example.net.key -out ./example.net.crt
В результате работы вышеприведённой команды в дополнение к имеющимся компонентам мы получим файл "example.net.crt" самодельного сертификата, подлинность которого нельзя проверить в интернет инфраструктуре центров сертификации, хотя функционально он нормален и применим.
Проверка корректности сертификатов и ключей.
В полученном SSL/TLS-сертификате зафиксирована как минимум следующая информация:
Версия сертификата;
Серийный номер сертификата;
Алгоритм подписи;
Полное (уникальное) имя владельца сертификата;
Открытый ключ владельца сертификата;
Дата выдачи сертификата;
Дата окончания действия сертификата;
Полное (уникальное) имя центра сертификации;
Цифровая подпись издателя.
Серийный номер сертификата;
Алгоритм подписи;
Полное (уникальное) имя владельца сертификата;
Открытый ключ владельца сертификата;
Дата выдачи сертификата;
Дата окончания действия сертификата;
Полное (уникальное) имя центра сертификации;
Цифровая подпись издателя.
Лично я всегда проверяю верность указанных в сертификате данных, декодируя и просматривая его содержимое с помощью следующей команды:
$ cd ./make-cert
$ openssl x509 -noout -text -in ./example.net.crt
$ openssl x509 -noout -text -in ./example.net.crt
На практике часто случается так, что некомпетентные клиенты или коллеги предоставляют для применения непосредственно в web-сервисах перепутанные сертификаты и ключи, не связанные между собой. Попытка применения таковых в web-сервере вызовет ошибку вроде "x509 key value mismatch".
Простейший способ проверки корректности связки "приватного" ключа, CSR-запроса и финального X.509-сертификата заключается в сверке контрольной суммы "публичного" ключа (блока "modulus"), содержащегося во всех этих контейнерах:
$ openssl rsa -noout -modulus -in ./example.net.key | openssl md5
$ openssl req -noout -modulus -in ./example.net.csr | openssl md5
$ openssl x509 -noout -modulus -in ./example.net.crt | openssl md5
$ openssl req -noout -modulus -in ./example.net.csr | openssl md5
$ openssl x509 -noout -modulus -in ./example.net.crt | openssl md5
Строка MD5-хеша короткая, и выявление различий между ними не составит труда.
Формируем типовой набор файлов сертификатов и ключей.
Обычно центры сертификации предоставляют не только запрашиваемый сертификат, а ещё и дополнительный набор промежуточных сертификатов (самого центра, его вышестоящего узла, и так вплоть до корневого узла).
В общем, в процессе у нас может скопиться несколько файлов, которые я именую соответственно их функционалу, примерно так:
"example.net.key" - контейнер с "закрытым" и "открытым" ключами (защищённый паролем);
"example.net.key.decrypt" - незащищённый паролем контейнер с "закрытым" и "открытым" ключами;
"example.net.csr" - CSR-запрос, использовавшийся при заказе сертификата;
"example.net.crt" - непосредственно наш X.509-сертификат;
"intermediate.crt" - сертификат (или цепочка таковых) центра сертификации;
"root.crt" - сертификат корневого центра, от которого начинается цепь доверия.
"example.net.key.decrypt" - незащищённый паролем контейнер с "закрытым" и "открытым" ключами;
"example.net.csr" - CSR-запрос, использовавшийся при заказе сертификата;
"example.net.crt" - непосредственно наш X.509-сертификат;
"intermediate.crt" - сертификат (или цепочка таковых) центра сертификации;
"root.crt" - сертификат корневого центра, от которого начинается цепь доверия.
Промежуточные сертификаты нам предоставлены не только для ознакомления - ими желательно дополнить предназначенный для применения в web-сервисе контейнер с нашим сертификатом, сформировав там цепочку вплоть до общеизвестного доверенного узла. Делается это простейшим добавлением текстовых кодов в конец файла:
$ cd ./make-cert
$ cat ./example.net.crt >> ./example.net-chain.crt
$ сat ./intermediate.crt >> ./example.net-chain.crt
$ cat ./root.crt >> ./example.net-chain.crt
$ cat ./example.net.crt >> ./example.net-chain.crt
$ сat ./intermediate.crt >> ./example.net-chain.crt
$ cat ./root.crt >> ./example.net-chain.crt
Обращаю внимание, что наш сертификат обязательно должен быть в начале цепочки, размещённой в контейнере - обычно web-сервер сверяет прилагаемый "закрытый" ключ с "открытым" в первом попавшемся в процессе чтения содержимого контейнера сертификате.
В Linux-е для сертификатов и ключей шифрования уже предусмотрены места в файловой системе. Распределяем файлы и защищаем их от доступа посторонних:
# mkdir -p /etc/ssl/certs
# mkdir -p /etc/ssl/private
# cp ./example.net-chain.crt /etc/ssl/certs/
# cp ./example.net.key.decrypt /etc/ssl/private/
# chown -R root:root /etc/ssl
# chmod -R o-rwx /etc/ssl
# mkdir -p /etc/ssl/private
# cp ./example.net-chain.crt /etc/ssl/certs/
# cp ./example.net.key.decrypt /etc/ssl/private/
# chown -R root:root /etc/ssl
# chmod -R o-rwx /etc/ssl
SSL-сертификат в web-сервере Nginx.
В самом простом случае применение SSL-сертификата в web-сервере "Nginx" реализуется примерно следующим образом:
# vi /etc/nginx/sites-enabled/example.net.conf
....
# Описание рабочего окружения доступного по HTTPS web-сайта
server {
listen 443 ssl;
server_name example.net;
....
# Рекомендуемые обобщённые настройки протокола
ssl on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES256-SHA:RC4:HIGH:!aNULL:!MD5:!kEDH;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:30m;
ssl_session_timeout 1h;
# Файлы сертификатов и ключей
ssl_certificate /etc/ssl/certs/example.net-chain.crt;
ssl_certificate_key /etc/ssl/private/example.net.key.decrypt;
....
}
....
# Описание рабочего окружения доступного по HTTPS web-сайта
server {
listen 443 ssl;
server_name example.net;
....
# Рекомендуемые обобщённые настройки протокола
ssl on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES256-SHA:RC4:HIGH:!aNULL:!MD5:!kEDH;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:30m;
ssl_session_timeout 1h;
# Файлы сертификатов и ключей
ssl_certificate /etc/ssl/certs/example.net-chain.crt;
ssl_certificate_key /etc/ssl/private/example.net.key.decrypt;
....
}
....
SSL-сертификат в web-сервере Apache.
В web-сервере "Apache" SSL-сертификат применяется примерно так:
# vi /etc/apache2/sites-enabled/example.net.conf
....
# Описание рабочего окружения доступного по HTTPS web-сайта
<VirtualHost example.net:443>
ServerName example.net
....
<IfModule mod_ssl.c>
# Рекомендуемые обобщённые настройки протокола
SSLEngine on
SSLProtocol all -SSLv2
SSLHonorCipherOrder on
SSLCipherSuite HIGH:MEDIUM:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!aECDH:+SHA1:+MD5:+HIGH:+MEDIUM
SSLOptions +StrictRequire
SSLCompression off
# Файлы сертификатов и ключей
SSLCertificateFile /etc/ssl/certs/example.net-chain.crt
SSLCertificateKeyFile /etc/ssl/certs/example.net.key.decrypt
</IfModule>
....
</VirtualHost>
....
# Описание рабочего окружения доступного по HTTPS web-сайта
<VirtualHost example.net:443>
ServerName example.net
....
<IfModule mod_ssl.c>
# Рекомендуемые обобщённые настройки протокола
SSLEngine on
SSLProtocol all -SSLv2
SSLHonorCipherOrder on
SSLCipherSuite HIGH:MEDIUM:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!aECDH:+SHA1:+MD5:+HIGH:+MEDIUM
SSLOptions +StrictRequire
SSLCompression off
# Файлы сертификатов и ключей
SSLCertificateFile /etc/ssl/certs/example.net-chain.crt
SSLCertificateKeyFile /etc/ssl/certs/example.net.key.decrypt
</IfModule>
....
</VirtualHost>
....