Создание сертификатов при помощи OpenSSL
OpenSSL является библиотекой по работе с криптографией, но в этой статье я затрону только часть функций этого инструмента, а именно создание само-подписанных сертификатов.
Создание центра сертификации
При помощи корневого сертификата, мы будем подписывать сертификаты клиентские. Создаём сертификат центра сертификации…
Где:
-days '3650'
- количество дней, по прошествии которого сертификат центра сертификации станет недействительным.-keyout 'ca.root.key'
- название создаваемого файла с ключом центра сертификации.-out 'ca.root.crt'
- название создаваемого файла с сертификатом центра сертификации.
Создание клиентского сертификата
Как только будет готов корневой сертификат, можно приступать к выпуску клиентских сертификатов.
Создание приватного ключа
Для начала создаём приватный ключ.
Где:
-out 'client.key.private.pem'
- название создаваемого файла с клиентским приватным ключом.
Создание публичного ключа
Создание публичного ключа будет не лишним.
Где:
-in 'client.key.private.pem'
- файл c клиентским приватным ключом.-out 'client.key.public.pem'
- название создаваемого файла с клиентским публичным ключом.
Создание запроса на подпись сертификата
Выполняем запрос на сертификат.
Где:
-key 'client.key.private.pem'
- файл с приватным ключом клиентского сертификата.-out 'client.csr'
- название создаваемого файла с запросом на подпись клиентского сертификата.
При выполнении запроса будет предложено ввести актуальные данные для будущего сертификата:
Country Name (2 letter code)
- двухбуквенный код страны, в которой юридически находится ваша организация.State or Province Name (full name)
- штат или провинция, в которой юридически находится ваша организация.Locality Name (e.g., city)
- город, в котором юридически находится ваша организация.Organization Name (e.g., company)
- юридически зарегистрированное название вашей организации.Organizational Unit Name (e.g., section)
- название вашего отдела в организации (опционально).Common Name (e.g., server FQDN)
- полное доменное имя (FQDN) (например, www.example.com).Email Address
- ваш адрес email (опционально).A challenge password
- пароль (опционально).An optional company name
- необязательное название компании (опционально).
Самое главное поле это Common Name (e.g., server FQDN)
(CN
), заполнять его необходимо очень внимательно.
Создание и подпись сертификата
В заключительной части остаётся только создать сам сертификат и подписать его.
Где:
-in 'client.csr'
- файл с запросом клиентского сертификата.-CA 'ca.crt'
- файл с сертификатом центра сертификации.-CAkey 'ca.key'
- файл с ключом центра сертификации.-days '3650'
- количество дней, по прошествии которого клиентский сертификат станет недействительным.-out 'client.crt'
- название создаваемого файла с клиентским сертификатом.
Экспорт сертификата
Для того, чтобы импортировать сертификат на клиентские устройства, его необходимо экспортировать в формат P12
. P12
является контейнером, в котором содержится приватный ключ сертификата и сам сертификат.
Где:
-inkey 'client.key.private.pem'
- файл с приватным клиентским ключом.-in 'client.crt'
- файл с клиентским сертификатом.-out 'client.p12'
- название создаваемого файла-контейнера с приватным ключом и сертификатом.
Верификация сертификата
-CAfile 'ca.crt'
- файл с сертификатом центра сертификации.'client.crt'
- файл с клиентским сертификатом.
Просмотр сертификата
Где:
-in 'client.crt'
- файл с клиентским сертификатом.
При выполнении команды, терминал покажет информацию со всеми основными сведениями о сертификате (пример ниже).
openssl x509 -in 'client.crt' -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
49:14:b8:78:17:a1:ca:c4:6a:41:1b:23:f3:8a:8d:36:e0:9e:69:81
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = CA
Validity
Not Before: Oct 18 21:31:53 2023 GMT
Not After : Oct 15 21:31:53 2033 GMT
Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = CN-FQDN, emailAddress = mail@example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:9f:22:91:cc:14:b3:75:ad:44:cc:0d:96:0d:19:
04:c4:20:79:fd:b7:f5:65:64:dd:65:a1:f0:b8:2d:
e4:02:75:62:41:03:7c:6e:2f:48:e4:11:38:dc:ed:
08:1f:4c:fa:5f:2f:a2:f5:5d:51:2e:8e:de:de:70:
33:aa:e5:3b:95
ASN1 OID: prime256v1
NIST CURVE: P-256
Signature Algorithm: ecdsa-with-SHA256
30:64:02:30:0d:ff:b1:dc:8b:a6:c6:9c:ad:65:8a:7c:01:41:
9f:91:ca:24:4c:0b:28:5a:5c:f6:35:2a:b2:d7:58:ca:39:da:
6c:bf:cf:8b:23:20:ce:11:45:13:61:36:e2:23:4a:e9:02:30:
54:dc:45:ed:ef:21:58:ea:c7:b6:63:db:a2:d9:71:fe:3d:b3:
d6:1e:15:82:7b:c8:e8:08:33:d5:2f:d5:f2:8f:3b:41:ea:53:
1e:2d:a9:1e:9e:25:9c:fb:a7:12:f9:ec
Просмотр запроса на подпись сертификата
Где:
-in 'client.csr'
- файл с запросом на подпись клиентского сертификата.
Команда выдаст информацию по запросу на подпись клиентского сертификата (пример ниже).
openssl req -in 'client.csr' -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = CN-FQDN, emailAddress = mail@example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:9f:22:91:cc:14:b3:75:ad:44:cc:0d:96:0d:19:
04:c4:20:79:fd:b7:f5:65:64:dd:65:a1:f0:b8:2d:
e4:02:75:62:41:03:7c:6e:2f:48:e4:11:38:dc:ed:
08:1f:4c:fa:5f:2f:a2:f5:5d:51:2e:8e:de:de:70:
33:aa:e5:3b:95
ASN1 OID: prime256v1
NIST CURVE: P-256
Attributes:
a0:00
Requested Extensions:
Signature Algorithm: ecdsa-with-SHA256
30:45:02:20:51:9c:a0:b9:b2:61:7f:fa:64:ea:34:1f:65:15:
37:ae:f4:89:30:47:11:89:db:c4:1b:1d:9b:82:b9:64:ea:c7:
02:21:00:f8:00:70:4e:e6:db:99:78:cf:25:22:c0:8d:c6:b1:
f3:f0:d8:68:3b:c2:51:21:a5:b3:fa:97:f9:85:c6:9c:49
Автоматизация
Команд много. Поэтому я как обычно, решил всё автоматизировать и загнать в скрипт.
#!/usr/bin/bash -e
#
# OpenSSL certificate generator.
#
# @package Bash
# @author Kitsune Solar <mail@kitsune.solar>
# @copyright 2023 Library Online
# @license MIT
# @version 0.1.1
# @link https://lib.onl/ru/articles/2023/10/6733cb51-62a0-5ed9-b421-8f08c4e0cb18/
# -------------------------------------------------------------------------------------------------------------------- #
(( EUID == 0 )) && { echo >&2 'This script should not be run as root!'; exit 1; }
# -------------------------------------------------------------------------------------------------------------------- #
# CONFIGURATION.
# -------------------------------------------------------------------------------------------------------------------- #
# Get 'date' command.
date="$( command -v date )"
# Get 'openssl' command.
ossl="$( command -v openssl )"
# Get 'shuf' command.
shuf="$( command -v shuf )"
# CA key & certificate names.
ca_key='ca.root.key'
ca_crt='ca.root.crt'
# Specifies the number of days to make a certificate valid for.
# Default is 30 days.
days='3650'
# Timestamp.
ts="$(( $( ${date} -u '+%s%N' ) / 1000000 ))"
# Suffix.
sfx=$( ${shuf} -i '1000-9999' -n 1 --random-source='/dev/random' )
# -------------------------------------------------------------------------------------------------------------------- #
# CERTIFICATE AUTHORITY.
# -------------------------------------------------------------------------------------------------------------------- #
ca() {
local ec='secp384r1'
echo "" && echo "--- [CREATE] Certificate Authority" && echo ""
${ossl} req -x509 -newkey ec:<( openssl ecparam -name "${ec}" ) \
-nodes -days "${days}" \
-keyform 'PEM' -outform 'PEM' \
-keyout "${ca_key}" -out "${ca_crt}" \
&& ${ossl} x509 -in "${ca_crt}" -text
}
# -------------------------------------------------------------------------------------------------------------------- #
# CLIENT CERTIFICATE.
# -------------------------------------------------------------------------------------------------------------------- #
cert() {
local ec='prime256v1'
local key_pvt="${ts}.${sfx}.key.private.pem"
local key_pub="${ts}.${sfx}.key.public.pem"
local csr="${ts}.${sfx}.csr"
local crt="${ts}.${sfx}.crt"
local p12="${ts}.${sfx}.p12"
local srl="${ts}.${sfx}.srl"
echo "" && echo "--- [CREATE] Client Certificate [${ts}]" && echo ""
${ossl} ecparam -name "${ec}" -genkey -noout -out "${key_pvt}" \
&& ${ossl} ec -in "${key_pvt}" -pubout -out "${key_pub}" \
&& ${ossl} req -new -key "${key_pvt}" -out "${csr}" \
&& ${ossl} x509 -req -in "${csr}" \
-CA "${ca_crt}" -CAkey "${ca_key}" -days "${days}" \
-CAcreateserial -CAserial "${srl}" \
-outform 'PEM' -out "${crt}" \
&& ${ossl} pkcs12 -export \
-inkey "${key_pvt}" \
-in "${crt}" -out "${p12}" \
&& ${ossl} verify -CAfile "${ca_crt}" "${crt}" \
&& ${ossl} x509 -in "${crt}" -text
}
# -------------------------------------------------------------------------------------------------------------------- #
# -------------------------------------------------< RUNNING SCRIPT >------------------------------------------------- #
# -------------------------------------------------------------------------------------------------------------------- #
"$@"
Скрипт содержит две функции, вызывать которых можно по отдельности. Функция ca()
позволяет сгенерировать ключ и сертификат центра сертификации, а функция cert()
, соответственно, генерирует клиентские сертификаты.
Использование
- Создать ключ и сертификат центра сертификации:
- Создать клиентские ключи и сертификаты:
Немного расскажу про алгоритм генерации сертификатов.
- У сертификата есть поле
Serial Number
, которое содержит серийный номер сертификата. Серийный номер сертификата это уникальный номер, выданный центром сертификации. В моём скрипте при генерации клиентского сертификата указаны опции-CAcreateserial
и-CAserial "${srl}"
, которые позволяют OpenSSL создавать рядом с клиентскими сертификатами файлы формата.slr
, содержащие в себе серийные номера сгенерированных сертификатов. Таким образом можно создавать небольшую локальную базу данных выданных сертификатов. - Файл каждого клиентского сертификата генерируется с названием вида
[TS].[SFX].[EXE]
, где[TS]
- это временная метка в микросекундах,[SFX]
- числовой суффикс, а[EXE]
- расширение файлов.
На этом всё. Не исключаю факта присутствия ошибок или неточностей. Если что, жду предложения в электронную почту. 😄
2023-11-08
bash.openssh.ca.sh
: добавление проверки на запуск скрипта под root’ом.bash.openssh.ca.sh
: добавление комментариев.