openssl — набор подкоманд для работы с криптографией и TLS: создать ключ и сертификат, прочитать сертификат, подписать его своим центром сертификации, подключиться к серверу и посмотреть, что он отдаёт. Первым словом всегда идёт подкоманда: x509, req, s_client, genpkey, verify…
Синтаксис
openssl ПОДКОМАНДА [опции]
openssl ПОДКОМАНДА -help # опции конкретной подкоманды
Файлы обычно в формате PEM — текст между строками -----BEGIN …----- и -----END …-----. Бинарный вариант того же — DER.
| Заголовок PEM | Что внутри |
|---|
BEGIN CERTIFICATE | сертификат |
BEGIN CERTIFICATE REQUEST | запрос на сертификат (CSR) |
BEGIN PRIVATE KEY | закрытый ключ в формате PKCS#8 (BEGIN RSA PRIVATE KEY — старый формат RSA) |
BEGIN ENCRYPTED PRIVATE KEY | закрытый ключ, зашифрованный паролем |
BEGIN PUBLIC KEY | открытый ключ |
x509 — смотреть и подписывать сертификаты
| Опция | Что делает |
|---|
-in файл | входной сертификат (-inform DER — если он в DER) |
-noout | не печатать сам сертификат в PEM — только запрошенные поля |
-text | всё содержимое в читаемом виде |
-subject / -issuer | кому выдан / кем подписан; -nameopt RFC2253 — в виде CN=…,O=… |
-dates, -startdate, -enddate | срок действия: notBefore и notAfter |
-serial | серийный номер |
-fingerprint -sha256 | отпечаток сертификата |
-ext subjectAltName | одно расширение: SAN, keyUsage, basicConstraints… |
-pubkey | открытый ключ из сертификата |
-modulus | модуль RSA-ключа (только для RSA) |
-checkend N | код 1 и Certificate will expire, если истечёт в ближайшие N секунд |
-outform DER -out файл | конвертировать в DER |
-req -in csr -CA ca.pem -CAkey ca.key | выпустить сертификат по CSR, подписав своим CA |
-CAcreateserial | создать файл серийных номеров CA, если его нет |
-days N | срок действия выпускаемого сертификата |
-copy_extensions copy | перенести расширения (SAN) из CSR в сертификат (OpenSSL 3) |
Поля x509 -text
| Поле | Что значит |
|---|
Serial Number | уникальный номер у этого CA |
Signature Algorithm | чем подписан: sha256WithRSAEncryption, ecdsa-with-SHA256 |
Issuer | кто подписал; у самоподписанного совпадает с Subject |
Validity: Not Before / Not After | с какого и до какого момента действителен (время в GMT) |
Subject | кому выдан: CN (имя), O (организация), C (страна) |
Subject Public Key Info | алгоритм и размер ключа: rsaEncryption 2048 bit, id-ecPublicKey 256 bit |
X509v3 Subject Alternative Name | имена и IP, для которых сертификат действителен |
X509v3 Basic Constraints | CA:TRUE — сертификатом можно подписывать другие |
X509v3 Key Usage / Extended Key Usage | для чего ключ: подпись, шифрование, TLS Web Server Authentication |
req — запросы и самоподписанные сертификаты
| Опция | Что делает |
|---|
-new | создать CSR |
-x509 | вместо CSR сразу выдать самоподписанный сертификат |
-newkey rsa:2048 / ec -pkeyopt ec_paramgen_curve:P-256 | заодно создать новый ключ |
-key файл | использовать существующий ключ |
-keyout файл / -out файл | куда записать новый ключ / CSR или сертификат |
-nodes (в OpenSSL 3 ещё -noenc) | не шифровать ключ паролем |
-subj '/CN=имя/O=Орг' | субъект без интерактивных вопросов |
-addext 'subjectAltName=DNS:a,IP:1.2.3.4' | добавить расширение |
-days N | срок для -x509 |
-in csr -noout -text / -verify | посмотреть CSR / проверить его подпись |
Ключи
| Команда | Что делает |
|---|
genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 | RSA-ключ |
genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 | ключ на эллиптической кривой |
genpkey -algorithm ed25519 | ключ Ed25519 |
genrsa -out key.pem 2048 | RSA-ключ, старая команда |
pkey -in key.pem -pubout | открытый ключ из закрытого |
pkey -in key.pem -noout -text | параметры ключа |
pkey -in key.pem -check -noout | проверить целостность ключа |
rsa -in key.pem -noout -modulus | модуль RSA-ключа |
s_client — подключиться к TLS-серверу
| Опция | Что делает |
|---|
-connect хост:порт | куда подключаться |
-servername имя | SNI: какое имя сайта просить у сервера |
-showcerts | вывести всю цепочку, которую прислал сервер |
-CAfile ca.pem | доверять этому CA при проверке |
-verify_hostname имя | проверить, что сертификат выдан на это имя |
-verify_return_error | прервать соединение, если проверка не прошла (код выхода 1) |
-brief | короткая сводка: протокол, шифр, сертификат |
-tls1_2 / -tls1_3 | только эта версия протокола |
-starttls smtp | TLS поверх обычного протокола (smtp, imap, ftp, postgres…) |
В выводе важны строки subject= / issuer= (сертификат сервера), Protocol/Cipher и Verify return code: 0 (ok) — цепочка проверена; 18 — самоподписанный; 20/21 — не найден CA; 10 — истёк; 62 — имя не совпало.
Прочее
| Команда | Что делает |
|---|
verify -CAfile ca.pem cert.pem | проверить подпись цепочки; -untrusted inter.pem — промежуточные сертификаты |
dgst -sha256 файл | хеш файла |
rand -hex 16 / rand -base64 24 | случайные байты: пароли, токены |
passwd -6 'пароль' | хеш пароля для /etc/shadow; -apr1 — для htpasswd |
enc -aes-256-cbc -pbkdf2 -in f -out f.enc | зашифровать файл паролем; -d — расшифровать |
pkcs12 -export -in cert.pem -inkey key.pem -out b.p12 | упаковать сертификат и ключ в PKCS#12 (.p12/.pfx) |
pkcs12 -in b.p12 -nokeys | достать сертификаты из PKCS#12 |
Примеры
# самоподписанный сертификат на год для localhost, ключ без пароля
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
-keyout key.pem -out cert.pem \
-subj '/CN=localhost' -addext 'subjectAltName=DNS:localhost'
# кому выдан, кем и до какого числа
openssl x509 -in cert.pem -noout -subject -issuer -dates
# истекает ли в ближайшие 30 дней
openssl x509 -in cert.pem -noout -checkend $((30*86400)) || echo 'скоро истечёт'
# свой CA и сертификат, подписанный им
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 -subj '/CN=Demo CA' -keyout ca.key -out ca.pem
openssl req -new -newkey rsa:2048 -nodes -subj '/CN=localhost' \
-addext 'subjectAltName=DNS:localhost' -keyout srv.key -out srv.csr
openssl x509 -req -in srv.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
-days 90 -copy_extensions copy -out srv.pem
openssl verify -CAfile ca.pem srv.pem
# подходит ли ключ к сертификату: открытые ключи должны совпасть
diff <(openssl x509 -in cert.pem -noout -pubkey) <(openssl pkey -in key.pem -pubout) && echo 'пара'
# то же для RSA через модуль
openssl x509 -in cert.pem -noout -modulus | sha256sum
openssl rsa -in key.pem -noout -modulus | sha256sum
# что отдаёт TLS-сервер; </dev/null — чтобы команда не ждала ввода
openssl s_client -connect localhost:8443 -servername localhost </dev/null
# сертификат сервера сразу в x509: срок и субъект
openssl s_client -connect localhost:8443 -servername localhost </dev/null 2>/dev/null \
| openssl x509 -noout -subject -dates
# случайный пароль
openssl rand -base64 24
Подводные камни
s_client висит без </dev/null. После рукопожатия он ждёт ввода с клавиатуры. Для разовой проверки подавай пустой stdin.
-servername важен: без SNI сервер с несколькими сайтами может отдать сертификат не того сайта.
s_client не обрывает соединение при ошибке проверки. Verify return code: 18 — соединение установлено, просто сертификат никто не подписывал. Для строгой проверки добавь -verify_return_error, для своего CA — -CAfile.
- CN больше не главный. Браузеры и программы на Go сверяют имя хоста только с
subjectAltName, CN они игнорируют. curl с сертификатом без SAN ещё может согласиться, а браузер — уже нет. Добавляй -addext 'subjectAltName=…'.
- SAN из CSR не переносится сам.
x509 -req по умолчанию выбрасывает расширения запроса. Нужен -copy_extensions copy (OpenSSL 3) или -extfile с нужными строками.
-modulus есть только у RSA. Для EC и ed25519 сравнивай открытые ключи через -pubkey / pkey -pubout — этот способ работает для любых ключей.
- Без
-nodes ключ шифруется паролем, и nginx будет спрашивать его при каждом старте.
- Формат
genrsa изменился. В OpenSSL 3 он пишет BEGIN PRIVATE KEY (PKCS#8), а не BEGIN RSA PRIVATE KEY. Если инструкция ищет старый заголовок, дело в версии, а не в ключе.
- Порядок в файле цепочки: сначала сертификат сервера, потом промежуточные. Корневой CA серверу отдавать не нужно.
- Ключ — секрет: права
600, владелец — тот, кто его читает.
См. также
nginx · curl · ssh · checksums · base64