Enter pem pass phrase что это
Перейти к содержимому

Enter pem pass phrase что это

  • автор:

Что такое Private Key

Для безопасной передачи данных в Интернет используется криптографический протокол SSL ( Secure Sockets Layer — уровень защищённых сокетов). Для работы с ним можно воспользоваться специальным криптографическим пакетом OpenSSL. Данный продукт является открытым и свободно распространяется как в виде исходных кодов, так и в виде бинарных пакетов. Он применяется для создания сертификатов X.509, ключей DSA, RSA, DH, формирования CSR и CRT и т.д. Пакет OpenSSL по умолчанию включен в большинство дистрибутивов Unix-подобных систем (Linux, BSD, Solaris и т.п). Кроме того, его всегда можно получить на официальном сайте https://www.openssl.org/.

Создание Private Key

Private key (частный ключ) — специальный 2048 битный ключ для шифрования по алгортму RSA. PrivateKey работает совместно с с SSL сертификатом, обеспечивая защищенное HTTPS соединение между сервером и его посетителем. Для созданияPrivate key на сервере необходимо выполнить следующую команду:

openssl genrsa -des3 -out /root/security_patch/private.key 2048

*/root/security_patch/private.key — это путь к директории, в которой хранятся Ваши сертификаты. Данная команда запускает диалог, который попросит Вас ввести пароль для формирования ключа. Далее потребуется подтверждение пароля — просто введите его еще раз. Обратите внимание, что в целях безопасности, во время ввода пароля символы на экране не будут отображаться, а курсор — смещаться. Пример сессии представлен ниже.

# openssl genrsa -des3 -out /root/serts/private.key 2048 Generating RSA private key, 1024 bit long modulus . ++++++ . ++++++ e is 65537 (0x10001) Enter pass phrase for /root/security_patch/private.key: Verifying - Enter pass phrase for /root/security_patch/private.key:

В результате будет создан файл private.key:
*Обязательно сделайте резервную копию этого ключа на своем личном компьютере, сменном носителе и т.п. В случае его утраты, сертификат перестанет работать.

Пример Private key RSA

Полученый Private key используется для созданмя CSR-запроса, который необходим для получения сертификата подписанного в сертификационном центре. Для генерации запроса CSR необходимо выполнить в консоли сервера команду

openssl req -new -key /root/security_patch/private.key -out /root/security_patch/request.csr

/root/security_patch/private.key — путь к файлу приватного ключа.
/root/security_patch/request.csr — путь по которому будет создан файл запроса сертификата

NO russia - мы не осблуживаем резидентов из россии

Copyright © 1997-2023 adgrafics

Генерация ключа

Сначала, с помощью команды cd , перейдите в каталог /etc/httpd/conf . Удалите фиктивный ключ и сертификат, созданные во время установки, выполнив следующие команды:

rm ssl.key/server.key rm ssl.crt/server.crt

Затем, вы должны создать собственный случайный ключ. Введите следующую команду:

На экране компьютера появится подобное сообщение:

umask 77 ; \ /usr/bin/openssl genrsa -des3 1024 > /etc/httpd/conf/ssl.key/server.key Generating RSA private key, 1024 bit long modulus . ++++++ . ++++++ e is 65537 (0x10001) Enter PEM pass phrase:

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

Замечание

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

Вам будет предложено ввести пароль повторно, чтобы подтвердить его правильность. Как только вы сделает это, будет создан файл server.key , содержащий ваш ключ.

Обратите внимание, если вы не хотите вводить пароль при каждом запуске вашего безопасного веб-сервера, вместо команды make genkey вы можете выполнить следующие две команды. Каждая команда должна располагаться в одной строке.

Выполните следующую команду:

/usr/bin/openssl genrsa 1024 > /etc/httpd/conf/ssl.key/server.key

чтобы создать свой ключ. Затем выполните эту команду:

chmod go-rwx /etc/httpd/conf/ssl.key/server.key

чтобы установить для этого ключа правильные разрешения.

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

Внимание

Отключение пароля для веб-сервера представляет собой угрозу безопасности. НЕ рекомендуется отключать использование пароля на вашем безопасном веб-сервере.

В зависимости от защищенности вашего компьютера, у вас могут возникнуть проблемы, связанные с отключением пароля. Например, если злоумышленник взломает систему безопасности UNIX на этом компьютере, он сможет получить ваш закрытый ключ (содержимое файла server.key ). Этот ключ затем может быть использован для фальсификации веб-страниц, и компрометации вашего сервера.

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

Файл server.key должен принадлежать пользователю root и не должен быть доступен другим пользователям. Сделайте резервную копию этого файла и сохраните её в безопасном, защищённом месте. Эта копию необходимо сохранить, так как если вы утеряете файл server.key , сформировав до этого с его помощью запрос на получение сертификата, ваш сертификат больше не будет работать и центр сертификации ничем не сможет вам помочь. В таком случае вы сможете только запросить (и оплатить) получение нового сертификата.

Если вы собираетесь приобрести сертификат в центре сертификации, перейдите к разделу Формирование запроса к центру сертификации на получение сертификата . Если вы самостоятельно выдаёте себе сертификат, перейдите к разделу Самостоятельное формирование сертификата .

Назад Начало Вперед
Виды сертификатов Вверх Формирование запроса к центру сертификации на получение сертификата

Enter pem pass phrase что это

Проверка версии OpenSSL

Определение используемой версии OpenSSL является важным первым шагом в подготовке генерации приватного ключа и запроса CSR. Ваша версия OpenSSL диктует криптографический алгоритм, который может использовать для генерации ключей и поддерживаемый протокол. К примеру, OpenSSL version 1.0.1 является первой версией, поддерживающей TLS 1.1 и TLS 1.2. Знание используемой версииf OpenSSL также важно когда вы решаете возникшие в процессе проблемы.

Команда для определения версии OpenSSL:

openssl version -a

В этой команде, » -a » включит отображение следующей информации:

  • Номер версии и дата выхода (OpenSSL 1.0.2g 1 Mar 2016).
  • Опции библиотеки (options).
  • название директории где находятся сертификат и приватные ключи (OPENSSLDIR).

При вводе команды openssl version -a появится информация такого вида:

OpenSSL 1.0.2g 1 Mar 2016 built on: reproducible build, date unspecified platform: debian-amd64 options: bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx) compiler: cc -I. -I.. -I../include -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS - D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -g -O2 -fstack-protector- strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wl,- Bsymbolic-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int - DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 - DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM - DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM OPENSSLDIR: "/usr/lib/ssl"

OpenSSL and CSR Creation

Первым шагом к получению SSL-сертификата является использование OpenSSL для создания запроса подписи сертификата (CSR), который может быть отправлен в центр сертификации (CA) (например, DigiCert). CSR содержит общее имя (ы), которое вы хотите, чтобы ваш сертификат был защищен, информация о вашей компании и ваш открытый ключ. Чтобы создать CSR, он должен иметь закрытый ключ, из которого извлекается открытый ключ. Это можно сделать, используя существующий закрытый ключ или создав новый закрытый ключ.

Примечание по безопасности. Из-за проблем с безопасностью, связанных с использованием существующего закрытого ключа, а также потому, что очень просто и совершенно бесплатно создавать закрытый ключ, мы рекомендуем создавать новый закрытый ключ при создании CSR.

Выбор вариантов генерации ключей

При создании ключа вы должны решить три вещи:

  • Алгоритм ключа Key Algorithm,
  • размер ключа Key Size
  • использование кодовой фразы Passphrase

Для ключевого алгоритма вам необходимо учитывать его совместимость. По этой причине мы рекомендуем использовать RSA. Однако, если у вас есть конкретная необходимость использовать другой алгоритм (например, ECDSA), вы также можете использовать его, но помните о проблемах совместимости, с которыми вы можете столкнуться.

Примечание. В этом руководстве рассматриваются только генераторы ключей с использованием алгоритма RSA.

Для размера ключа вам необходимо выбрать длину бита не менее 2048 при использовании RSA и 256 при использовании ECDSA; это самый маленький размер ключа, разрешенные для сертификатов SSL. Если вам не нужен более крупный размер ключа, мы рекомендуем придерживаться 2048 с RSA и 256 с ECDSA.

Примечание. В старых версиях OpenSSL, если не задан размер ключа, используется размер ключа по умолчанию 512. Любой размер ключа ниже 2048 считается незащищенным и никогда не должен использоваться.

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

Создание приватного ключа

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

Используйте следующую команду для генерации вашего закрытого ключа с использованием алгоритма RSA:

openssl genrsa -out yourdomain.key 2048

Эта команда генерирует закрытый ключ в вашем текущем каталоге с именем yourdomain.key (-out yourdomain.key) с использованием алгоритма RSA (genrsa) с длиной ключа 2048 бит (2048). Сгенерированный ключ создается с использованием формата OpenSSL под названием PEM.

Используйте следующую команду для просмотра необработанного, закодированного содержимого (формат PEM) закрытого ключа:

cat yourdomain.key

Несмотря на то, что содержимое файла может выглядеть как случайный фрагмент текста, на самом деле он содержит важную информацию о ключе. Используйте следующую команду для декодирования закрытого ключа и просмотра его содержимого:

openssl rsa -text -in yourdomain.key -noout

Переключатель -noout отключает вывод кодированной версии закрытого ключа.

Извлечение открытого ключа

Файл закрытого ключа содержит как закрытый ключ, так и открытый ключ. Вы можете извлечь свой открытый ключ из своего файла закрытого ключа, если это необходимо.

Используйте следующую команду для извлечения открытого ключа:

openssl rsa -in yourdomain.key -pubout -out yourdomain_public.key

Создание CSR

После создания секретного ключа вы готовы создать свою CSR. CSR создается с использованием формата PEM и содержит часть открытого ключа закрытого ключа, а также информацию о вас (или вашей компании).

Используйте следующую команду для создания CSR с использованием только что созданного закрытого ключа:

openssl req -new -key yourdomain.key -out yourdomain.csr

После ввода команды вам будет задан ряд вопросов. Ваши ответы на эти вопросы будут включены в CSR. Ответьте на вопросы, как описано ниже:

Country Name (2 letter code) The two-letter country code where your company is legally located.
State or Province Name (full name) The state/province where your company is legally located.
Locality Name (e.g., city) The city where your company is legally located.
Organization Name (e.g., company) Your company’s legally registered name (e.g., YourCompany, Inc.).
Organizational Unit Name (e.g., section) The name of your department within the organization. (You can leave this option blank; simply press Enter.)
Common Name (e.g., server FQDN) The fully-qualified domain name (FQDN) (e.g., www.example.com).
Email Address Your email address. (You can leave this option blank; simply press Enter.)
A challenge password Leave this option blank (simply press Enter).
An optional company name Leave this option blank (simply press Enter).

Некоторые из вышеуказанных вопросов CSR имеют значения по умолчанию, которые будут использоваться, если вы оставите пустой ответ и нажмите Enter. Эти значения по умолчанию извлекаются из файла конфигурации OpenSSL, расположенного в OPENSSLDIR (см. Проверка версии OpenSSL). Если вы хотите оставить вопрос пустым, не используя значение по умолчанию, введите «.». (период) и нажмите Enter.

Использование переключателя -subj

Другим вариантом при создании CSR является предоставление всей необходимой информации внутри самой команды с помощью -subj-переключателя.

Используйте следующую команду, чтобы отключить приглашения к запросам при создании CSR:

openssl req -new -key yourdomain.key -out yourdomain.csr \ -subj "/C=US/ST=Utah/L=Lehi/O=Your Company, Inc./OU=IT/CN=yourdomain.com"

This command uses your private key file (-key yourdomain.key) to create a new CSR (-out yourdomain.csr) and disables question prompts by providing the CSR information (-subj).

Создание CSR с помощью одной команды

Вместо того, чтобы генерировать закрытый ключ, а затем создавая CSR двумя разными шагами, вы можете одновременно выполнять обе задачи.

Используйте следующую команду для создания как закрытого ключа, так и CSR:

openssl req -new \ -newkey rsa:2048 -nodes -keyout yourdomain.key \ -out yourdomain.csr \ -subj "/C=US/ST=Utah/L=Lehi/O=Your Company, Inc./OU=IT/CN=yourdomain.com"

Эта команда генерирует новый закрытый ключ (-newkey) с использованием алгоритма RSA с длиной ключа 2048 бит (rsa: 2048) без использования парольной фразы (-nodes), а затем создает файл ключа с именем yourdomain.key (- keyout yourdomain.key). Затем команда cгенерирует CSR с именем файла yourdomain.csr (-out yourdomain.csr), информация для CSR предоставляется (-subj).

Примечание. Хотя возможно добавление альтернативного имени объекта (SAN) в CSR с использованием OpenSSL, процесс немного сложнее. Если вам нужно добавить SAN в свой сертификат, это легко сделать, добавив их в виде примечания в форму заказа при покупке вашего сертификата ssl.

Проверка информации CSR

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

Используйте следующую команду для просмотра информации в вашей CSR перед отправкой ее в сертификационный центр.

openssl req -text -in yourdomain.csr -noout -verify

Переключатель -noout отключает вывод кодированной версии CSR. Переключатель -verify проверяет подпись файла, чтобы убедиться, что он не был изменен. Выполнение этой команды дает вам следующий результат:

verify OK Certificate Request: Data: Version: 0 (0x0) Subject: C=US, ST=Utah, L=Lehi, O=Your Company, Inc., OU=IT, CN=yourdomain.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:bb:31:71:40:81:2c:8e:fb:89:25:7c:0e:cb:76: [. 17 lines removed] Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha256WithRSAEncryption 0b:9b:23:b5:1f:8d:c9:cd:59:bf:b7:e5:11:ab:f0:e8:b9:f6: [. 14 lines removed]

В первой строке выведенного выше вы увидите, что CSR была проверена (verify OK).

В четвертой строке поле Subject: содержит информацию, предоставленную вами при создании CSR. Убедитесь, что эта информация верна.

Если какая-либо информация неверна, вам нужно будет создать совершенно новІй запрос CSR для исправления ошибок. Это связано с тем, что файлы CSR имеют цифровую подпись, что означает, что даже если в файле изменяется один символ, он будет отклонен центром сертификации.

Отправка CSR в CA

Когда вы подготовите запрос CSR для оформления сертификата SSL, вам нужно использовать формат PEM — необработанный, закодированный текст CSR, который вы увидите при открытии его в текстовом редакторе.

Для того, чтобы просмотреть исходный вывод CSR:

cat yourdomain.csr

Вам надо скопировать содержимое (включая ——BEGIN CERTIFICATE REQUEST—— и ——END CERTIFICATE REQUEST—— вместе с черточками) вставить в текстовый документ и направить в компанию, которая оформляет для вас сертификат ssl.

Просмотр информации о сертификате

После получения сертификата от CA (например, DigiCert) мы рекомендуем убедиться, что информация в сертификате верна и соответствует вашему закрытому ключу. Вы делаете это, используя команду x509.

Используйте следующую команду для просмотра содержимого вашего сертификата:

openssl x509 -text -in yourdomain.crt -noout

Проверка соответствия ваших ключей

Чтобы проверить соответствие ваших общих и закрытых ключей, используйте ключ -modulus для генерации хэша вывода для всех трех файлов (закрытый ключ, CSR и сертификат).

Используйте следующие команды для генерации хэша модуля каждого файла:

openssl rsa -modulus -in yourdomain.key -noout | openssl sha256
openssl req -modulus -in yourdomain.csr -noout | openssl sha256
openssl x509 -modulus -in yourdomain.crt -noout | openssl sha256

Примечание. Вышеприведенные команды должны вводиться один за другим для генерации трех отдельных выходов.

Каждая команда выведет (stdin) =, а затем строку символов. Если результат каждой команды соответствует, то ключи для каждого файла одинаковы.

Однако, если есть какое-либо несоответствие, то ключи не совпадают, и сертификат не может быть установлен.

Ошибки рассогласования ключей обычно вызваны установкой сертификата на машине, отличной от той, которая используется для генерации CSR. Если вы столкнулись с ошибкой несоответствия ключа, вам необходимо выполнить одно из следующих действий:

  • Перенесите закрытый ключ из машины, используемой для генерации CSR, к тому, к которому вы пытаетесь установить сертификат.
  • Установите сертификат на машине с помощью закрытого ключа.
  • Создайте совершенно новый ключ и создайте новый CSR на машине, которая будет использовать сертификат.

Преобразование форматов сертификатов

По умолчанию OpenSSL генерирует ключи и CSR, используя формат PEM. Однако могут быть случаи, когда вам нужно преобразовать свой ключ или сертификат в другой формат, чтобы экспортировать его в другую систему.

PEM для PKCS # 12

Формат PKCS # 12 представляет собой архивный файл, в котором хранятся как сертификат, так и закрытый ключ. Этот формат полезен для переноса сертификатов и ключей из одной системы в другую, так как содержит все необходимые файлы. Файлы PKCS # 12 используют либо расширение .pfx, либо .p12.

Используйте следующую команду для преобразования вашего ключа PEM и сертификата в формат PKCS # 12 (т. Е. Один файл .pfx):

openssl pkcs12 -export -name "yourdomain-digicert-(expiration date)" \ -out yourdomain.pfx -inkey yourdomain.key -in yourdomain.crt

Примечание. После ввода команды вам будет предложено указать пароль для шифрования файла. Поскольку формат PKCS # 12 часто используется для миграции системы, мы рекомендуем шифровать файл с помощью очень надежного пароля. Эта команда объединяет ваш закрытый ключ (-inkey yourdomain.key) и ваш сертификат (-in yourdomain.crt) в один файл .pfx (-out yourdomain.pfx) с дружественным именем (-name «yourdomain-digicert- (expiration дата) «), где дата истечения срока действия сертификата истекает.

PKCS № 12 для PEM

Поскольку формат PKCS # 12 содержит как сертификат, так и закрытый ключ, вам нужно использовать две отдельные команды для преобразования файла .pfx в формат PEM.

Используйте следующую команду, чтобы извлечь закрытый ключ из файла PKCS # 12 (.pfx) и преобразовать его в закрытый ключ, закодированный PEM:

openssl pkcs12 -in yourdomain.pfx -nocerts -out yourdomain.key -nodes

Используйте следующую команду для извлечения сертификата из файла PKCS # 12 (.pfx) и преобразования его в сертификат, закодированный PEM:

openssl pkcs12 -in yourdomain.pfx -nokeys -clcerts -out yourdomain.crt

Примечание. Вам необходимо указать пароль, используемый для шифрования файла .pfx, чтобы преобразовать ключ и сертификат в формат PEM.

Формат DER использует кодировку ASN.1 для хранения сертификата или ключевой информации. Подобно формату PEM, DER хранит информацию о ключах и сертификатах в двух отдельных файлах и обычно использует те же расширения файлов (то есть .key, .crt и .csr). Расширение файла .der было использовано в приведенных ниже примерах для ясности.

Используйте следующую команду для преобразования сертификата, закодированного в PEM, в сертификат, закодированный DER:

openssl x509 -inform PEM -in yourdomain.crt -outform DER -out yourdomain.der

Используйте следующую команду для преобразования закрытого ключа, закодированного в PEM, в закрытый закрытый ключ DER:

openssl rsa -inform PEM -in yourdomain.key -outform DER -out yourdomain_key.der

DER to PEM Используйте следующую команду для преобразования закодированного DER сертификата в сертификат, закодированный PEM:

openssl x509 -inform DER -in yourdomain.der -outform PEM -out yourdomain.crt

Используйте следующую команду для преобразования закрытого ключа с кодировкой DER в закрытый секретный ключ PEM:

openssl rsa -inform DER -in yourdomain_key.der -outform PEM -out yourdomain.key

Теория¶

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

Что такое openssl¶

OpenSSL — это опенсорсный набор библиотек и программ для работы с SSL/TLS и некоторыми распространёнными криптоалгоритмами. В этой статье мы будем работать только с программой openssl, она представляет собой коллекцию утилит (команд) для операций над крипто-объектами: ключами, сертификатами, зашифрованными данными.

OpenSSL — очень старая система, в ней огромное количество legacy-кода и legacy-интерфейсов. Различные команды из её состава принимают разные аргументы и имеют разную логику работы. Команд этих очень много и я не буду рассказывать о них, вместо этого я сфокусируюсь на конкретных задачах, в рамках которых буду давать примеры использования команд для её решения. Иногда путей для решения задачи будет несколько.

Что такое и зачем нужны сертификаты¶

Для начала определимся, что вообще означает слово сертификат. В бытовом понимании это специальный документ, удостоверяющий какой-нибудь факт, знание или компетенцию; причём важно, что документ выдан конкретной (сертифицирующей) организацией. У этого документа есть признаки, по которым можно проверить, что он действительный и не поддельный. Например, уникальный номер, печать организации, подпись ответственного лица, срок действия и так далее. Важно, что имеются чётко определённые процедуры верификации сертификата, например, сравнение подписи, печати, запрос в организацию по номеру и так далее.

В русском языке слово сертификат употребляется наравне со словами удостоверение, свидетельство; особенно это характерно для бюрократии, официальных текстов и государственных стандартов. Например, в российской Системе документов по аккредитации в документе СДА 06-2009 используется такое определение:

Удостоверение (сертификат) — документ, выданный органом по сертификации персонала, удостоверяющий компетентность специалиста в определенной области испытаний в соответствии с присвоенным уровнем квалификации.

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

Термин цифровой сертификат (digital certificate) означает, что первичная его форма — в виде байтов на диске, памяти компьютера, на носителе информации. Цифровой сертификат можно легко скопировать и полученная копия будет обладать всеми его свойствами. В основе цифровых сертификатов лежит криптография, именно с помощью криптоалгоритмов происходит работа с сертификатом на всех этапах его жизненного цикла: создание, использование, уничтожение. Без знания основ криптографии, хотя бы самых элементарных, невозможно полноценно понять суть и смысл цифровых сертификатов, поэтому я про них тоже расскажу.

В дальнейшем я под словом сертификат буду подразумевать исключительно цифровой сертификат.

Основы криптографии¶

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

Википедия нам даёт такое определение:

Криптогра́фия (от др.-греч. κρυπτός «скрытый» + γράφω «пишу») — наука о методах обеспечения конфиденциальности (невозможности прочтения информации посторонним), целостности данных (невозможности незаметного изменения информации), аутентификации (проверки подлинности авторства или иных свойств объекта), шифрования (кодировка данных).

Все эти аспекты используются при работе с сертификатами. Начнём с шифрования, в упрощённой форме это процесс преобразования открытого текста в зашифрованный и наоборот, из зашифрованного в открытый — этот процесс называется дешифрованием, дешифровкой, расшифровкой. Шифрование и дешифрование работают на самом деле с произвольными наборами байтов, поэтому фразу открытый текст нужно воспринимать как открытый набор байтов.

В криптографии принято алгоритм алгоритм шифрования/дешифрования называть просто шифр (cipher). Считается, что шифр сам по себе не может быть секретным, его алгоритм должен быть общеизвестным, а секретность обеспечиваться ключом — специальным набором байтов, который определяет, как именно алгоритм будет зашифровывать/расшифровывать данные. Общеизвестность нужна для того, чтобы шифр могли исследовать специалисты, подтверждая или опровергая его надёжность.

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

Важным для нас вариантом асимметричного шифра является криптосистема с открытым ключом (public-key cryptography). В её основе лежат такие принципы:

  • ключ состоит из двух компонентов: закрытого ключа / private key (предполагается, что он секретный и тщательно охраняется) и открытого ключа / public key (который может и должен распространяться свободно по любым каналам);
  • открытый ключ вычисляется из закрытого простым способом, а вот обратная процедура (вычисление закрытого ключа из открытого) является чрезвычайно сложной, затратной и невыполнимой за разумное время на любом доступном оборудовании;
  • существует открытые, общеизвестные и надёжные алгоритмы, которые используют закрытый и открытый ключ для криптографических операций, например, для шифрования/дешифрования.

Часто закрытый ключ также называют приватным или секретным, открытый ключ называют публичным, но я в тексте буду придерживаться терминов закрытый/открытый.

Первая схема использования пары закрытого и открытого ключей — шифрование: отправитель шифрует текст, затем отправляет получателю зашифрованный текст через открытый канал, а получатель их расшифровывает снова в открытый текст. Эта схема предназначена для защиты информации, вот что для неё требуется:

  • предполагается, что у отправителя уже есть открытый ключ, а у получателя — закрытый (парный к открытому, естественно);
  • отправитель при помощи открытого ключа и алгоритма (шифра) шифрует данные и отправляет результат через открытые каналы;
  • получатель при помощи закрытого ключа расшифровывает данные и восстанавливает исходный текст.

Поскольку открытый ключ общеизвестен, любой человек может зашифровать при помощи него сообщение, а дальше подменить оригинальное. У получателя нет никакого способа автоматически проверить (то есть аутентифицировать), что полученное им сообщение не было изменено и пришло именно от нужного отправителя. И тут на помощь приходит вторая схема использования пары ключей — цифровая подпись / digital signature. Она используется для подтверждения авторства сообщения, то есть для аутентификации. Вот пример:

  • у отправителя файла (и только у него!) есть доступ до закрытого ключа, а открытый ключ является публичным и доступен в том числе получателю;
  • отправитель берёт файл и при помощи алгоритма подписи и закрытого ключа создаёт цифровую подпись — ещё один набор байтов в виде отдельного файла, который отправляется получателю вместе с оригинальным текстовым файлом по открытому каналу;
  • получатель берёт текстовый файл и файл подписи и при помощи алгоритма проверки цифровой подписи и открытого ключа верифицирует, создана ли эта подпись закрытым ключом, парой которому является данный открытый ключ.

Алгоритм подписи чаще всего оперирует не с сообщением целиком, а с его дайджестом (digest), то есть «сжатым» при помощи алгоритма криптографического хеширования (например, SHA-1 или гостовского СТРИБОГ). И в целом схема выглядит так:

Схема работы цифровой подписи

На практике байты цифровой подписи и байты собственно исходного (подписанного) сообщения укладываются в один файл-контейнер, но важно понимать, что в процессе верификации они разделяются. Цифровая подпись обычно достаточно короткая, порядка нескольких сотен байтов максимум.

Во многих статьях (например, здесь) можно встретить некорректное и устаревшее описание цифровой подписи, в нём она является зашифрованным с помощью закрытого ключа дайджестом, а соответственно верификация производится расшифровкой подписи с помощью открытого ключа и последующим сравнением результата с отдельно подсчитанным на стороне получателя дайджестом сообщения. Такой процесс возможен для RSA, почти во всех остальных криптосистемах шифрование собственно открытыми/закрытыми ключами принципиально не поддерживается, а поддерживается только создание цифровой подписи. Однако для организации защищённого канала этого достаточно и я ниже в разделе Используемые криптоалгоритмы подробно расскажу, как при помощи произвольного алгоритма цифровой подписи организовать безопасное шифрование и дешифрование данных. А в практическом разделе расскажу, как это сделать командами openssl.

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

Использование криптографии в X.509-сертификатах¶

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

Существует несколько бинарных форматов для представления сертификатов, однако в абсолютном большинстве случаев вам придётся иметь дело с X.509-сертификатами. Все остальные форматы нишевые и я про них здесь не буду рассказывать.

X.509 — это технический стандарт, определяющий формат для сертификата с открытым ключом, то есть для такого сертификата, в информационном блоке которого записан (помимо других данных) открытый ключ. Как правило вместе с открытым ключом указываются личные данные / identity персоны или организации, владеющей соответствующим закрытым ключом.

Существует также набор стандартов для криптографии с открытым ключом PKCS (Public Key Cryptography Standards). На данный момент в нём 15 стандартов, их принято обозначать как PKCS#1, PKCS#2 и т.д. С полным списком можно ознакомиться в википедии: https://en.wikipedia.org/wiki/PKCS, а я в тексте буду на нужные мне части ссылаться по мере необходимости.

Изначально стандарты семейства PKCS разрабатывались компанией RSA Security LLC в целях рекламы крипто-алгоритмов, патенты на которые были на руках у компании, поэтому в индустрии отношение к этому наборы было и остаётся настороженным.

В середине девяностых IETF и NIST сформировали рабочую группу Public-Key Infrastructure (X.509), которая позднее стала называться просто PKIX. В рамках рабочей группы были разработаны стандарты, детально описывающие, как нужно использовать X.509 на практике: RFC 3280 и его наследник RFC 5280.

Для описания структуры используемых данных чрезвычайно широко используется стандарт Abstract Syntax Notation One (ASN.1), фактически все типы данных в прикладной криптографии описаны через ASN.1-нотацию.

Используемые криптоалгоритмы¶

В инфраструктуре открытых ключей чаще всего используются RSA, DSA и ECC.

  • RSA — криптосистема, названная по первым буквам имён её создателей: Rivest-Shamir-Adleman. В основе её теории лежит сложная задача факторизации (разделения на множители) произведения двух очень больших простых чисел. Выбирается два случайных очень больших простых числа p и q, их произведение n = p · q называется модулем / modulus и длина модуля в битах задаёт длину закрытого ключа. Чем больше длина, тем более надёжным считается ключ. Также выбирается сравнительно небольшое простое число e (чаще всего это 65537), называемое открытой экспонентой / public exponent. Дальше из модуля n вычисляется по специальному алгоритму (который я тут не буду объяснять) закрытая экспонента / private exponent. В итоге формируется открытый ключ в виде пары чисел (e, n) и закрытый ключ в виде пары (d, n). Этот алгоритм долгое время был самым распространённым и по умолчанию фигурировал во всех инструкциях и мануалах. Однако в середине девяностых был разработан алгоритм для квантовых компьютеров, выполняющий факторизацияю чисел. Хотя квантовых компьютеров ещё нет, но теперь RSA считается потенциально слабым, если длина закрытого ключа меньше 2048 бит. RSA содержит алгоритмы как для шифрования, так и для цифровой подписи.
  • DSA — криптографический алгоритм, названием расшифровывается как Digital Signature Algorithm, то есть алгоритм цифровой подписи. Он основан на математической теории возведения в степень по модулю и задаче дискретного логарифмирования. В отличие от RSA, этот алгоритм может использоваться только для подписывания данных, но не для их шифрования. Исторически DSA использовался и продолжает использовать в операциях с государственными органами США, однако нас он не интересует, поэтому больше о нём не будем, просто имейте в виду, что он поддерживается при создании сертификатов тоже. DSA может использоваться только для цифровой подписи.
  • ECC (или просто EC) — набор криптосистем на основе теории эллиптических кривых над конечным полем. Сейчас эти виды шифров используется всё активнее вместо RSA, поскольку они быстрее, размер ключа значительно меньше, потенциально устойчивее к взлому на квантовых компьютерах. Эллиптическая криптография построена на основе набора алгебраических операций на эллиптической кривой, которые, в свою очередь, строятся на основе операций в конечном поле, над которым задана кривая. В общем, это такая хардкорная высшая математика, знать которую совсем не обязательно для использования шифров. Крипто-алгоритмов на основе EC достаточно много, часть из них была перенесена из старых классических крипто-систем, часть придумана заново. Например, алгоритм цифровой подписи ГОСТ 34.10-2018 также использует эллиптические кривые для работы. Некоторые из ECC-алгоритмов могут использоваться для шифрования, а некоторые для цифровой подписи.

Из широко известных криптосистем только RSA позволяет собственными ключами шифровать и подписывать, все остальные непосредственно используются только для создания цифровой подписи. Однако можно пользоваться алгоритмом Diffie-Hellman для создания общего ключа для симметричного алгоритма (например, AES) и дальше уже им зашифровывать и расшифровывать данные.

Протокол Diffie-Hellman (Diffie–Hellman key exchange, дальше я буду его коротко называть DH) играет чрезвычайно большую роль в современной криптографии, поэтому я о нём расскажу подробно.

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

Итак, на разных сторонах открытого сетевого канала находятся Алиса и Боб которым нужно договориться о ключе (в моём примере это целое число) для симметричного шифра. Просто так передать его по сети нельзя, так как канал открытый и априори небезопасный.

  1. Алиса и Боб придумывают по секретному числу, например, Алиса выбирает 9 , а Боб — 2 .
  2. Алиса и Боб через открытый канал договариваются о каком-нибудь общем целом числе, скажем, 18 . Это число не является секретным, но при каждом сеансе DH оно должно быть новым. Самый простой способ договориться, когда сторона, начинающая коммуникацию, просто выбирает число и другая сторона его принимает.
  3. Дальше каждая сторона складывает своё секретное число и общее число, у Алисы получается 9 + 18=27 , а у Боба 2 + 18=20 . Полученный результат каждый отправляет другой стороне по открытому каналу.
  4. Полученное число Алиса и Боб складывают со своим секретным числом: у Алисы получается 20 + 9 = 29 , а у Боба 27 + 2 = 29 .
  5. Вот это число 29 и является ключом, который каждая из сторон использует для шифрования/дешифрования.

Я выбрал операцию сложения ради простоты объяснения, в реальном протоколе используется сложно-обратимая операция. Если её обозначить через ⊕, то для произвольных значений X и Y вычисление Z = X ⊕ Y выполняется легко; а зная Z и X , вычислить Y исключительно сложно и затратно. В реальном DH используется функция возведения в степень в мультипликативной группе вычетов по простому модулю, её обратная операция — дискретный логарифм — считается крайне сложной и на данный момент не имеет эффективного решения.

Протокол DH, очевидно, уязвим для атак типа Man-in-the-middle, то есть третья сторона может незаметно вклиниться в обмен данными и полностью перехватывать и расшифровывать все данные. Поэтому в реальной жизни обмен блоками данных в DH сопровождается алгоритмами аутентификации, например, цифровой подписью.

Рассмотрим такую ситуацию: есть клиент и есть сервер, к которому подключается клиент через небезопасный и незащищённый канал. Также выбран некоторый криптоалгоритм цифровой подписи. У сервера есть закрытый ключ, а его открытая часть уже есть у клиента. Тогда аутентифицированный DH может работать, например, так:

  1. Клиент генерирует случайное секретное значение X общее публичное значение A.
  2. Клиент инициирует соединение к серверу и отправляет по нему A.
  3. Сервер получает A, генерирует своё секретное значение Y и вычисляет публичное значение B на основе публичного значения A и своего секретного Y.
  4. Сервер вычисляет общий секретный ключ K на основе публичного значения A и своего секретного значения Y.
  5. Сервер вычисляет цифровую подпись S от объединённого набора значений A и B и отправляет клиенту публичное значение B и цифровую подпись S.
  6. Клиент получает публичное значение B, вычисляет на основе B и своего секретного значения X общий секретный ключ K.
  7. Клиент проверяет цифровую подпись K объединённого набора значений A и только что полученного B (помним, что у клиента уже есть открытый ключ сервера).
  8. Если верификация подписи проходит успешно, вычисленный ключ K используется для шифрования и дешифрования данных между клиентом и сервером при помощи симметричного алгоритма.

В такой схеме клиент может быть уверен, что между ним и сервером нет третьей стороны, которая перехватывает данные, гарантией этому служит цифровая подпись. Такой ключ K, который создаётся на время сессии, называется эфемерным ключом (ephemeral key).

Ранее мы уже договорились, что контейнером для распространения открытого ключа является цифровой сертификат. И теперь остаётся вопрос: каким образом сертификат сервера оказывается у клиента перед установкой соединения.

Концепт CSR и подписывания сертификата удостоверяющим центром¶

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

Под личными данными заявителя я подразумеваю его имя, название организации, адрес, город и прочую информацию, которую в англоязычной терминологии принято называть identity.

Чтобы удостоверяющий центр создал сертификат с открытым ключом и личными данными заявителя, ему нужно убедиться как минимум в двух вещах:

  1. Заявитель является именно тем, за кого себя выдаёт, то есть предоставленные им личные данные точно его или его организации, уполномоченным представителем которой он является.
  2. У заявителя есть закрытый ключ для того открытого, который он предоставил удостоверяющему центру для подписи вместе с личными данными.

Первый пункт — это процедура, которая проводится административными, а не криптографическими методами, поэтому о ней здесь не будем рассказывать — это проверка паспорта, учредительных документов, звонки по телефонам, различные заверенные у нотариуса документы и так далее. А вот вторая отлично решается в автоматическом режиме криптографически — достаточно заявителю подписать собственным закрытым ключом блок с информационными данными (куда также записан собственно этот же открытый ключ!). В этом случае удостоверяющий центр берёт открытый ключ из информационного блока и верифицирует им цифровую подпись всего блока.

Вот этот вот информационный блок (состоящий из личных данных и открытого ключа) плюс цифровая подпись для него формируют запрос на подпись сертификата / certificate signing request (CSR). Для X.509 формат данных CSR определён в спецификации PKCS#10, он достаточно простой и по сути представляет собой линейный список информационных полей, поэтому я особо не буду углубляться в описание его формата.

В удостоверяющем центре после верификации CSR выделяют из всего блока личных данных нужные, дополняют их данными УЦ, после чего получившийся новый блок подписывают закрытым ключом УЦ и получается X.509-сертификат.

Все эти шаги я нарисовал на одной схеме:

CSR Explained

TBS Certificate расшифровывается как to be signed certificate, то есть, данные для подписи, подписываемый сертификат.

Такая инфраструктура называется Public key infrastructure (Инфраструктура открытых ключей) или сокращённо PKI.

Инфраструктура УЦ и сертификаты¶

X.509-сертификат состоит из стандартного набора полей, часть из них обязательна, часть нет. Официального перевода этих названий на русский нет, поэтому я преимущественно буду пользоваться оригинальными именами с пояснениями при необходимости.

В каждом X.509-сертификате есть два обязательных поля: issuer и subject. Поле subject (то есть субъект, в философском смысле: носитель деятельности, осуществляющий активность) содержит личные данные заявителя и по сути является названием сертификата, его главным идентифицирующим признаком, именем. Я специально не использую термин идентификатор, поскольку в контексте сертификата такое поле уже есть, причём оно является необязательным. Содержимое берётся из одноимённого поля в CSR при создании сертификата и обычно представляет собой имя персоны, организации или домен веб-сайта.

В поле issuer хранится имя сертификата удостоворяющего центра. Постоянно помним, что открытые ключи у нас распространяются исключительно внутри сертификата. Поэтому в поле issuer находится содержимое поля subject сертификата УЦ, внутри которого находится открытый ключ, закрытая часть которого используется для подписи сертификата заявителя.

Поля issuer и subject являются структурированными, то есть это не просто строчки текста, а оформленные в жёстко заданную структуру данные типа distinguished name. Об этом подробнее я расскажу в практическом разделе.

Таким образом любой сертификат A в подобной инфраструктуре подписан закрытым ключом, открытая часть которого записана в каком-то другом сертификате B. Для простоты обычно в таком случае говорят, что сертификат A подписан сертификатом B. В свою очередь сертификат B подписан сертификатом C и так далее. Образуется цепочка зависимостей, которая завершается сертификатом Z специального вида, в котором поля issuer и subject совпадают. Это означает, что сертификат Z подписан закрытым ключом, открытая часть которого записана в этом же сертификате. Он так и называется — самоподписанный сертификат (self-signed certificate).

Считается, что вы как клиент доверяете (trust) сертификату A, если вы доверяете записанным в нём данным. Например, если вы получили сертификат организации через надёжный канал от надёжного представителя организации и записали на надёжном диске. Используя доверенный сертификат, а точнее, открытый ключ из него, вы можете организовать криптографически защищённый канал связи, например, до веб-сайта. Однако вы физически не сможете для каждого веб-сайта в таком режиме содержать «реестр» доверенных сертификатов и отслеживать его актуальность (сертификаты у сайтов часто меняются, например).

Описанная выше схема зависимостей между сертификатами лежит в основе системы доверия на базе удостоверяющих центров. Подразумевается, что если вы доверяете сертификату B, то вы также доверяете сертификату A, который им подписан. Так как организация-владелец сертификата B может им подписать множество других сертификатов, вы автоматически доверяете всем им. Следуя по цепочке доверия вы в итоге спускаетесь до самоподписанных сертификатов. Если вы доверяете самоподписанному сертификату Z, то вы автоматически доверяете всем остальным, которые имеют Z в цепочке доверия.

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

В итоге, только удостоверяющие центры (certification authority) обладают сертификатами, которые можно использовать для подписывания других сертификатов, чтобы они могли включаться в цепочку доверия. Их принято называть CA-сертификатами (CA certificate). А финальный самоподписанный сертификат в цепочке доверия называется сертификатом корневого удостоверяющего центра или просто корневым сертификатом (root certificate).

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

Также в сертификате есть множество других полей, которые ограничивают его применение. Например, диапазон дат, внутри которых сертификат можно считать доверенным. Практически все системы помечают сертификат недоверенным, если текущая дата в системе лежит вне указанного в сертификате диапазона. Диапазон действия корневых сертификатов обычно очень большой, порядка 10-20 лет. Этот диапазон дат указывается в полях notBefore и notAfter.

Здесь нужно отметить, что интерпретация «срока годности» сертификата целиком лежит на стороне программного обеспечения, которое сертификат использует. Нет никаких объективных причин, по которым сертификат перестаёт быть доверенным после достижения некоторой даты. Однако ограниченный срок жизни гарантирует стабильный источник дохода удостоверяющим центрам, которые выписывают сертификаты за весьма большие деньги.

Когда удостоверяющий центр выписывает сертификат, он записывает в поле serialNumber числовое значение, которое должно быть разным для каждого сертификата, заверенного этим конкретным сертификатом УЦ (X.509, п. 4.1.2.2). Туда можно записывать порядковый номер, можно текущую дату-время, можно случайное число, главное требование — это число должно быть уникальным для каждого выписанного сертификата.

X.509 — стандарт очень гибкий и позволяет добавлять произвольные дополнительные поля помимо базовых, это делается через расширения (extensions), я о них подробнее расскажу в практической части.

Цепочки доверия сертификатов на примере¶

Понятнее всего будет объяснить цепочки доверия на примере веб-сайтов и браузера.

У каждого работающего через SSL/TLS сайта имеется X.509-сертификат, подтверждающий его identity. Когда браузер устанавливает первое защищённое соединение с веб-сервером, они обмениваются информацией об используемых криптоалгоритмах, в рамках этого обмена веб-сервер отдаёт браузеру набор сертификатов, в котором есть обязательно сертификат собственно сайта, а остальные — промежуточные сертификаты для построения цепочки доверия.

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

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

Отзыв сертификата¶

Удостоверяющий центр может отозвать (revoke) любой выписанный им сертификат. Обычно это происходит при компрометации сертификата, когда связанный с ним закрытый ключ воруют злоумышленники. Ну или владелец сертификата по каким-то своим причинам решил сертификат принудительно лишить статуса доверенного у всех пользователей.

Изначально каждый удостоверяющий центр поддерживал собственный ресурс (веб-сайт) с регулярно обновляемым списком отозванных сертификатов, они так и назывались — списки отозванных сертификатов (certificate revocation list, сокращённо CLR). Программы должны скачивать эти CLR, парсить их и затем принудительно помечать указанные там сертификаты как недоверенные. Такая схема очень неэффективна и ресурсозатратна, поэтому она постепенно заменяется на новую — Online Certificate Status Protocol или OCSP.

OCSP позволяет практически в режиме реального времени проверять, отозван ли сертификат удостоверяющим центром, и некоторые браузеры его активно используют.

Помимо утечки закрытого ключа удостоверяющего центра, причиной отзыва может стать халатность самого УЦ, который выписывал сертификаты без должной проверки направо и налево. Либо использовал небезопасные или уязвимые криптоалгоритмы.

Как работает активное проксирование TLS/SSL¶

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

Естественно, зашифровать тем же закрытым ключом он не может, так как он есть только у оригинального владельца сайта-источника TLS-трафика, поэтому провайдер шифрует отдаваемый настоящему клиенту поток данных собственным закрытым ключом. При этом у клиента браузер начнёт выдавать ошибки, поскольку в его базе нет доверенного сертификата, закрытым ключом которого провайдер шифрует данные. Чтобы ошибок не было, провайдер может заставить клиентов установить в систему свой корневой сертификат и сделать его доверенным.

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

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

Практика¶

Я начну с обзора форматов данных, на которых всё построено, и дальше последовательно пройду по всем этапам жизненного цикла сертификата: создание закрытого ключа, создание CSR, создание сертификата на основе этого CSR. Мы будем очень интенсивно использовать консольную программу openssl из состава одноимённой библиотеки. Версия openssl должна быть 1 или лучше 1.1. Бо́льшая часть команд будет работать и в форках, например, libressl в макоси или boringssl в андроиде. Удобнее всего пользоваться терминалом в linux, macos, либо в новом режиме windows.

Форматы данных¶

Первичным форматом представления сертификатов (а часто и других объектов в openssl) в бинарном виде является DER (Distinguished Encoding Rules). DER в свою очередь является способом представления в бинарной форме структурированных данных, описанных на специальном языке ASN.1, который традиционно используется в телекоме и сетях. ASN.1 не просто язык описания структурированных данных, для него разработаны инструменты трансляции ASN.1-нотации в код на множестве языков программирования, который кодирует и декодирует бинарные объекты в типизированные объекты языка, например, в структуры или классы. При этом важным свойством DER-объектов является интегрированность информации о структуре прямо в данных, то есть вы можете взять DER-файл и программно разобрать его на составные части даже без формального описания в ASN.1. Естественно, вы не будете знать смысл отдельных полей и какие именно данные там закодированы, но вы как минимум увидите структуру и стандартные типы: кортежи, целые числа, строки (в том числе юникодные).

Если вам интересно, можете прочитать подробное описание стандарта и правил кодирования в статье википидии про стандарт X.680 (именно он описывает ASN.1) и X.690 (он описывает кодирование бинарных объектов для ASN.1), также эту тему я затронул в своей статье про кодирование данных на смарт-картах. В этой статье я не буду рассказывать о синтаксисе и других деталях ASN.1, однако будут приводить упрощённые описания на нём, так как они достаточно простые и лёгкие для базового понимания.

Структуру и данные («дамп») DER-объекта можно посмотреть командой openssl asn1parse . Примеры её использования будут дальше в этой статье, когда я буду рассказывать о внутреннем устройстве различных бинарных крипто-объектов и буду приводить «дампы» их структуры.

Второй распространённый формат данных — PEM, это своего рода контейнер, позволяющий записать бинарные данные в ограниченном символьном наборе Base64, пригодном для передачи через электронную почту, чаты или даже бумагу. Один блок данных в PEM-формате выглядит так:

-----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBAKhGNt7cXXgzTk9NaAjdJy5Lpfq3mIqws4Ev7zf1Idh043hcAFbB /uQr/BISsrAU170bLmAXE14s3edWkQNIWaECAwEAAQJAFcFmLK/+4aB4emY+kg7N lv2uythbv2qS+pvQ6MIniw10AZ+Ypa78x67DaZMeIRFPB9EkKs2AyYzzQmd/DBId MQIhANOlzUg24pOCT3bsB3ZcDXs52iyBYa+vk99w0S7ybF7NAiEAy4mSyjbJI1Uv e9zhdYwXjYutp+z6tjlYtIUAMBNNPiUCIE++mANOkr5Lig9fzUv+USIN4TOFqD3e 5NN6mYab1tM9AiALHkzCdxOttm2NmpdGUIzI0qR909guNBvAYLON7L//cQIhALr7 12CHrerflaB6KknHPDtA+1rEKdut36RQ/5WmqVdX -----END RSA PRIVATE KEY----- 

Блок начинается с символов ——BEGIN , дальше идёт метка, обозначающая тип хранимых данных, потом —— , затем кусок закодированных в Base64 данных и дальше ——END , снова та же метка и в конце опять —— .

Внутри одного файла может быть несколько PEM-блоков, причём вокруг них может быть произвольный текст, который обычно программами игнорируется. У PEM-файлов часто используется расширение .pem , либо расширения, обозначающие тип хранимых там объектов, к примеру, .cer или .crt для сертификатов или .key для закрытых ключей.

Если раскодировать через base64 текст внутри PEM-блока, обычно получим корректный DER-объект. Таким образом, для программы метка в PEM-блоке служит подсказкой, какой тип данных находится внутри.

Практически всегда мы будем работать именно с PEM, более того, openssl по умолчанию использует его во всех своих командах для ввода и вывода.

Типы данных¶

Object identifier (OID)¶

В описанных через ASN.1 данных для идентификации различных сущностей используется OID (Object indentifier) — это механизм построения идентификаторов, стандартизированный всякими международными техническими комитетами. В рамках этого механизма различные сущности, объекты, концепты, алгоритмы, компании (и вообще что угодно, на самом деле) получают гарантированно уникальный однозначный идентификатор.

OID используется везде, где нужно сослаться на некую «вещь», которая определена где-то ещё. Например, если нужно указать используемый алгоритм, то записываем OID этого алгоритма вместо, скажем, строки или локального идентификатора.

Структура OID иерерахичная, в человекочитаемом виде их обычно представляют набором чисел, разделённых точкой, например, 1.2.840.113549.1.1.1 — OID алгоритма шифрования RSA. При этом OID 1.2.840.113549 является идентификатором компании RSA® Security Limited Liability Company (LLC), соответственно, этот алгоритм находится в «пространстве имён» этой компании, которая может создавать любые новые идентификаторы, начинающиеся с её OID (1.2.840.113549). Также каждый сегмент-число может иметь строковое представление, оно локально для конкретного «родительского» OID. Например, корневой сегмент 1 имеет альтернативное имя iso , корневой сегмент 0 — itu-t , корневой сегмент 2 — joint-iso-itu-t , других корневых сегментов нет. Внутри корневого сегмента 1 определены дочерние сегменты: standard(0), registration-authority(1), member-body(2), identified-organization(3). Ну и так далее. В таком виде строятся OID в ASN.1 нотации: . Существует ещё одна эквивалентная нотация — OID-IRI (Internationalized Resource Identifier), в неё идентификатор выглядит так: /ISO/Member-Body/US/113549/1/1/1 . Однако мы в этом тексте из всего этого великолепия будем пользоваться исключительно точечной нотацией: 1.2.840.113549.1.1.1.

В ASN.1 определён специальный тип OBJECT IDENTIFIER для OID и он используется чрезвычайно широко в самых разных объектах, если вы в спецификации блока данных видите OBJECT IDENTIFIER , то в этом блоке лежит OID.

В интернете есть специальный сайт oid-info.com, на котором в едином реестре сведено множество OID, например, для нашего идентификатора алгоритма шифрования RSA адрес страницы: http://oid-info.com/get/1.2.840.113549.1.1.1 . Вы можете им пользоваться, если вам встретится незнакомый OID, или же вы захотите узнать числовое представление идентификатора, указанного в виде строки. Дальше я в тексте буду стараться указывать OID разных сущностей в виде ссылки на соответствующую страницу oid-info.com.

Distinguished Name (DN)¶

В русской литературе DN часто переводят как отличающееся имя, но это выглядит и звучит так мерзко, что я им не буду пользоваться, а буду всегда писать просто DN.

Понятие Distinguished Name (DN) пришло из LDAP, по сути это способ записи имени некоторого объекта/субъекта/сущности в строго структурированном виде.

DN представляет собой кортеж (то есть упорядоченную последовательность) из нескольких Relative DN (RDN), а каждый RDN состоит из пары значений AttributeType (тип атрибута) и AttributeValue (значение атрибута), при этом AttributeType является OID, а в AttributeValue чаще всего находится значение какого-нибудь из строковых типов.

Формальное определение DN даётся в RFC 5280 в таком виде:

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue AttributeTypeAndValue ::= SEQUENCE < type AttributeType, value AttributeValue >AttributeType ::= OBJECT IDENTIFIER AttributeValue ::= ANY -- DEFINED BY AttributeType DirectoryString ::= CHOICE

Строго говоря, каждый RelativeDistinguishedName представляет собой не пару AttributeType и AttributeValue, а множество таких пар. Несколько пар в рамках одного RDN называется multi-valued RDN и теоретически может встретиться в реальной жизни, но мы пока оставим эту тему за рамками статьи.

В отличие от LDAP, в X.509 нет единого общепринятого способа сериализации DN в строковое значение (и обратно), поэтому различные программы и библиотеки придумывают свои способы. Но общий принцип такого кодирования примерно одинаковый: каждый RDN кодируется в виде строки KEY=VALUE , а такие пары ключ-значение собираются в строку при помощи разделителя, например, A1=V1; A2=V2; A3=V3 . Во входных данных openssl используется нотация в такой форме:

/C=RU/ST=NSO/L=Novosibirsk/O=Regolit/CN=Sergey Stolyarov 

При интерпретации такой строки каждый сегмент вида /type=value декодируется в соответствующее бинарное значение. Типы атрибутов C , L , O и некоторые другие определены в стандарте и декодируются в соответствующие OID. При этом можно сразу указать нужный OID. Например, вот эквивалентное представление DN:

/2.5.4.6=RU/2.5.4.8=NSO/L=Novosibirsk/O=Regolit/CN=Sergey Stolyarov 

Здесь мы заменили C/Country на его OID 2.5.4.6, а ST/stateOrProvinceName — на OID 2.5.4.8. Также можно писать «длинные» типы атрибутов, например, вот тоже эквивалентное представление DN:

/Country=RU/stateOrProvinceName=NSO/L=Novosibirsk/O=Regolit/CN=Sergey Stolyarov 

Все три строки будут в итоге сконвертированы в одинаковый бинарный код, представляющий DN.

Важное замечание

Последовательность компонентов в DN имеет значение, /C=RU/L=Novosibirsk и /L=Novosibirsk/C=RU — это разные DN.

О конкретных типах атрибутов я расскажу ниже в разделе, где это будет более уместно и логично.

При выводе DN в текстовом виде openssl использует другую нотацию, что, впрочем, вполне в духе программы: C=RU, ST=NSO, L=Novosibirsk, O=Regolit, CN=Sergey Stolyarov

AlgorithmIdentifier¶

Под типом AlgorithmIdentifier почти всегда подразумевается подобная структура:

AlgorithmIdentifier ::= SEQUENCE

Это последовательность из двух полей: идентификатор (OID) алгоритма и опциональное поле с параметрами алгоритма. Названия конкретных полей могут различаться, но суть именно такая.

Генерация закрытого ключа¶

Первым этапом создания сертификата является генерация нового закрытого ключа на основе случайных данных. Я специально выделил это в отдельный пункт, чтобы вы смогли больше понять, как всё устроено. В других инструкциях сразу начинают с этапа создания certificate signing request (CSR), но мы к нему придём более последовательным путём.

Ключ можно дополнительно зашифровать симметричным шифром, используя отдельный пароль. Это дополнительный слой защиты для такого важного объекта: даже если злоумышленник получит доступ к файловой системе, он найдёт только зашифрованный объект. При использовании такого ключа необходимо ввести пароль при старте программы или в другой момент, когда он требуется.

Начнём с выбора криптографического алгоритма. Изначально он был ограничен двумя — RSA и DSA, позднее к ним добавились алгоритмы на эллиптических кривых (ECC).

Закрытый ключ RSA¶

Классическая команда для создания ключа RSA длиной 512 бит в файле rsa512_1.pem выглядит так:

[user@shell]% openssl genrsa -out rsa512_1.pem 512 Generating RSA private key, 512 bit long modulus (2 primes) . +++++++++++++++++++++++++++ . +++++++++++++++++++++++++++ e is 65537 (0x010001) 

Результатом будет файл с одним PEM-блоком с меткой RSA PRIVATE KEY :

-----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBALCwLuqdlD0h/ZiNd1iORH5Zgbz6Una9iAb1uT2+5+VKAHjC53RC p6RG95VKVvQFhKic78Wy0hvxTbVbPGABS5MCAwEAAQJAa+OJInYKWLHyuj5Xy9lD dauODykDRcJB144gCNYTn+vmIvaUpe15DCCLpOe1KtkowFbS8HKsWHgAL28zn3nx 0QIhAN0qYrvboEMJJkHmbYIOEyheS1S2xMHD1EsR8YdyU92/AiEAzIRtP52v8trb xpm+VGbvqdoqyuaRC2yElpt8AjBC7y0CIQCaLopWXG4FTcOV/YYqPJWuds4daK0S R+sfyoqO2m0NEQIgBSCQyJaAcbsw5VK3ZdBK09xHVFzhaALpdAkj274v/2UCIEM3 WFaS5azuCXD53wMrJEC5GlqjPHfXbm6Zssyi15xh -----END RSA PRIVATE KEY----- 

Внутри этого блока закодирован объект в формате, описанном в стандарте PKCS#1. PKCS#1 описывает алгоритм RSA, на данный момент его актуальный текст опубликован в виде RFC 3447. В стандарте описаны бинарные структуры ключей, именно в этом формате их создаёт команда openssl genrsa .

Вот как выглядит разобранный на составные закрытый ключ RSA в формате PKCS#1 (я сократил слишком длинные строки для читабельности, помним, что почти все объекты в нашей области закодированы в DER, который позволяет проводить автоматический разбор структуры):

[user@shell]% openssl asn1parse -i -in rsa512_1.pem 0:d=0 hl=4 l= 314 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=2 l= 65 prim: INTEGER :B12CA08DF04E4D4AD4149E789. skip. B0D7E0644D7186EC5C6B7D 74:d=1 hl=2 l= 3 prim: INTEGER :010001 79:d=1 hl=2 l= 64 prim: INTEGER :7B5CD76DFD24882C9F74ADAEC. skip. 17D123C69EE06BFEAFF01 145:d=1 hl=2 l= 33 prim: INTEGER :D543F842828515251F369D601752BC08602383B4A15A34D6C705877D791B54DB 180:d=1 hl=2 l= 33 prim: INTEGER :D4AD434262295D2BB2F3DE825AF8F6697B72D0902694112773A72EB36161C487 215:d=1 hl=2 l= 32 prim: INTEGER :4D84381F8CAB6CC522744A7D9BDCA1A5F5B3D2F27BD77AEF3A45E33A93238113 249:d=1 hl=2 l= 32 prim: INTEGER :56A1DD6C0520645B90A1D659B34506DB20F63C0EFC280474D59F9C5E65A4B5B1 283:d=1 hl=2 l= 33 prim: INTEGER :B5F1F5F4CA1771A6990851CFBCBDF5E2B6A032AD02AFA8AF914E47A73E8AE0DB 

Для бо́льшей наглядности я использовал аргумент -i , он отделяет вложенные блоки отступом. В данном случае мы видим, что внутри файла последовательно записаны девять чисел, в RFC 3447, раздел A.1.2 даётся такое ASN.1 определение этой структуры:

RSAPrivateKey ::= SEQUENCE

Первое поле — версия данных, это стандартная практика, а дальше идут восемь чисел, определяющих закрытый ключ RSA. Программы, использующие закрытый ключ, разбирают эти данные на числа и дальше пользуются ими для работы.

Команда openssl genrsa не умеет записывать ключ сразу в формате DER. Если вам нужен именно он, можно сконвертировать ключ из rsa512_1.pem в файл rsa512_1.der вот такой командой:

[user@shell]% openssl rsa -in rsa -in rsa512_1.pem -outform DER -out rsa512_1.der writing RSA key 

Аргумент -outform DER как раз задаёт выходной формат данных, если его не указывать, то подразумевается -outform PEM .

Как я уже упоминал выше, данные закрытого ключа можно зашифровать симметричным алгоритмом. Для этого нужно в команду openssl genrsa передать дополнительный аргумент, после чего программа попросит вас ввести два раза пароль, которым будут зашифрованы сгенерённые данные. Например, чтобы зашифровать ключ шифром AES-128-CBC , нужно выполнить команду:

[user@shell]% openssl genrsa -out rsa512_1_e.pem -aes128 512 Generating RSA private key, 512 bit long modulus . ++++++++++++ . ++++++++++++ e is 65537 (0x10001) Enter pass phrase for rsa512_1_e.pem: Verifying - Enter pass phrase for rsa512_1_e.pem: 

Результирующий файл rsa512_1_e.pem содержит один PEM-блок с такой же меткой RSA PRIVATE KEY , однако к блоку добавлены дополнительные атрибуты (они описаны в RFC 1421), указывающие, что данные внутри зашифрованы:

-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,49FDC7C579C43CA931FAC9BCB6AD829B SORCkWmb3Nv1Zzge5+kDLWbNDBdVl4w5bDQaGY4ebArDTqKPHAwQMJ2Kv7H2XUEo U94CJ8BT1X9Ycn4CCawY7DQoUn17TfHHGpW7Kn8Nzh6k7CWKzsvdQHxfnKM5QRN7 00COHepj2fAN5+UIT+2Md3c4QcKCjLfA4sIzTLBrrNl7HdwUs9cFEyKxl0j4DkzE t0OytYL2o/yrLY90QHohLsqMVDRr2I+O+QtaJm/3zSbGAJmsEDYkt9InG9MfikYd /HTCV3Mw/uLVLUEBbHT48lFUNZcaYD2a17r0hinsmNIwY9PVNfc4zt5WRKFYV+MV Xw44d0cM8aA9dLx76VGSbyshBR/m2DRvwvUonjH7Sv/zKe6mz990NZ4e6pgwWCek XmLu+z9k7hOERYwMJC0vweLGlxR3Cu1fErcbHiDfIGI= -----END RSA PRIVATE KEY----- 

Расшифровать такой файл можно такой командой (нужно знать пароль, которым зашифрованы данные):

[user@shell]% openssl rsa -in rsa512_1_e.pem -out rsa512_1.pem Enter pass phrase for rsa512_1_e.pem: writing RSA key 

Ну и также вы можете зашифровать уже имеющийся закрытый ключ RSA ( rsa512_1.pem ) командой openssl rsa (воспользуемся алгоритмом AES-192-CBC):

[user@shell]% openssl rsa -in rsa512_1.pem -out rsa512_1_e.pem -aes192 writing RSA key Enter PEM pass phrase: Verifying - Enter PEM pass phrase: 

Замечания

Список доступных алгоритмов для шифрования зависит от версии и сборки openssl. Базовые алгоритмы типа AES-128-CBC , AES-192-CBC , DES-CBC , DES-EDE3-CBC и несколько других обычно есть везде.

Как вы могли заметить, для создания ключей RSA используется команды openssl genrsa , а для модификации — openssl rsa . Вторая команда также может использоваться для конвертации PEM в DER и обратно, генерации открытого ключа из закрытого и некоторых других операций.

Зашифрованный ключ формата PKCS#1 нельзя хранить в виде DER-файла. Если вы попытаетесь сконвертировать закрытый RSA-ключ командой openssl rsa , то программа спросит у вас пароль и запишет DER-файл с расшифрованным ключом внутри.

Никогда не используйте закрытый RSA ключ длиной менее 2048 бит, я в статье использую 512 только для демонстрации!

Закрытый ключ эллиптической криптосистемы¶

Важное замечание.

Разные программы и библиотеки поддерживают разные эллиптические кривые, и несмотря на то что openssl понимает их очень много, лишь очень ограниченный набор применим для реальных ситуаций, например, для SSL/TLS. См., например, таблицу совместимости кривых и TLS-библиотек: https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Supported_elliptic_curves. Я буду использовать в примерах лишь те кривые, которые имеют максимально возможную поддержку среди библиотек.

Для создания закрытого ключа эллиптической криптосистемы (EC-ключа) используется команда openssl ecparam :

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-eckey.pem 

Аргумент -noout нужен для того, чтобы в результирующий файл был записан только сгенерённый закрытый ключ, без параметров использованной эллиптической кривой в виде отдельного PEM-блока. Название используемой кривой указываем в аргументе -name prime256v1 .

Команда openssl ecparam создаёт ключ в формате, описанном в стандарте RFC 5915, в PEM-файле это блок с маркером EC PRIVATE KEY , его структура описывается вот таким упрощённым ASN.1-определением:

ECPrivateKey ::= SEQUENCE < version INTEGER, privateKey OCTET STRING, parameters [0] ECParameters > OPTIONAL, publicKey [1] BIT STRING OPTIONAL > 

В нём два обязательных поля: version и privateKey, а также два опциональных: parameters — с параметрами эллиптической кривой и publicKey — с открытым ключом.

Посмотрим на созданный ключ, он записывается в PEM-блок с маркером EC PRIVATE KEY :

-----BEGIN EC PRIVATE KEY----- MHcCAQEEIP6zRS0PbMX8QZZb7KMc0Us/XFa/NMDWVgXLuVEeas0LoAoGCCqGSM49 AwEHoUQDQgAEFoLqkuY6BGIKFrQE7B1ui+rrEit4vLr34toMd2IX7tKwn+WlRRcZ CfvZUi/8NVK5T3ru2Y0RpmW5qC1QUGPWcA== -----END EC PRIVATE KEY----- 

Если воспользоваться командой openssl asn1parse , увидим структуру данных внутри этого блока:

[user@shell]% openssl asn1parse -i -in prime256v1-eckey.pem 0:d=0 hl=2 l= 119 cons: SEQUENCE 2:d=1 hl=2 l= 1 prim: INTEGER :01 5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:FEB3452D0F6CC5FC41965BECA31CD14B3F5C56BF34C0D65605CBB9511E6ACD0B 39:d=1 hl=2 l= 10 cons: cont [ 0 ] 41:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 51:d=1 hl=2 l= 68 cons: cont [ 1 ] 53:d=2 hl=2 l= 66 prim: BIT STRING 

Видим, что в первом поле записана версия (число 01 ), во втором поле — закрытый ключ в виде байтовой строки, в третьем находится блок с параметрами в виде идентификатора кривой (в форме OID, которое преобразуется программой в человекочитаемый формат prime256v1 ) и в конце — открытый ключ.

При генерации ключа вместо prime256v1 можно указать название другой эллиптической кривой, openssl их знает очень много, полный список можно вывести командой openssl ecparam -list_curves :

[user@shell]% openssl ecparam -list_curves secp112r1 : SECG/WTLS curve over a 112 bit prime field secp112r2 : SECG curve over a 112 bit prime field secp128r1 : SECG curve over a 128 bit prime field . skip. brainpoolP512t1: RFC 5639 curve over a 512 bit prime field SM2 : SM2 curve over a 256 bit prime field 

За каждым названием типа secp112r1 или secp112r1 скрыт набор параметров, задающих эту кривую, и вы можете их включить в закрытый ключ вместо предопределённого названия кривой. Это делается добавлением аргумента -param_enc explicit в вызов команды openssl ecparam :

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout -param_enc explicit -out prime256v1-eckey-full.pem 

Результирующий файл prime256v1-eckey-full.pem получается заметно больше:

-----BEGIN EC PRIVATE KEY----- MIIBaAIBAQQg90po7E2F5ushBs6832qyZDKu34YUL6XnQgTzICeYgbaggfowgfcC AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 YyVRAgEBoUQDQgAEYYr/jahQc8DXGycDUG+4uYPPvAM447vdt6mAtNOEisSPeKVW CTBUZ+Bm/rTzuDqIkRVFiGibIh/irFnK3gTvAg== -----END EC PRIVATE KEY----- 

А его структура уже сложнее — вместо идентификатора кривой появился новый блок с её полными параметрами:

[user@shell]% openssl asn1parse -i -in prime256v1-eckey-full.pem 0:d=0 hl=4 l= 360 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :01 7:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:F74A68EC4D85E6EB2106CEBCDF6AB26432AEDF86142FA5E74204F320279881B6 41:d=1 hl=3 l= 250 cons: cont [ 0 ] 44:d=2 hl=3 l= 247 cons: SEQUENCE 47:d=3 hl=2 l= 1 prim: INTEGER :01 50:d=3 hl=2 l= 44 cons: SEQUENCE 52:d=4 hl=2 l= 7 prim: OBJECT :prime-field 61:d=4 hl=2 l= 33 prim: INTEGER :FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF 96:d=3 hl=2 l= 91 cons: SEQUENCE 98:d=4 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC 132:d=4 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B 166:d=4 hl=2 l= 21 prim: BIT STRING 189:d=3 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:046B17D1F2E12C4247F8. skipped. CBB6406837BF51F5 256:d=3 hl=2 l= 33 prim: INTEGER :FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 291:d=3 hl=2 l= 1 prim: INTEGER :01 294:d=1 hl=2 l= 68 cons: cont [ 1 ] 296:d=2 hl=2 l= 66 prim: BIT STRING 

Для любой именованной кривой, которую знает openssl, вы можете посмотреть её параметры в человекочитаемом формате:

[user@shell]% openssl ecparam -name prime256v1 -text -param_enc explicit -noout Field Type: prime-field Prime: 00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00: 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff: ff:ff:ff A: 00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00: 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff: ff:ff:fc B: 5a:c6:35:d8:aa:3a:93:e7:b3:eb:bd:55:76:98:86: bc:65:1d:06:b0:cc:53:b0:f6:3b:ce:3c:3e:27:d2: 60:4b Generator (uncompressed): 04:6b:17:d1:f2:e1:2c:42:47:f8:bc:e6:e5:63:a4: 40:f2:77:03:7d:81:2d:eb:33:a0:f4:a1:39:45:d8: 98:c2:96:4f:e3:42:e2:fe:1a:7f:9b:8e:e7:eb:4a: 7c:0f:9e:16:2b:ce:33:57:6b:31:5e:ce:cb:b6:40: 68:37:bf:51:f5 Order: 00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff: ff:ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc: 63:25:51 Cofactor: 1 (0x1) Seed: c4:9d:36:08:86:e7:04:93:6a:66:78:e1:13:9d:26: b7:81:9f:7e:90 

Здесь параметр -text означает, что нужно вывести информацию в человекочитаемой форме, а -param_enc explicit означает, что параметры кривой нужно вывести в явной форме без сокращённого до имени названия. -noout отключает вывод собственно указанного объекта на экран.

Вы можете сравнить вывод этого и предыдущего листингов, чтобы убедиться, что они описывают один и тот же объект.

Параметры кривой можно также вывести в отдельный PEM-файл:

[user@shell]% openssl ecparam -name prime256v1 -param_enc explicit -out prime256v1-curve.pem 

Получается такой файл prime256v1-curve.pem с PEM-блоком с маркером EC PARAMETERS :

-----BEGIN EC PARAMETERS----- MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP////////// /////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6 k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+ kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz ucrC/GMlUQIBAQ== -----END EC PARAMETERS----- 

И мы опять можем через asn1parse посмотреть его структуру:

[user@shell]% openssl asn1parse -i -in prime256v1-curve.pem 0:d=0 hl=3 l= 247 cons: SEQUENCE 3:d=1 hl=2 l= 1 prim: INTEGER :01 6:d=1 hl=2 l= 44 cons: SEQUENCE 8:d=2 hl=2 l= 7 prim: OBJECT :prime-field 17:d=2 hl=2 l= 33 prim: INTEGER :FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF 52:d=1 hl=2 l= 91 cons: SEQUENCE 54:d=2 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC 88:d=2 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B 122:d=2 hl=2 l= 21 prim: BIT STRING 145:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F. 406837BF51F5 212:d=1 hl=2 l= 33 prim: INTEGER :FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 247:d=1 hl=2 l= 1 prim: INTEGER :01 

Если у вас есть файл с параметрами эллиптической кривой, то вы можете его передать в команду openssl ecparam и сгенерировать ключ на этой кривой, даже если вашей версии openssl ничего про неё не известно. Вот полезный пример, как создать ключ для алгоритма ГОСТ 34.10-2012 в версии openssl, которая по умолчанию не содержит определения этой кривой. Параметры я записал в файл id-tc26-gost-3410-2012-512-paramSetA.pem, вы можете его скачать и использовать для создания ключа таким образом:

[user@shell]% openssl ecparam -in id-tc26-gost-3410-2012-512-paramSetA.pem -genkey -noout -out gost-eckey.pem 

Если вы запускали все вышеперечисленные команды, у вас должно быть создано два закрытых ключа: secp160k1-eckey.pem и gost-eckey.pem . Если посмотрите размеры этих файлов, то увидите, что в первом байтов в несколько раз меньше (922 байта против 174):

[user@shell]% ls -l prime256v1-eckey.pem gost-eckey.pem -rw------- 1 sigsergv sigsergv 922 сен 1 23:56 gost-eckey.pem -rw------- 1 sigsergv sigsergv 227 сен 1 23:48 prime256v1-eckey.pem 

Это происходит потому, что для второго ключа ( gost-eckey.pem ) мы явным образом указали все параметры эллиптической кривой, в то время как для первого — только название предопределённой. Разница особенно заметна, если сравнить содержимое через asn1parse:

[user@shell]% openssl asn1parse -i -in prime256v1-eckey.pem 0:d=0 hl=2 l= 119 cons: SEQUENCE 2:d=1 hl=2 l= 1 prim: INTEGER :01 5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:FEB3452D0F6CC5FC41965BECA31CD14B3F5C56BF34C0D65605CBB9511E6ACD0B 39:d=1 hl=2 l= 10 cons: cont [ 0 ] 41:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 51:d=1 hl=2 l= 68 cons: cont [ 1 ] 53:d=2 hl=2 l= 66 prim: BIT STRING [user@shell]% openssl asn1parse -i -in gost-eckey.pem 0:d=0 hl=4 l= 631 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :01 7:d=1 hl=2 l= 64 prim: OCTET STRING [HEX DUMP]:0310F98B02AAC16490DCBD61. skipped. E4589F44F219EFFF4 73:d=1 hl=4 l= 422 cons: cont [ 0 ] 77:d=2 hl=4 l= 418 cons: SEQUENCE 81:d=3 hl=2 l= 1 prim: INTEGER :01 84:d=3 hl=2 l= 76 cons: SEQUENCE 86:d=4 hl=2 l= 7 prim: OBJECT :prime-field 95:d=4 hl=2 l= 65 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF. skipped. FFFFFFFFFFFFDC7 162:d=3 hl=3 l= 132 cons: SEQUENCE 165:d=4 hl=2 l= 64 prim: OCTET STRING [HEX DUMP]:FFFFFFFFFFFFFFFFFFFFFFFFFFFF. skipped. FFFFFFFDC4 231:d=4 hl=2 l= 64 prim: OCTET STRING [HEX DUMP]:E8C2505DEDFC86DDC1BD0B2. skipped. 4761503190785A71C760 297:d=3 hl=3 l= 129 prim: OCTET STRING [HEX DUMP]:04000000000000. skipped. 5B889A589CB5215F2A4 429:d=3 hl=2 l= 65 prim: INTEGER :FFFFFFFFFFFFFFFFFF. skipped. 11F10B275 496:d=3 hl=2 l= 1 prim: INTEGER :01 499:d=1 hl=3 l= 133 cons: cont [ 1 ] 502:d=2 hl=3 l= 130 prim: BIT STRING 

Замечание

Команда openssl ecparam умеет сама записывать создаваемый ключ в формате DER, для этого нужно указать аргумент -outform DER :

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout -outform DER -out prime256v1-eckey.der 

Обратите внимание, что этот бинарный файл prime256v1-eckey.der по-прежнему подчиняется RFC 5915, это НЕ закодированный в DER PKCS#8-ключ. Если вам нужен бинарный PKCS#8-ключ, смотрите раздел Конвертация закрытых ключей в формат PKCS#8 и обратно.

Как и в случае RSA, вы можете зашифровать создаваемый закрытый ключ (только внутри PEM, шифрование DER не поддерживается), однако для этого нужно использовать сразу две соединённые команды, если хотите сгенерённый ключ зашифровать сразу при создании:

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout | openssl ec -aes-128-cbc -out prime256v1-eckey-e.pem 

Для операций над ключами эллиптических криптосистем существует отдельная команда openssl ec , она по сути аналогична openssl rsa , только работает для другого типа ключей. Например, конвертация ключа из формата PEM в DER делается так:

[user@shell]% openssl ec -in prime256v1-eckey.pem -outform DER -out prime256v1-eckey.der read EC key writing EC key 

А шифрование закрытого ключа — так:

[user@shell]% openssl ec -in prime256v1-eckey.pem -aes192 -out prime256v1-eckey-e.pem read EC key writing EC key Enter PEM pass phrase: Verifying - Enter PEM pass phrase: 

Закрытые ключи в формате PKCS#8¶

Важное замечание насчёт PKCS#8.

Ключи в данном формате могут до сих пор считаться несколько экзотичными и некоторые библиотеки или программы их не понимают. Но важно понимать, что это точно такие же закрытые ключи, только в специальном «универсальном» формате-контейнере.

Выше мы видели, что форматы данных для RSA и EC-ключей совершенно разные, а отличить их друг от друга можно только через разные PEM-маркеры. Если же ключи представлены в DER-файлах, распознать их можно только эмпирическим путём, пытаясь разобрать данные для разных спецификаций.

Эту ситуацию пытается разрешить стандарт PKCS#8, он описывает способ представления закрытых ключей для произвольных алгоритмов, а также способ шифрования данных ключа.

Структура закрытого ключа в формате PKCS#8 очень простая и описывается такой ASN.1-схемой (я её упростил для читаемости):

PrivateKeyInfo ::= SEQUENCE < version Version, privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, privateKey PrivateKey, attributes [0] IMPLICIT Attributes OPTIONAL >PrivateKeyAlgorithmIdentifier ::= SEQUENCE

По сути это набор из как минимум трёх полей: версии синтаксиса (сейчас там может быть только 0), идентификатора алгоритма закрытого ключа (см. Типы данных → AlgorithmIdentifier) и собственно данных закрытого ключа.

Идентификатор алгоритма (privateKeyAlgorithm) представляет собой набор из одного обязательного поля algorithm, в котором записывается OID (см. Типы данных → Object identifier (OID)), и опционального поля с параметрами алгоритма.

Обычно с конкретным идентификатором алгоритма закрытого ключа связан способ его кодирования, именно в таком формате должны быть записаны данные в поле privateKey.

Для создания закрытых ключей в формате PKCS#8 используется команда openssl genpkey . Например, для создания RSA-ключа длиной 512 бит команда выглядит так (ключ записывается в файл rsa512_8.pem ):

[user@shell]% openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:512 -out rsa512_8.pem 

А вот как создать ключ для эллиптического алгоритма на кривой secp160k1 и сохранить его в файл secp160k1_8.pem :

[user@shell]% openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -pkeyopt ec_param_enc:named_curve -out prime256v1-eckey-8.pem Enter PEM pass phrase: Verifying - Enter PEM pass phrase: 

В обоих примерах создаётся файл в формате PEM, причём с одинаковыми маркерами. Вот как выглядит файл rsa512_8.pem :

-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaqCEC9Y6I3VC8 +QtqA6oD6vxvEJczu+YV5Kn8b7CvcqWBfXI3RCG8VB/Hbt1cj5n0jc266d/XDimT . skipped. G0SVctomV0+dx5azDC5Dj1Mt8xLgnkn6924yPLGLomGGVzsCpzxyqND7g4bU5yQV XILO58GSBmyOuWI7+EFb7s6N -----END PRIVATE KEY----- 

А вот файл prime256v1-eckey-8.pem , для его создания мы указали аргумент -pkeyopt ec_param_enc:named_curve , поэтому полные параметры кривой в него не включены, а только имя:

-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgIcYPIBeg/FEzbxU7 gfUTGkSYULyfLAErmi/BWXUCq6+hRANCAARULnWxbWLN1bEP2l4tKHo8j4TjMU54 pldrPAXxlsRTG1A68AP8w+ATR3SAKGauy25+fTdgbk3gn2TbBXyoM3IE -----END PRIVATE KEY----- 

Если запустить openssl asn1parse , то можно увидеть внутреннюю структуру этих данных, например:

[user@shell]% openssl asn1parse -i -in prime256v1-eckey-8.pem 0:d=0 hl=3 l= 135 cons: SEQUENCE 3:d=1 hl=2 l= 1 prim: INTEGER :00 6:d=1 hl=2 l= 19 cons: SEQUENCE 8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 17:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 27:d=1 hl=2 l= 109 prim: OCTET STRING [HEX DUMP]:306B020101042021C60F. skipped. D37606E4DE09F64DB057CA8337204 

Мы видим три поля: версию (со значением 0 ), идентификатор алгоритма, состоящий из OID 1.2.840.10045.2.1 (обозначается идентификатором id-ecPublicKey ) и OID параметра 1.2.840.10045.3.1.7 именованной эллиптической кривой (обозначается идентификатором prime256v1 ).

Если при создании ключа указать аргумент -pkeyopt ec_param_enc:explicit , то в поле параметра алгоритма будут стоять параметры кривой вместо идентификатора prime256v1 .

Команда genpkey позволяет также создавать зашифрованные ключи, однако по необъяснимым причинам позволяет это делать только в формате PEM, а чтобы преобразовать зашифрованный ключ в DER, нужно использовать команду openssl pkcs8 , о которой я расскажу в следующем разделе.

Зашифрованный ключ создаётся при указании аргумента с алгоритмом симметричного шифрования (в данном случае -aes-128-cbc ):

[user@shell]% openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -aes-128-cbc -out rsa512_8_e.pem . +++++ . +++++ Enter PEM pass phrase: Verifying - Enter PEM pass phrase: 

Конвертация закрытых ключей в формат PKCS#8 и обратно¶

В принципе, все современные библиотеки и платформы должны корректно принимать ключи в формате PKCS#8, однако в некоторых из них требуют ключ только в традиционном формате для данного алгоритма (например, PKCS#1 для RSA-ключей). В openssl есть команда для конвертации закрытых ключей между PKCS#8 и традиционным форматом и обратно.

Например, для преобразования файла RSA-ключа rsa512_1.der из PKCS#1 DER в PKCS#8 PEM без симметричного шифрования используется такая команда:

[user@shell]% openssl pkcs8 -topk8 -nocrypt -in rsa512_1.der -inform DER 

Если же вы хотите зашифровать ключ, замените аргумент -nocrypt на -v2 aes128 (вместо aes128 можно также использовать aes256 или des3 ):

[user@shell]% openssl pkcs8 -topk8 -v2 aes128 -in rsa512_1.der -inform DER Enter Encryption Password: Verifying - Enter Encryption Password: 

Команда запросит новый пароль и его подтверждение.

Важное замечание насчёт пароля.

Симметричный алгоритм обычно требует в качестве ключа шифрования набор байтов строго определённой длины, например, 128 бит в случае AES-128-CBC, однако пользователю разрешено ввести произвольный пароль, длина которого отличается от требуемых 128 бит. Поэтому пароль сначала преобразуется специальными методами в набор байтов нужной длины и только потом этот набор байтов используется в качестве ключа.

Такая процедура называется KDF — key derivation function, в русскоязычной терминологии — функция формирования ключа. И если выбранный алгоритм симметричного шифрования использует очень короткий ключ, ваш длинный «безопасный» пароль будет преобразован в короткий ключ, который злоумышленник сможет легко подобрать (то есть ему нужно подобрать существенно менее длинный ключ, чем пароль, из которого он генерируется).

В некоторых вариантах openssl, например, в libressl из macos по умолчанию используется очень слабый алгоритм с очень коротким ключом, поэтому всегда указывайте алгоритм шифрования, как минимум это должен быть AES-128-CBC (что делается аргументом -v2 aes128 ).

Ну а вообще вся эта криптография с паролем соответствует PKCS#5, последняя версия которого описана в RFC 2898. Аргумент -v2 включает как раз её (PKCS#5 v2.0), однако не все программы могут такие данные принимать и может понадобиться использовать прошлую версию (PKCS#5 v1.5), но это уже детали, о которых я тут не буду рассказывать.

По умолчанию результат выводится в терминал, чтобы вывести в файл rsa512_8_e.pem , укажите аргумент -out rsa512_8_e.pem :

[user@shell]% openssl pkcs8 -topk8 -v2 aes128 -in rsa512_1.der -inform DER -out rsa512_8_e.pem 

Если вы не хотите шифровать данные ключа, используйте аргумент -nocrypt :

[user@shell]% openssl pkcs8 -topk8 -nocrypt -in rsa512_1.der -inform DER -out rsa512_8.pem 

Для обратного преобразования из PKCS#8 в традиционный формат используется аргумент -traditional :

[user@shell]% openssl pkcs8 -nocrypt -in rsa512_8.pem -traditional 

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

Хаос с генерацией ключей в openssl¶

В документации к openssl написано, что genpkey заменяет целый класс других команд типа genrsa, gendsa и других. Однако формат создаваемых файлов у genrsa и genpkey совершенно разный: первая генерирует RSA-ключ в формате PKCS#1, а вторая — PKCS#8. Но если указать вывод в DER, то genpkey создаёт не PKCS#8 в формате DER, а тоже PKCS#1 DER! Однако для эллиптических алгоритмов и PEM, и DER оба ключа создаются в формате PKCS#8.

Более того, в ряде команд нигде не указано, что результирующий файл будет записан в формате PKCS#8, например, этим грешит команда openssl req , ниже я подробнее о ней расскажу.

Создание Certificate Signing Request¶

Жизненный цикл сертификата продолжается созданием запроса не подпись сертификата (Certificate Signing Request, CSR). По сути он является шаблоном, на основе которого удостоверяющий центр создаст и подпишет сертификат. CSR содержит обязательные личные данные заявителя, открытый ключ и дополнительные необязательные поля с другими данными. И всё это должно быть подписано закрытым ключом, который соответствует приложенному открытому.

Создание CSR в диалоговом режиме¶

Мы будем делать CSR на основе закрытого ключа, ранее созданного в файле prime256v1-eckey.pem .

Для создания CSR используется команда openssl req , обычно её запускают в интерактивном режиме, в котором она запрашивает у пользователя личные данные:

[user@shell]% openssl req -new -key prime256v1-eckey.pem -out regolit-1.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []:RU State or Province Name (full name) []:NSO Locality Name (eg, city) []:Novosibirsk Organization Name (eg, company) []:Regolit Organizational Unit Name (eg, section) []: Common Name (eg, fully qualified host name) []:test.regolit.com Email Address []:[email protected] Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:123456 An optional company name []: 

Стандартный набор полей:

  • страна (Country Name) → RU, здесь вводится двухсимвольный код страны в соответствии с ISO 3166-1;
  • область/регион (State or Province Name) → NSO, название области, края, провинции и так далее;
  • название населённого пункта (Locality Name) → Novosibirsk, название города, посёлка и так далее;
  • название организации (Organization Name) → Regolit, название организации;
  • отдел организации (Organizational Unit Name) → название отдела в организации (я это поле не заполнял);
  • общее имя (Common Name) → regolit.com, это по сути название сертификата, ранее сюда принято было записывать доменное имя сайта, подробнее об этом я расскажу позднее;
  • электронная почта (Email Address) → [email protected], адрес электронной почты;
  • опознавательный пароль (A challenge password) → 123456, опознавательный пароль, об этом я тоже расскажу отдельно.

Я указал закрытый ключ в аргументе -key secp160k1-eckey.pem , в процессе генерации CSR в файле domain.csr из него был извлечён открытый ключ, добавлен в CSR, добавлены остальные личные данные, и в итоге этим же закрытым ключом CSR был подписан.

Формат CSR описан в PKCS#10, последняя на текущий момент его версия — RFC 2986. Как и в случае с ключом, вы можете посмотреть структуру только что созданного файла командой openssl ans1parse :

[user@shell]% openssl asn1parse -dump -i -in domain.csr 0:d=0 hl=4 l= 341 cons: SEQUENCE 4:d=1 hl=3 l= 251 cons: SEQUENCE 7:d=2 hl=2 l= 1 prim: INTEGER :00 10:d=2 hl=3 l= 129 cons: SEQUENCE 13:d=3 hl=2 l= 11 cons: SET 15:d=4 hl=2 l= 9 cons: SEQUENCE 17:d=5 hl=2 l= 3 prim: OBJECT :countryName 22:d=5 hl=2 l= 2 prim: PRINTABLESTRING :RU 26:d=3 hl=2 l= 12 cons: SET 28:d=4 hl=2 l= 10 cons: SEQUENCE 30:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName 35:d=5 hl=2 l= 3 prim: UTF8STRING :NSO 40:d=3 hl=2 l= 20 cons: SET 42:d=4 hl=2 l= 18 cons: SEQUENCE 44:d=5 hl=2 l= 3 prim: OBJECT :localityName 49:d=5 hl=2 l= 11 prim: UTF8STRING :Novosibirsk 62:d=3 hl=2 l= 16 cons: SET 64:d=4 hl=2 l= 14 cons: SEQUENCE 66:d=5 hl=2 l= 3 prim: OBJECT :organizationName 71:d=5 hl=2 l= 7 prim: UTF8STRING :Regolit 80:d=3 hl=2 l= 25 cons: SET 82:d=4 hl=2 l= 23 cons: SEQUENCE 84:d=5 hl=2 l= 3 prim: OBJECT :commonName 89:d=5 hl=2 l= 16 prim: UTF8STRING :test.regolit.com 107:d=3 hl=2 l= 33 cons: SET 109:d=4 hl=2 l= 31 cons: SEQUENCE 111:d=5 hl=2 l= 9 prim: OBJECT :emailAddress 122:d=5 hl=2 l= 18 prim: IA5STRING :[email protected] 142:d=2 hl=2 l= 89 cons: SEQUENCE 144:d=3 hl=2 l= 19 cons: SEQUENCE 146:d=4 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 155:d=4 hl=2 l= 8 prim: OBJECT :prime256v1 165:d=3 hl=2 l= 66 prim: BIT STRING 0000 - 00 04 16 82 ea 92 e6 3a-04 62 0a 16 b4 04 ec 1d . b. 0010 - 6e 8b ea eb 12 2b 78 bc-ba f7 e2 da 0c 77 62 17 n. +x. wb. 0020 - ee d2 b0 9f e5 a5 45 17-19 09 fb d9 52 2f fc 35 . E. R/.5 0030 - 52 b9 4f 7a ee d9 8d 11-a6 65 b9 a8 2d 50 50 63 R.Oz. e..-PPc 0040 - d6 70 .p 233:d=2 hl=2 l= 23 cons: cont [ 0 ] 235:d=3 hl=2 l= 21 cons: SEQUENCE 237:d=4 hl=2 l= 9 prim: OBJECT :challengePassword 248:d=4 hl=2 l= 8 cons: SET 250:d=5 hl=2 l= 6 prim: UTF8STRING :123456 258:d=1 hl=2 l= 10 cons: SEQUENCE 260:d=2 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA256 270:d=1 hl=2 l= 73 prim: BIT STRING 0000 - 00 30 46 02 21 00 f2 e7-5d 8b b5 23 90 84 00 13 .0F. ]..#. 0010 - a7 39 f7 36 78 d1 31 dc-99 9c 90 0e 6c 1a 33 56 .9.6x.1. l.3V 0020 - 81 b1 b0 0c b2 ab 02 21-00 90 7b 5d 8c 58 ec 06 .  0030 - f7 88 bf cd 19 22 20 29-d7 ff aa 19 09 0b c1 c1 . " ). 0040 - 66 94 18 39 9f 47 b4 0d-07 f..9.G. 

Полную ASN.1-схему вы найдёте в RFC 2986. А я сейчас простыми словами её расскажу. Весь блок CSR состоит из трёх последовательно идущих элементов:

toBeSigned содержательная часть запроса с личными данными, открытым ключом и другими атрибутами, в RFC 2986 этот блок обозначается как CertificationRequestInfo ; algorithm идентификатор (OID) алгоритма подписи, в нашем случае openssl знает, на какой именно объект ссылается OID и вместо его «сырого» представления (1.2.840.10045.4.3.2) подставляет «человеческое» название ecdsa-with-SHA256 ; signature собственно цифровая подпись содержательной части.

Структура блока CertificationRequestInfo стандартная:

version номер версии; subject структурированный блок с личными данными; subjectPKInfo открытый ключ; attributes опциональный набор дополнительных атрибутов.

Практически все поля, которые вы заполняли в диалоговом режиме, ушли в блок subject , его тип — distinguished name и я про него писал подробно в разделе Типы данных → Distinguished Name (DN).

Значение поля опознавательный пароль (A challenge password) было записано в отдельный атрибут, детально оно в стандартах не определено и отдано на усмотрение удостоверяющим центрам. Оно не фигурирует в итоговом сертификате или в процессе его изготовления, однако может использоваться в отдельных административных процедурах самого центра. К примеру, для отзыва сертификата УЦ может потребовать от заявителя сообщить тот же самый пароль, который был передан в оригинальном CSR. Также обратите внимание, что это чисто информационное поле и оно никак не используется в криптографических операциях на протяжении всего жизненного цикла сертификата.

Замечание

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

При использовании -newkey закрытый ключ всегда создаётся в формате PKCS#8 и поэтому может потребовать принудительной конвертации в традиционный формат.

Создание CSR в командном режиме¶

У openssl req есть командный режим, в котором CSR создаётся без интерактивного взаимодействия, а все требуемые значения передаются в командной строке, например, так:

[user@shell]% openssl req -new -batch -key prime256v1-eckey.pem \ -subj '/C=RU/ST=NSO/L=Novosibirsk/O=Regolit/CN=test.regolit.com/[email protected]' \ -out regolit-2.csr 

Результат будет практически тот же самый, только поле challengePassword в таком режиме передать невозможно.

В аргументе -subj указываются личные данные в формате /type1=value1/type2=value2/type3=value3 , его я подробно разбирал в разделе Типы данных → Distinguished Name (DN). В качестве type1, type2 и т.п. могут выступать следующие значения:

  • C или countryName
  • CN или commonName
  • L или localityName
  • ST или stateOrProvinceName
  • O или organizationName
  • OU или organizationalUnitName
  • emailAddress

Создание CSR в расширенном командном режиме¶

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

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

Вот готовый файл с полным набором данных для создания CSR, включая поле challengePassword.

[ req ] prompt = no distinguished_name = req_distinguished_name attributes = req_attributes [ req_distinguished_name ] C = RU ST = NSO L = Novosibirsk O = Regolit CN = test.regolit.com emailAddress = se[email protected] [ req_attributes ] challengePassword = 123456 

Вы можете скачать его с моего гитхаба (domain-csr.cnf) в каталог с закрытым ключом, а потом запустить в этом же каталоге такую команду:

[user@shell]% openssl req -new -batch -config domain-csr.cnf -key prime256v1-eckey.pem -out regolit.csr 

cnf-файлы мы ещё будем использовать позднее при создании сертификата. Пока лишь отмечу, что в реальной жизни вам вряд ли понадобится создание CSR таким способ, поскольку удостоверяющий центр обычно берёт из файла запроса очень ограниченный набор данных, фактически только имя и открытый ключ, а всё остальное берёт по другим каналом, например, через форму в кабинете заявителя на сайте УЦ.

Создание тестового удостоверяющего центра¶

Чтобы продемонстрировать весь жизненный цикл сертификата, мы должны также выступить в роли удостоверяющего центра (УЦ, Certification Authority, CA), который проверит переданный ему CSR и сгенерирует на его основе сертификат.

Для более полного понимания мы создадим два простейших УЦ: корневой и промежуточный. Вместе с подписанным сертификатом заявителя мы получим цепочку из трёх. И если корневой сертификат будет доверенным, автоматически будут и оба других.

Сразу важное замечание: описанный здесь процесс ни в коем случае не описывает принципы работы и технологии настоящего удостоверяющего центра, однако общие принципы переданы верно. Также в составе openssl есть команда openssl ca , которая в минимальной степени реализует некоторые технические операции удостоверяющего центра, однако это тоже тема отдельной статьи и в этом тексте я её рассматривать не буду.

Самоподписанный сертификат для корневого УЦ¶

Для корневого удостоверяющего центра мы должны создать отдельный ключ ( demo-root-ca.key ) и самоподписанный сертификат ( demo-root-ca.crt ). Сначала сгенерируем закрытый ключ (эллиптическая кривая secp384r1 ради разнообразия, она тоже поддерживается всеми библиотеками):

[user@shell]% openssl ecparam -name secp384r1 -genkey -out demo-root-ca.key 

Создать самоподписанный сертификат можно той же командой openssl req , которой создаётся CSR, даже аргументы идентичны, только добавляется ещё аргумент -x509 :

[user@shell]% openssl req -new -x509 -batch -days 1000 -key demo-root-ca.key -subj '/C=AQ/O=Penguin Co./CN=Demo Root CA' -out demo-root-ca.crt 

Также мы добавили аргумент -days 1000 , указывающий, что нужно срок действия сертификата выставить в 1000 дней, начиная с текущей даты.

В аргументе -subj передаётся DN поля subject, закодированный в виде строки, об этом формате я писал в разделе Типы данных → Distinguished Name (DN). А о типах атрибутов в нём я писал в разделе Создание CSR в командном режиме.

Просмотр сертификата¶

Просмотр сертификата — это, пожалуй, самая частая операция, которую вы будете делать. Так как первый сертификат мы сделали только что, то и команда для его просмотра в этом разделе. Вот как это выглядит на примере только что созданного сертификата demo-root-ca.crt :

[user@shell]% openssl x509 -text -noout -in demo-root-ca.crt Certificate: Data: Version: 3 (0x2) Serial Number: 01:67:67:4d:23:ef:1e:91:4d:41:b1:df:0b:97:52:70:80:34:a9:03 Signature Algorithm: ecdsa-with-SHA256 Issuer: C = AQ, O = Penguin Co., CN = Demo Root CA Validity Not Before: Sep 1 08:00:26 2020 GMT Not After : May 29 08:00:26 2023 GMT Subject: C = AQ, O = Penguin Co., CN = Demo Root CA Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (384 bit) pub: 04:2d:3a:84:fe:c1:d8:54:ee:93:55:5c:8b:33:15: 2f:bb:46:44:e3:8e:b7:63:b4:17:9c:1b:c3:43:83: c2:ce:ab:6e:bd:01:7b:92:e0:cf:12:f1:0f:ab:db: bc:9f:35:38:da:b8:c0:b1:2e:40:e2:5f:c9:ff:61: 06:d8:2f:95:1d:41:64:ec:eb:8a:da:37:94:0c:41: 12:54:bb:26:5a:44:97:3f:c7:a7:94:e0:67:ad:38: 14:f3:0d:83:f4:5c:0b ASN1 OID: secp384r1 NIST CURVE: P-384 X509v3 extensions: X509v3 Subject Key Identifier: 89:12:EA:73:BC:F2:E2:43:7F:E0:A4:54:A6:60:AE:B7:4D:EA:06:0C X509v3 Authority Key Identifier: keyid:89:12:EA:73:BC:F2:E2:43:7F:E0:A4:54:A6:60:AE:B7:4D:EA:06:0C X509v3 Basic Constraints: critical CA:TRUE Signature Algorithm: ecdsa-with-SHA256 30:65:02:31:00:ba:85:60:9a:18:02:3f:c9:ac:10:ff:f4:7a: be:59:3f:b1:3b:c5:ee:b5:ea:0f:d6:98:45:ee:bb:4f:61:32: 23:f2:5a:b8:aa:a2:aa:9e:0a:fa:e0:da:45:0f:3e:a3:62:02: 30:50:a9:ff:7f:9c:e5:47:1f:e3:95:cb:c2:4c:27:86:75:be: 4f:23:9a:fa:5a:f1:3b:0e:59:1b:09:10:ca:cd:62:e2:38:70: 71:1c:00:22:06:e0:91:50:5c:c5:97:d7:06 

Аргумент -text означает, что мы хотим посмотреть представление сертификата в текстовом человекочитаемом виде, а -noout означает, что собственно содержимое сертификата в виде PEM-блока на экран выводить не нужно.

Структура сертификата в виде ASN.1-определения задана в RFC 5280, раздел 4.1. Basic Certificate Fields:

Certificate ::= SEQUENCE

Если вы внимательно читали предыдущие разделы, то заметите, что структура аналогична CSR: блок данных типа TBSCertificate, идентификатор алгоритма и цифровая подпись. Вся содержательная часть сертификата находится внутри блока с типом TBSCertificate (напомню, что tbs расшифровывается как to be signed, то есть подлежит подписи или требует подписи). TBSCertificate определяется там же в RFC 5280 следующим образом:

TBSCertificate ::= SEQUENCE

Первые семь базовых полей являются обязательными, они всегда есть в любом сертификате (их семантика описана в RFC 5280, раздел 4.1.2 TBSCertificate):

version версия формата сертификата, здесь может быть либо значение 0 (означает версию 1, указывается, когда в рассматриваемом блоке tbsCertificate есть только базовые поля); либо значение 2 (означает версию 3, указывается, когда есть дополнительные поля). Другие значения помимо 0 или 2 в стандарте не определены и на практике не должны использоваться. serialNumber порядковый номер сертификата в реестре УЦ, про него я писал выше, здесь должно быть число, уникальное для каждого сертификата, подписанного конкретным сертификатом УЦ. signature в этом поле указывается идентификатор алгоритма цифровой подписи, которую использовал удостоверяющий центр для подписи сертификата. Формат поля зависит от использованного алгоритма, но всегда включает в себя как минимум OID конкретного алгоритма. issuer здесь содержится имя сертификата УЦ, которым был подписан этот сертификат. Как и в случае с CSR, здесь записывается не строка, а строго структурированное значение distinguished name (DN), я о нём подробно писал в разделе Типы данных → Distinguished Name (DN). validity интервал, в течение которого сертификат может быть доверенным, состоит из двух значений: notBefore и notAfter. subject субъект сертификата, то есть та персона или организация, для которой он был выписан, формат поля — DN, такой же, как и для issuer. Также значение из этого поля принято считать названием или именем сертификата,именно оно используется для отображение в браузере, например. subjectPublicKeyInfo в этом поле записывается открытый ключ субъекта, он состоит из двух последовательных значений: идентификатора алгоритма (поле algorithm, см. Типы данных → AlgorithmIdentifier)) и собственно открытого ключа в бинарной форме (поле subjectPublicKey).

Расширения сертификата (Certificate extensions)¶

Когда openssl создаёт самоподписанный сертификат, то в него автоматически добавляются три расширения: Subject Key Identifier, Authority Key Identifier и Basic Constraints. В текстовом представлении сертификата расширения показываются в секции X509v3 extensions вот так:

 X509v3 extensions: X509v3 Subject Key Identifier: 89:12:EA:73:BC:F2:E2:43:7F:E0:A4:54:A6:60:AE:B7:4D:EA:06:0C X509v3 Authority Key Identifier: keyid:89:12:EA:73:BC:F2:E2:43:7F:E0:A4:54:A6:60:AE:B7:4D:EA:06:0C X509v3 Basic Constraints: critical CA:TRUE 

Я пока отмечу только расширение Basic Constraints, в нём указывается флаг-разрешение, может ли сертификат использоваться для подписывания других сертификатов. Если может, то подписанные им другие сертификаты корректным образом встраиваются в цепочку доверия. Если же разрешения нет, то подписанные сертификаты будут автоматически считаться недоверенными. Так как мы создаём сертификат УЦ, он автоматически помечается как разрешённый для подписывания других.

В расширениях обычно записывается дополнительная информация, которой не нашлось места в базовых полях.

Когда только X.509-сертификаты стали использоваться в SSL, название сайта (домен) записывалось в поле subject, в атрибуте CommonName (CN). Однако очень быстро стало понятно, что этого недостаточно, так как один и тот же сайт может иметь несколько доменных имён и для каждого нужен свой сертификат, поэтому было придумано расширение subjectAltName. В общем же случае расширение subjectAltName призвано отделить имя сертификата от identity, которая в сертификате хранится. Имя записывается в subject, identity — в subjectAltName. Полная спецификация этого расширения описана в RFC 5280, раздел 4.2.1.6 Subject Alternative Name.

Другой пример расширения — Basic Constraints, оно описано в RFC 5280, раздел 4.2.1.9 Basic Constraints. Через него удостоверяющий центр разрешает этому сертификату выступать в роли промежуточного (intermediate). Если такое разрешение прописано, то подписанные таким сертификатом другие сертификаты корректным образом встраиваются в цепочку доверия. Если же разрешения нет, то подписанные сертификаты будут автоматически считаться недоверенными.

У каждого расширения есть идентификатор — OID, например, для Subject Alternative Name это 2.5.29.17, а для Basic Constraints — 2.5.29.19. А формальное описание одного расширения на ASN.1 выглядит так:

Extension ::= SEQUENCE

В поле extnID записывается OID расширения. В булевском поле critical записывается специальный флаг критичности расширения, если он установлен и приложение не знает про такое расширение, то весь сертификат должен помечаться как недоверенный; если же флаг отсутствует, значение подразумевается false. В поле extnValue записывается байтовая строка, интерпретация которой зависит от конкретного расширения. Как правило, она закодирована в DER и для неё где-то существует соответствующее ASN.1 описание.

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

Создание сертификата промежуточного УЦ¶

Сертификат корневого удостоверяющего центра практически никогда не используется для подписи конечных сертификатов заявителей, вместо этого им подписываются сертификаты промежуточных УЦ, а уже потом они используются для подписи конечных сертификатов.

Удостоверяющий центр называется промежуточным (intermediate), если его сертификат (который он использует для подписи) подписан каким-то другим сертификатом и при этом имеет разрешение на подписывание других сертификатов (через расширение Basic Constraints). Мы сделаем свой тестовый промежуточный УЦ, у него будет собственный ключ и собственный сертификат. Закрытый ключ на этот раз будет RSA 2048 бит и в формате PKCS#8:

[user@shell]% openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -out demo-intermediate-ca.key ..+++++ . +++++ 

Дальше создаём CSR:

[user@shell]% openssl req -new -batch -key demo-intermediate-ca.key \ -subj '/C=RU/L=Omsk/CN=Demo Intermediate Authority' -out demo-intermediate-ca.csr 

Создаём файл demo-intermediate-ca-crt.cnf с параметрами расширений, которые мы хотим включить в сертификат:

[cert_ext] authorityKeyIdentifier = keyid subjectKeyIdentifier = hash basicConstraints = critical, CA:true keyUsage = digitalSignature, keyCertSign 

Вот что каждая строчка в нём означает:

authorityKeyIdentifier = keyid Идентификатор ключа «родительского» удостоверяющего центра автоматически берётся из расширения Subject Key Identifier того сертификата, которым подписываем данный. subjectKeyIdentifier = hash Идентификатора собственного ключа порождается автоматически из открытого ключа по алгоритму из RFC 5280. basicConstraints = critical, CA:true Критичное расширение Basic Constraints, разрешающее выступать в роли удостоверяющего центра. keyUsage = digitalSignature, keyCertSign Разрешения, как можно использовать сертификата: цифровая подпись и подписывание других сертификатов.

И, наконец, создаём сертификат demo-intermediate-ca.crt , используя конфигурационный файл:

[user@shell]% openssl x509 -req -in demo-intermediate-ca.csr -days 365 \ -CA demo-root-ca.crt -CAkey demo-root-ca.key -CAcreateserial -extfile demo-intermediate-ca-crt.cnf \ -extensions cert_ext -out demo-intermediate-ca.crt 

Пояснения по новым аргументам:

-req указывает, что на вход в аргументе -in regolit.csr ожидается именно Certificate Signing Request; -days 365 выписываем сертификат на 365 дней; -CA demo-root-ca.crt -CAkey demo-root-ca.key указываем сертификат и закрытый ключ УЦ, из сертификата demo-root-ca.pem будет взято поле subject и вставлено в итоговой сертификат в поле issuer ; -CAcreateserial это означает, что будет создан файл с именем demo-root-ca.srl , в который будет записан серийный номер сертификата, а дальше openssl из этого файла возьмёт значение и запишет в сертификат, про серийный номер я уже писал выше в теоретическом разделе, это должно быть число, уникальное для каждого сертификата, подписанного конкретным сертификатом УЦ. В реальном удостоверяющем центре ведётся реестр выписанных сертификатов и для каждого создаётся собственный уникальный serialNumber. Вы можете создать файл demo-root-ca.srl самостоятельно и прописать туда любое число. При каждом запуске команды создания сертификата на базе CSR значение в этом файле увеличивается на единицу. Если файла нет и аргумент -CAcreateserial не указан, то openssl выдаст ошибку. Если файл уже существует, то аргумент -CAcreateserial игнорируется. -extfile demo-intermediate-ca-crt.cnf Путь к файлу с параметрами расширений. -extensions cert_ext Название секции в файле, где собственно и записаны параметры расширений.

К этом моменту у нас есть тестовый удостоверяющий центр, сертификатом которого ( demo-intermediate-ca.crt ) мы можем подписывать сертификаты заявителей.

Создание сертификата из CSR¶

Несколькими разделами ранее мы создали CSR в файле regolit.csr , также мы сделали цепочку из двух тестовых удостоверяющих центров: корневого и промежуточного. И теперь готовы подписать CSR-запрос сертификатом промежуточного УЦ demo-intermediate-ca.crt . Последовательность действий здесь практически такая же, только будут прописаны другие расширения.

Удостоверяющий центр при создании сертификата на базе CSR заявителя обычно действует так:

  • из CSR берутся: имя из поля subject и открытый ключ;
  • из сертификата УЦ берётся значение поле subject, оно пойдёт в поле issuer сертификата;
  • из другого источника берутся данные для расширений, например, список дополнительных доменов для расширения Subject Alternative Name, которые заявитель указал через форму на веб-сайте УЦ;
  • из внутренней базы удостоверяющего центра берутся данные для других полей и расширений;
  • на основе собранных данных собирается сертификат, подписывается закрытым ключом и отдаётся заявителю.

Создаём файл с параметрами расширений ( regolit-crt.cnf ) со следующим содержимым:

[cert_ext] authorityKeyIdentifier = keyid basicConstraints = critical, CA:false subjectAltName = DNS:regolit.com, DNS:www.regolit.com keyUsage = digitalSignature 

В нём заданы такие параметры:

authorityKeyIdentifier = keyid Идентификатор ключа удостоверяющего центра автоматически берётся из расширения Subject Key Identifier того сертификата, которым подписываем данный, то есть из demo-intermediate-ca.crt . basicConstraints = critical, CA:false УЦ явным образом запрещает создаваемый сертификат использовать для подписывания других сертификатов. Кроме того, значение помечено как критическое. subjectAltName = DNS:regolit.com, DNS:www.regolit.com Перечисляем все дополнительные записи-identity, которые мы хотим добавить в сертификат keyUsage = digitalSignature Разрешаем использование сертификата для проверки цифровой подписи.

И вот итоговая команда:

[user@shell]% openssl x509 -req -in regolit.csr -days 365 -CA demo-intermediate-ca.crt \ -CAkey demo-intermediate-ca.key -CAcreateserial -extfile regolit-crt.cnf -extensions cert_ext -out regolit.crt 

Получаем вот такой сертификат с расширениями:

[user@shell]% openssl x509 -in regolit.crt -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 5a:25:eb:62:a4:84:9f:75:42:9a:6e:d0:ac:aa:0b:d8:eb:34:26:d4 Signature Algorithm: sha256WithRSAEncryption Issuer: C = RU, L = Omsk, CN = Demo Intermediate Authority Validity Not Before: Sep 1 10:06:40 2020 GMT Not After : Sep 1 10:06:40 2021 GMT Subject: C = RU, ST = NSO, L = Novosibirsk, O = Regolit, CN = test.regolit.com, emailAddress = [email protected] Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:16:82:ea:92:e6:3a:04:62:0a:16:b4:04:ec:1d: . skipped. 50:50:63:d6:70 ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: DNS:regolit.com, DNS:www.regolit.com X509v3 Key Usage: Digital Signature Signature Algorithm: sha256WithRSAEncryption 3b:2a:fd:fc:0d:9a:ae:9a:d5:83:d8:74:28:a1:87:6a:58:ab: . skipped. 1f:8c:70:29 

Тестирование сертификатов¶

Для проверки сертификатов можно воспользоваться командами openssl s_server и openssl s_client . Первая запускает простейший TLS веб-сервер с указанными сертификатами и на указанном адресе. А вторая обращается к любому указанному адресу и верифицирует соединение.

Важное свойство этих команд в том, что вы полностью контролируете формирование цепочки доверия. Например, вы можете указать для openssl s_client файл с доверенными сертификатами и тогда при установке соединения цепочки будут строиться только с использованием указанных сертификатов, а не всех системных. Аналогично с openssl s_server — вы можете указать, какие промежуточные сертификаты передавать клиентами при установке соединения.

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

Сначала выступаем в роли заявителя, который хочет запустить веб-сервер с только что полученным сертификатом. У заявителя есть сертификат — файл regolit.crt , закрытый ключ — prime256v1-eckey.pem , а также сертификат удостоверяющего центра — demo-intermediate-ca.crt . При этом предполагается, что в браузере клиента в списке доверенных сертификатов есть корневой сертификат demo-root-ca.crt , но при этом там нет промежуточного сертификата demo-intermediate-ca.crt .

В первом терминале запускаем такую команду для старта TLS веб-сервера:

[user@shell]% openssl s_server -accept 127.0.0.1:9443 -key prime256v1-eckey.pem -cert regolit.crt -cert_chain demo-intermediate-ca.crt Using default temp DH parameters ACCEPT 

Если всё сделано правильно и в каталоге лежат нужные файлы, программа запустит веб-сервер по адресу https://127.0.0.1:9443, вы даже можете открыть его в браузере, но он сразу выдаст вам ошибку вида NET::ERR_CERT_AUTHORITY_INVALID .

Теперь запустим в другом терминале команду для проверки соединения (указываем аргументы -no-CApath , чтобы не использовать системное хранилище доверенных сертификатов и -quiet , чтобы не показывать подробную информацию о соединении, в аргументе -servername www.regolit.com указываем название домена, которое клиент передаёт при инициализации соединения в расширении протокола TLS Server Name Indication / SNI 1 ):

[user@shell]% openssl s_client -connect 127.0.0.1:9443 -no-CApath -CAfile demo-root-ca.crt -servername www.regolit.com -quiet depth=2 C = AQ, O = Penguin Co., CN = Demo Root CA verify return:1 depth=1 C = RU, L = Omsk, CN = Demo Intermediate Authority verify return:1 depth=0 C = RU, ST = NSO, L = Novosibirsk, O = Regolit, CN = test.regolit.com, emailAddress = [email protected] verify return:1 

Программа выдаёт поле subject каждого из сертификатов в построенной цепочке, в данном случае она успешно построена и проверифицирована, так как сообщений об ошибке нет. Сертификат сервера показывается в самом низу. Программа ждёт от вас ввода HTTP-запроса, но мы пока это пропустим и просто нажмём Ctrl+C, чтобы завершить команду.

Если мы в команде вместо аргумента -CAfile demo-root-ca.crt укажем -no-CAfile (означает, что у клиента нет доверенного корневого сертификата), то получим такое:

[user@shell]% openssl s_client -connect 127.0.0.1:9443 -no-CApath -no-CAfile -servername www.regolit.com -quiet depth=1 C = RU, L = Omsk, CN = Demo Intermediate Authority verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = RU, ST = NSO, L = Novosibirsk, O = Regolit, CN = test.regolit.com, emailAddress = [email protected] verify return:1 

Так как доверенного сертификата у клиента нет, он не может построить корректную цепочку доверия, поэтому выдаёт ошибку verify error:num=20:unable to get local issuer certificate . Однако по-прежнему показывает, что от сервера пришло два сертификата. Снова завершаем программу по Ctrl+C.

Следующий сценарий: сервер при соединии отдаёт только сертификат домена без промежуточного (убираем аргумент -cert_chain ):

[user@shell]% openssl s_server -accept 127.0.0.1:9443 -key prime256v1-eckey.pem -cert regolit.crt Using default temp DH parameters ACCEPT 

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

[user@shell]% openssl s_client -connect 127.0.0.1:9443 -no-CApath -CAfile demo-root-ca.crt -servername www.regolit.com -quiet depth=0 C = RU, ST = NSO, L = Novosibirsk, O = Regolit, CN = test.regolit.com, emailAddress = [email protected] verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = RU, ST = NSO, L = Novosibirsk, O = Regolit, CN = test.regolit.com, emailAddress = [email protected] verify error:num=21:unable to verify the first certificate verify return:1 

verify error:num=20:unable to get local issuer certificate Эта ошибка означает, что клиент не смог найти сертификат, которым подписан сертификат домена — сервер промежуточный сертификат в запросе не передал. Буквальный текст описания этой ошибки из openssl: the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found. verify error:num=21:unable to verify the first certificate Клиент не смог создать верифицированную цепочку доверия, включающую сертификат сайта. Буквальный текст описания этой ошибки из openssl: no signatures could be verified because the chain contains only one certificate and it is not self signed.

Если вы хотите протестировать на «живом» окружении, можете импортировать корневой сертификат demo-root-ca.crt в системное хранилище сертификатов и пометить его как доверенный. Тогда вы сможете открыть тестовый URL в обычном браузере.

Верификация цепочки сертификатов¶

Для верификации сертификата вам нужна цепочка доверия, завершающаяся корневым сертификатом. У нас уже есть все нужные для этого файлы и мы можем записать сертфикаты удостоверяющих центров в один файл и затем использовать его для верификации при помощи команды openssl verify :

[user@shell]% cat demo-intermediate-ca.crt demo-root-ca.crt > chain.pem [user@shell]% openssl verify -no-CApath -CAfile chain.pem regolit.crt regolit.crt: OK 

Здесь мы сначала записываем оба наших сертификата УЦ в один файл chain.pem и дальше используе его для верификации.

Если мы не хотим строить целиком цепочку, а хотим только проверить, подписан ли один сертификат другим, нужно добавить аргумент -partial_chain :

[user@shell]% openssl verify -no-CApath -CAfile demo-intermediate-ca.crt -partial_chain regolit.crt regolit.crt: OK 

Здесь мы указали в качестве «цепочки» только один — промежуточный — сертификат удостоверяющего центра demo-intermediate-ca.crt , и без аргумента -partial_chain мы бы получили ошибку верификации:

[user@shell]% openssl verify -no-CApath -CAfile demo-intermediate-ca.crt regolit.crt C = RU, L = Omsk, CN = Demo Intermediate Authority error 2 at 1 depth lookup: unable to get issuer certificate error regolit.crt: verification failed 

Использование сертификатов для цифровой подписи любых файлов¶

От одного из предыдущих этапов у нас остался сертификат в файле regolit.crt и закрытый ключ для него — prime256v1-eckey.pem , мы им подпишем файл demo-intermediate-ca.crt :

[user@shell]% openssl dgst -sha256 -sign prime256v1-eckey.pem -out demo-intermediate-ca.crt.sig demo-intermediate-ca.crt 

Здесь мы используем команду openssl dgst , основное назначение которой — подсчёт дайджеста файла (то есть криптографического хеша). Однако эта же команда умеет генерировать и верифицировать цифровые подписи. Для генерации мы передаём закрытый ключ в аргументе -sign prime256v1-eckey.pem .

В openssl на текущий момент (5 сентября 2020 года) не существует штатной команды для проверки цифровой подписи при помощи сертификата, вам придётся вручную отдельно выделить открытый ключ из сертификата и дальше уже им верифицировать.

Выделяем открытый ключ из сертификата:

[user@shell]% openssl x509 -in regolit.crt -pubkey -noout > regolit-pubkey.pem 

И верифицируем файл demo-intermediate-ca.crt , используя цифровую подпись и выделенный только что открытый ключ:

[user@shell]% openssl dgst -sha256 -verify regolit-pubkey.pem -signature demo-intermediate-ca.crt.sig demo-intermediate-ca.crt Verified OK 

Проверка соответствия сертификата и закрытого ключа¶

Есть два файла: сертификат ( cert.pem ) и закрытый ключ ( key.pem ), нужно проверить, соответствует ли открытый ключ из сертификата этому закрытому ключу. Обычно этот вопрос решают через экспорт открытого ключа из сертификата и закрытого ключа, и последующего их сравнения, однако этот метод для разных алгоритмов использует очень разные команды, поэтому я буду пользоваться способом из предыдущего раздела — через цифровую подпись.

    Сделаем цифровую подпись файла cert.pem , используя закрытый ключ.

[user@shell]% openssl dgst -sha256 -sign key.pem -out test.sig cert.pem 
[user@shell]% openssl x509 -in cert.pem -pubkey -noout -out cert-pubkey.pem 
[user@shell]% openssl dgst -sha256 -verify cert-pubkey.pem -signature test.sig cert.pem Verified OK 

Использование сертификатов для шифрования¶

Этот раздел довольно экстремальный, поскольку описанный в нём метод мало подходит для практического применения. Однако он описывает подход, применяемый в современном TLS-шифровании веб-трафика.

В общем случае X.509-сертификаты не предназначены для шифрования данных, единственный пригодный для этого алгоритм — RSA, однако это исключение. Тем не менее, в разделе Используемые криптоалгоритмы я рассказал, как можно использовать сертификаты совместно с протоколом Diffie-Hellman для безопасного обмена ключами симметричного шифрования. А в этом разделе я расскажу, как это можно реализовать на практике через команды openssl.

Действующие лица: Алиса и Боб, у каждого из них есть свой X.509-сертификат с закрытым ключом, причём Алиса и Боб заранее обменялись сертификатами каким-то надёжным способом (например, при личной встрече). И с этого момента весь обмен данными происходит через небезопасный открытый канал.

Алиса хочет организовать безопасный сеанс связи с Бобом поверх небезопасного канала. Для этого отлично подходит симметричный алгоритм AES-128-CBC, однако для него обе стороны должны использовать одинаковый ключ — набор байтов размером 128 бит. Алиса и Боб будут для обмена ключом пользоваться протоколом Diffie-Hellman с аутентификацией через цифровые подписи.

Создадим сначала сертификаты и закрытые ключи к ним для каждой из сторон. Алиса создаёт закрытый ключ alice-x509.key и самоподписанный сертификат alice-x509.crt :

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout -out alice-x509.key [user@shell]% openssl req -new -x509 -batch -days 5000 -key alice-x509.key -subj '/CN=Alice' -out alice-x509.crt 

И Боб делает то же самое — ключ в файле bob-x509.key и самоподписанный сертификат bob-x509.crt :

[user@shell]% openssl ecparam -name prime256v1 -genkey -noout -out bob-x509.key [user@shell]% openssl req -new -x509 -batch -days 5000 -key bob-x509.key -subj '/CN=Bob' -out bob-x509.crt 

Дальше стороны должны заранее надёжным и безопасным способом передать друг-другу свои сертификаты.

Через какое-то время Алиса захотела обменяться важными данными с Бобом через e-mail. Это начало новой сессии обмена, в которой будут использоваться новые ключи (эфемерные, то есть не фиксированные, а созданные специально для этого момента, после сессии эфемерные ключи стираются), поэтому Алиса должна выбрать параметры протокола Diffie-Hellman, это делается такой командой:

[user@shell]% openssl dhparam -dsaparam -out dhp.pem 4096 Generating DSA parameters, 4096 bit long prime . +. + 

Здесь 4096 означает размер случайного простого числа в битах, он в настоящее время считается безопасным. Теперь Алиса на основе этого файла с параметрами создаёт свой закрытый ключ dh-alice.key (это ещё не эфемерный ключ, а только заготовка для него!):

[user@shell]% openssl genpkey -paramfile dhp.pem -out alice-dh.key 

И выделяет из него открытый ключ:

[user@shell]% openssl pkey -in alice-dh.key -pubout -out alice-dh-pub.pem 

Затем Алиса конкатенирует два файла dhp.pem и alice-dh-pub.pem в один alice2bob.pem :

[user@shell]% cat dhp.pem alice-dh-pub.pem > alice2bob.pem 

И создаёт цифровую подпись для него (в виде отдельного файла alice2bob.pem.sig ), используя свой закрытый ключ от X.509-сертификата:

[user@shell]% openssl dgst -sha256 -sign alice-x509.key -out alice2bob.pem.sig alice2bob.pem 

Дальше Алиса отправляет Бобу два файла: alice2bob.pem и alice2bob.pem.sig .

Боб получает от Алисы файл и цифровую подпись. Для проверки подписи ему сначала нужно извлечь из сертификата Алисы открытый ключ в файл alice-x509-pubkey.pem :

[user@shell]% openssl x509 -in alice-x509.crt -pubkey -noout > alice-x509-pubkey.pem 

И дальше проверить им цифровую подпись:

[user@shell]% openssl dgst -sha256 -verify alice-x509-pubkey.pem -signature alice2bob.pem.sig alice2bob.pem Verified OK 

Проверка прошла успешно, теперь Боб уверен, что полученный им файл alice2bob.pem действительно пришёл от Алисы, поэтому можно продолжать. Боб создаёт свой закрытый DH-ключ на основе полученных параметров:

[user@shell]% openssl genpkey -paramfile alice2bob.pem -out bob-dh.key 

Обратите внимание, что в аргументе с параметрами указан файл alice2bob.pem , в котором записано два разных PEM-блока, но так как PEM — это контейнер, openssl берёт из него только те данные, которые ему нужны в текущем контексте, а здесь контекст — это параметры DH, именно такой блок и будет прочитан. Другими словами, нет никакой необходимости разделять файл на части.

Дальше Боб выделяет открытый ключ на основе только что созданного закрытого:

[user@shell]% openssl pkey -in bob-dh.key -pubout -out bob-dh-pub.pem 

И, наконец, создаёт свой эфемерный закрытый ключ в файле bob-secret.key :

[user@shell]% openssl pkeyutl -derive -inkey bob-dh.key -peerkey alice2bob.pem -out bob-secret.key 

Теперь Боб создаёт цифровую подпись для своего открытого DH-ключа:

[user@shell]% openssl dgst -sha256 -sign bob-x509.key -out bob-dh-pub.pem.sig bob-dh-pub.pem 

И отправляет Алисе два файла: bob-dh-pub.pem и bob-dh-pub.pem.sig .

Алиса проверяет цифровую подпись аналогичным образом: выделяет открытый ключ из сертификата Боба и верифицирует файл bob-dh-pub.pem с подписью bob-dh-pub.pem.sig :

[user@shell]% openssl x509 -in bob-x509.crt -pubkey -noout > bob-x509-pubkey.pem [user@shell]% openssl dgst -sha256 -verify bob-x509-pubkey.pem -signature bob-dh-pub.pem.sig bob-dh-pub.pem Verified OK 

И, наконец, Алиса создаёт свой эфемерный ключ на основе собственного закрытого DH-ключа ( alice-dh.key ) и полученного от Боба открытого DH-ключа ( bob-dh-pub.pem ):

[user@shell]% openssl pkeyutl -derive -inkey alice-dh.key -peerkey bob-dh-pub.pem -out alice-secret.key 

Мы можем убедиться, что оба их эфемерных ключа одинаковые:

[user@shell]% diff -s alice-secret.key bob-secret.key Files alice-secret.key and bob-secret.key are identical 

Теперь Алиса может зашифровать файл alice-message.txt (внутри которого только одна строчка: Very secret message.), используя эфемерный ключ в качестве пароля:

[user@shell]% openssl enc -e -md md5 -pass file:alice-secret.key -aes-128-cbc \ -in alice-message.txt -out alice-message.txt.encrypted 

Здесь мы используем алгоритм хеширования MD5, чтобы получить из файла эфемерного ключа ровно 128 бит AES-ключа.

Боб теперь может расшифровать файл так:

[user@shell]% openssl enc -d -md md5 -pass file:bob-secret.key -aes-128-cbc -in alice-message.txt.encrypted Very secret message. 

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

Несколько примеров необычных сертификатов¶

Возьмём вот этот сертификат, это корневой сертификат Казахстанского центра межбанковских расчётов национального банка Республики Казахстан.

Вот как выглядит попытка распечатать его в текстовом виде:

Certificate: Data: Version: 3 (0x2) Serial Number: 1e:97:16:12:b3:4f:8d:e4:e8:39:8b:da:34:f5:1e:f5:3f:c6:0f:b8:29:cf:7a:07:c0:7a:db:f5:9f:e9:12:0b Signature Algorithm: 1.3.6.1.4.1.6801.1.2.2 Issuer: CN=KISC Root CA, O=KISC, C=KZ Validity Not Before: Sep 2 12:28:57 2008 GMT Not After : Aug 28 12:28:57 2028 GMT Subject: CN=KISC Root CA, O=KISC, C=KZ Subject Public Key Info: Public Key Algorithm: 1.3.6.1.4.1.6801.1.5.8 Unable to load Public Key 4594828908:error:06FFF09C:digital envelope routines:CRYPTO_internal:unsupported algorithm:/p_lib.c:241: 4594828908:error:0BFFF06F:x509 certificate routines:CRYPTO_internal:unsupported algorithm:x_pubkey.c:199: X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Subject Key Identifier: 1E:97:16:12:B3:4F:8D:E4:E8:39:8B:DA:34:F5:1E:F5:3F:C6:0F:B8:29:CF:7A:07:C0:7A:DB:F5:9F:E9:12:0B X509v3 Authority Key Identifier: keyid:1E:97:16:12:B3:4F:8D:E4:E8:39:8B:DA:34:F5:1E:F5:3F:C6:0F:B8:29:CF:7A:07:C0:7A:DB:F5:9F:E9:12:0B DirName:/CN=KISC Root CA/O=KISC/C=KZ serial:1E:97:16:12:B3:4F:8D:E4:E8:39:8B:DA:34:F5:1E:F5:3F:C6:0F:B8:29:CF:7A:07:C0:7A:DB:F5:9F:E9:12:0B Signature Algorithm: 1.3.6.1.4.1.6801.1.2.2 b4:dc:79:0f:a7:94:8f:fa:90:22:18:f9:22:27:30:83:33:59: af:b9:68:6b:1d:40:75:ad:87:e0:ff:46:37:3c:0a:78:55:b4: c3:b1:1a:8f:6c:62:37:ad:38:1b:9c:b6:1c:ac:68:16:37:c1: 8e:ae:6e:9c:7a:c4:00:6d:ff:3a 

Сразу же видим, что openssl не знает ни алгоритма открытого ключа (OID 1.3.6.1.4.1.6801.1.5.8), ни алгоритма цифровой подписи (OID 1.3.6.1.4.1.6801.1.2.2). Репозиторий oid-info.com тоже не знает про них ничего, однако знает google — это идентификаторы объектов из проприетарного ПО TumarCSP, которое используется в Казахстане. По факту это другие идентификаторы для объектов ГОСТовских криптоалгоритмов.

Следующий файл для препарирования — старый сертификат удостоверяющего центра Бурятии (ca-bur.der). Его текстовое представление великолепно:

Certificate: Data: Version: 3 (0x2) Serial Number: 1e:5d:f6:44:00:00:00:00:02:51 Signature Algorithm: GOST R 34.11-94 with GOST R 34.10-2001 Issuer: INN = 007710474375, OGRN = 1047702026701, emailAddress = [email protected], street = 125375 \D0\B3. \D0\9C\D0\BE\D1\81\D0\BA\D0\B2\D0\B0 \D1\83\D0\BB. \D0\A2\D0\B2\D0 \B5\D1\80\D1\81\D0\BA\D0\B0\D1\8F \D0\B4.7, O = \D0\9C\D0\B8\D0\BD\D0\BA\D0\BE\D0\BC\D1\81 \D0\B2\D1\8F\D0\B7\D1\8C \D0\A0\D0\BE\D1\81\D1\81\D0\B8\D0\B8, L = \D0\9C\D0\BE\D1\81\D0\BA \D0\B2\D0\B0, ST = 77 \D0\B3.\D0\9C\D0\BE\D1\81\D0\BA\D0\B2\D0\B0, C = RU, CN = \D0\A3\D0\A6 2 \D0\98\D0\A1 \D0\93\D0\A3\D0\A6 Validity Not Before: Jun 17 06:35:00 2014 GMT Not After : Jul 22 06:54:00 2017 GMT Subject: OGRN = 1020300972361, INN = 000323082280, street = \D1\83\D0\BB. \D0\9B\D0\B5 \D0\BD\D0\B8\D0\BD\D0\B0 54, emailAddress = [email protected], C = RU, ST = 03 \D0\A0\D0\B5\D1 \81\D0\BF\D1\83\D0\B1\D0\BB\D0\B8\D0\BA\D0\B0 \D0\91\D1\83\D1\80\D1\8F\D1\82\D0\B8\D1\8F, L = \D0\A3\D0\BB\D0\B0\D0\BD-\D0\A3\D0\B4\D1\8D, O = \D0\90\D0\B4\D0\BC\D0\B8\D0\BD\D0\B8\D1\81\D1\82 \D1\80\D0\B0\D1\86\D0\B8\D1\8F \D0\93\D0\BB\D0\B0\D0\B2\D1\8B \D0\A0\D0\91 \D0\B8 \D0\9F\D1\80\D0 \B0\D0\B2\D0\B8\D1\82\D0\B5\D0\BB\D1\8C\D1\81\D1\82\D0\B2\D0\B0 \D0\A0\D0\91, CN = \D0\A3\D0\A6 \D0 \A0\D0\B5\D1\81\D0\BF\D1\83\D0\B1\D0\BB\D0\B8\D0\BA\D0\B8 \D0\91\D1\83\D1\80\D1\8F\D1\82\D0\B8\D1\8F Subject Public Key Info: Public Key Algorithm: GOST R 34.10-2001 Unable to load Public Key 140269877257344:error:0609E09C:digital envelope routines:pkey_set_type:unsupported algorithm. /crypto/evp/p_lib.c:210: 140269877257344:error:0B09406F:x509 certificate routines:x509_pubkey_decode:unsupported algorithm. /crypto/x509/x_pubkey.c:114: X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Subject Key Identifier: 55:D2:55:96:82:D3:B1:E3:62:EC:60:34:BE:D3:42:19:C3:45:B5:74 X509v3 Key Usage: Digital Signature, Certificate Sign, CRL Sign 1.3.6.1.4.1.311.21.1: . X509v3 Certificate Policies: Policy: 1.2.643.100.113.1 Policy: 1.2.643.100.113.2 Policy: X509v3 Any Policy Signing Tool of Subject: .-". CSP" (. 3.6.1) X509v3 Authority Key Identifier: keyid:C6:6B:C1:02:A2:92:AA:14:0A:0A:4A:14:FD:19:1D:0D:57:D0:44:9C DirName:/[email protected]/C=RU/ST=77 \xD0\xB3. \xD0\x9C\xD0\xBE\xD1 \x81\xD0\xBA\xD0\xB2\xD0\xB0/L=\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0 serial:3C:82:25:19:00:00:00:00:00:18 X509v3 CRL Distribution Points: Full Name: URI:http://rostelecom.ru/cdp/vguc2.crl Full Name: URI:http://reestr-pki.ru/cdp/vguc2.crl Authority Information Access: CA Issuers - URI:http://rostelecom.ru/cdp/vguc2.crt CA Issuers - URI:http://reestr-pki.ru/cdp/vguc2.crt X509v3 Private Key Usage Period: Not Before: Jun 17 06:35:00 2014 GMT, Not After: Jun 17 06:35:00 2018 GMT Signing Tool of Issuer: 0. -". CSP" (. 3.6.1).S". . ". . " . 1.5.%. . /124-2239 . 04.10.2013 . %. . /128-1823 . 01.06.2012 . Signature Algorithm: GOST R 34.11-94 with GOST R 34.10-2001 3c:eb:c0:76:c9:3a:71:89:1a:b4:66:00:7f:ab:4d:ef:06:d8: bf:df:f7:23:d8:41:56:8e:65:af:5a:59:f9:f9:83:7a:d4:56: c5:53:26:44:bf:c8:46:e8:18:e9:ca:7d:74:4d:83:50:f5:d9: ac:0c:3b:2b:b1:ac:17:2b:9c:41 

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

Отображение кириллицы частично можно исправить, добавив аргумент -nameopt sep_multiline,utf8 :

[user@shell]% openssl x509 -inform DER -noout -text -in ca-bur.der -nameopt sep_multiline,utf8 Certificate: Data: Version: 3 (0x2) Serial Number: 1e:5d:f6:44:00:00:00:00:02:51 Signature Algorithm: GOST R 34.11-94 with GOST R 34.10-2001 Issuer: INN=007710474375 OGRN=1047702026701 [email protected] street=125375 г. Москва ул. Тверская д.7 O=Минкомсвязь России L=Москва ST=77 г.Москва C=RU CN=УЦ 2 ИС ГУЦ Validity Not Before: Jun 17 06:35:00 2014 GMT Not After : Jul 22 06:54:00 2017 GMT Subject: OGRN=1020300972361 INN=000323082280 street=ул. Ленина 54 [email protected] C=RU ST=03 Республика Бурятия L=Улан-Удэ O=Администрация Главы РБ и Правительства РБ CN=УЦ Республики Бурятия Subject Public Key Info: Public Key Algorithm: GOST R 34.10-2001 Unable to load Public Key 140283884340352:error:0609E09C:digital envelope routines:pkey_set_type:unsupported algorithm. /crypto/evp/p_lib.c:210: 140283884340352:error:0B09406F:x509 certificate routines:x509_pubkey_decode:unsupported algorithm. /crypto/x509/x_pubkey.c:114: X509v3 extensions: X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Subject Key Identifier: 55:D2:55:96:82:D3:B1:E3:62:EC:60:34:BE:D3:42:19:C3:45:B5:74 X509v3 Key Usage: Digital Signature, Certificate Sign, CRL Sign 1.3.6.1.4.1.311.21.1: . X509v3 Certificate Policies: Policy: 1.2.643.100.113.1 Policy: 1.2.643.100.113.2 Policy: X509v3 Any Policy Signing Tool of Subject: .-". CSP" (. 3.6.1) X509v3 Authority Key Identifier: keyid:C6:6B:C1:02:A2:92:AA:14:0A:0A:4A:14:FD:19:1D:0D:57:D0:44:9C DirName:/[email protected]/C=RU/ST=77 \xD0\xB3. \xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0/L=\xD0\x9C\xD0\xBE\xD1\x81 \xD0\xBA\xD0\xB2\xD0\xB0 serial:3C:82:25:19:00:00:00:00:00:18 X509v3 CRL Distribution Points: Full Name: URI:http://rostelecom.ru/cdp/vguc2.crl Full Name: URI:http://reestr-pki.ru/cdp/vguc2.crl Authority Information Access: CA Issuers - URI:http://rostelecom.ru/cdp/vguc2.crt CA Issuers - URI:http://reestr-pki.ru/cdp/vguc2.crt X509v3 Private Key Usage Period: Not Before: Jun 17 06:35:00 2014 GMT, Not After: Jun 17 06:35:00 2018 GMT Signing Tool of Issuer: 0. -". CSP" (. 3.6.1).S". . ". . " . 1.5.%. . /124-2239 . 04.10.2013 . %. . /128-1823 . 01.06.2012 . Signature Algorithm: GOST R 34.11-94 with GOST R 34.10-2001 3c:eb:c0:76:c9:3a:71:89:1a:b4:66:00:7f:ab:4d:ef:06:d8: bf:df:f7:23:d8:41:56:8e:65:af:5a:59:f9:f9:83:7a:d4:56: c5:53:26:44:bf:c8:46:e8:18:e9:ca:7d:74:4d:83:50:f5:d9: ac:0c:3b:2b:b1:ac:17:2b:9c:41 

Однако данные внутри расширений по-прежнему отображаются в закодированном виде.

В качестве алгоритма открытого ключа используется GOST R 34.10-2001, а для цифровой подписи — хеш-функция GOST R 34.11-94 с алгоритмом цифровой подписи GOST R 34.10-2001

Примечания¶

  1. Расширение протокола TLS Server Name Indication (сокращённо SNI) позволяет при инициализации TLS-соединения передать серверу домен веб-сайта, чтобы сервер выбрал подходящий сертификат именно для этого сайта. Без такого расширения сервер всегда отдавал одинаковый сертификат при соединеннии к конкретному IP-адресу и если на нём было несколько разных HTTPS-сайтов, начинались проблемы с сертификатом. ↩

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *