GrabDuck

Советы и трюки по работе с OpenSSL

:

Скорее всего, вы уже знакомы с OpenSSL как с библиотекой, которая дает возможность работать по протоколу SSL. Помимо библиотеки в составе OpenSSL идет полезная утилита для работы с командной строкой, которая используется при администрировании SSL/PKI. Сам этот инструмент плохо задокументирован, и цель данной статьи - немного рассказать о полезных советах и трюках по работе с OpenSSL в виде «поваренной книги».

Автор: Джошуа Дэвис (Joshua Davies)

Скорее всего, вы уже знакомы с OpenSSL как с библиотекой, которая дает возможность работать по протоколу SSL. Помимо библиотеки в составе OpenSSL идет полезная утилита для работы с командной строкой, которая используется при администрировании SSL/PKI. Сам этот инструмент плохо задокументирован, и цель данной статьи - немного рассказать о полезных советах и трюках по работе с OpenSSL в виде «поваренной книги».

Получение справки о подкомандах OpenSSL

Утилита для работы с командной строкой в OpenSSL является оболочкой для многих «подпрограмм». Для запуска нужной подпрограммы необходимо указать ее имя (например, ca, x509, asn1parse и т. д.) В документации по OpenSSL о подпрограммах сказано не особо много, однако на каждую такую подкоманду есть отдельная страница с документацией. Например, чтобы получить справку о подпрограмме openssl x509, наберите следующую команду:

$ man x509

Просмотр необработанной структуры ASN.1 файла

Протокол SSL является реализацией PKI (Public Key Infrastructure, Инфраструктура Открытых Ключей) и как таковой работает непосредственно с сертификатами. Можно с уверенностью сказать, если при настройке SSL возникли какие-то проблемы, то с 90% вероятностью дело в неправильно сконфигурированном сертификате. Сертификаты (или, если быть более точным, X.509 сертификаты) описываются формальным языком «ASN.1» (или Abstract Syntax Notation (.1)), в чем-то схожим с XML или JSON. Существует довольно много файлов, связанных с сертификатами, и нет никаких стандартов относительно их имен или расширений. Когда файл сертификата обнаружен, просмотр необработанной структуры (raw structure) может помочь в поиске проблемы. Однако если открыть файл сертификата, скажем, в текстовом редакторе, то можно увидеть нечто подобное:

MIICbDCCAioCAQAwaDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlRYMQ4wDAYDVQQHEwVQbGFubzER
MA8GA1UEChMIMnhvZmZpY2UxETAPBgNVBAsTCFJlc2VhcmNoMRYwFAYDVQQDEw1Kb3NodWEgRGF2
aWVzMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2
USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4
O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB
gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR
kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAOPlkQGq47HhKxmGBTDWaLaa140+Rl3b+
rZk3TpODy/BTS6O+v608EEBnJvF6ck26qFjLBHPC8IihovdcczKEAofIiR+do7CMjUEWdWIFnwKX
6W46ElBJN1ieWl1HtGj5RXnSfcfitiRGOiee1jsyV7wVn0Y4/8vbYPAUFRSPpk2gADALBgcqhkjO
OAQDBQADLwAwLAIUFgkt1lvVhcR1JE6wW7pyBAsgA1wCFHcSuOTaZdIM/dKwJ5dOFgsK0zOi

Файл закодирован по схеме Base64, но раскодировка не даст сколь-нибудь полезных результатов, поскольку в Base64 закодировано представление по стандарту DER (Distinguished Encoding Rule). Чтобы получить нечто более осмысленное, необходимо воспользоваться подкомандой asn1parse:

$ openssl asn1parse -in mysterious_file.pem

Результат выполнения подпрограммы:

0:d=0 hl=4 l= 620 cons: SEQUENCE
4:d=1 hl=4 l= 554 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
11:d=2 hl=2 l= 104 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 :US
26:d=3 hl=2 l= 11 cons: SET
28:d=4 hl=2 l= 9 cons: SEQUENCE
30:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
35:d=5 hl=2 l= 2 prim: PRINTABLESTRING :TX
39:d=3 hl=2 l= 14 cons: SET
41:d=4 hl=2 l= 12 cons: SEQUENCE
43:d=5 hl=2 l= 3 prim: OBJECT :localityName
48:d=5 hl=2 l= 5 prim: PRINTABLESTRING :Plano
55:d=3 hl=2 l= 17 cons: SET
57:d=4 hl=2 l= 15 cons: SEQUENCE
59:d=5 hl=2 l= 3 prim: OBJECT :organizationName
64:d=5 hl=2 l= 8 prim: PRINTABLESTRING :2xoffice
74:d=3 hl=2 l= 17 cons: SET
76:d=4 hl=2 l= 15 cons: SEQUENCE
78:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
83:d=5 hl=2 l= 8 prim: PRINTABLESTRING :Research
93:d=3 hl=2 l= 22 cons: SET
95:d=4 hl=2 l= 20 cons: SEQUENCE
97:d=5 hl=2 l= 3 prim: OBJECT :commonName
102:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Joshua Davies
117:d=2 hl=4 l= 439 cons: SEQUENCE
121:d=3 hl=4 l= 300 cons: SEQUENCE
125:d=4 hl=2 l= 7 prim: OBJECT :dsaEncryption
134:d=4 hl=4 l= 287 cons: SEQUENCE
138:d=5 hl=3 l= 129 prim: INTEGER :FD7F53811D75122952DF4A9C2...
270:d=5 hl=2 l= 21 prim: INTEGER :9760508F15230BCCB292B982A...
293:d=5 hl=3 l= 129 prim: INTEGER :F7E1A085D69B3DDECBBCAB5C3...
425:d=3 hl=3 l= 132 prim: BIT STRING
560:d=2 hl=2 l= 0 cons: cont [ 0 ]
562:d=1 hl=2 l= 11 cons: SEQUENCE
564:d=2 hl=2 l= 7 prim: OBJECT :dsaWithSHA1
573:d=2 hl=2 l= 0 prim: NULL
575:d=1 hl=2 l= 47 prim: BIT STRING

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

Работа с PEM-файлами и файлами, закодированными по стандарту DER

В большинстве случаев команда openssl asn1parse -in file будет работать корректно с любыми файлами, имеющими отношение к SSL/PKI, однако иногда может возникать следующая ошибка:

$ openssl asn1parse -in request.der
Error: offset too large

Скорее всего, это означает, что вы имеете дело с файлом, закодированным в формате DER, а не в формате PEM. В чем же различие? Формат DER – «необработанное представление», используемое SSL для корректной обработки сертификата. Именно в этом формате сертификат передается от сервера к клиенту для аутентификации. Как вы, возможно, уже знаете о том, что бинарные файлы и электронные сообщения не смешиваются, так как файлы обычно (но не всегда) кодируются в Base64 после чего прикрепляются к сообщению. Представление сертификата (или запроса на подпись), закодированного по стандарту DER, в виде Base64 называется (немного нелогично) Privacy Enhanced Mail или PEM-формат. В целом соглашение об именах гласит о том, чтобы «необработанным» (raw) файлам сертификатов назначалось расширение .der, а файлам закодированным в Base64 – расширение .pem.

Впервые термин PEM начал использоваться в проекте PGP (Pretty Good Privacy), который был особенно популярен в 90-х годах и направлен на защиту электронной почты. В то же время предпринималась попытка популяризировать стандарт IETF, где описывалась общая инфраструктура по шифрованию электронных писем. В настоящее время любой файл, закодированный в Base64 и имеющий отношение к сертификату, мы называем «закодированный по стандарту PEM», даже если он не предназначен для передачи конфиденциальной информации.

Предполагается, что любой объект, с которым взаимодействует OpenSSL, закодирован в Base64 и, следовательно, перед обработкой происходит его декодирование. Если необходимо обойти этот шаг, укажите параметр -inform der:

$ openssl asn1parse -inform der -in request.der
0:d=0 hl=4 l= 342 cons: SEQUENCE
4:d=1 hl=4 l= 256 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
...

Если и в этом случае возникает ошибка "offset too large", значит, файл либо не имеет отношение к сертификату, либо произошло его повреждение во время передачи.

Просмотр содержимого сертификата

Допустим, вы имеете дело с настоящим сертификатом стандарта X.509. Подпрограмма asn1parse во всех деталях расскажет о файле сертификата ( возможно, даже больше, чем вы ожидали). Вам же нужно узнать лишь срок действия и имя.

Для получения этой информации в OpenSSL предусмотрена подкоманда x509. Однако если использовать команду $ openssl x509 -in sample.cer, результат будет примерно таким:

-----BEGIN CERTIFICATE-----
MIIEszCCA5ugAwIBAgIJAMR0RhX+M2iEMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCVFgxDjAMBgNVBAcTBVBsYW5vMREwDwYDVQQKEwgy
...
qRH8SwcC2/+kLp5/SqpC7Tv1K1466jrxltb4ncJL6Is8p2FDRn1GTLTj3Z086JgX
s9y/DGoyTw==
-----END CERTIFICATE-----

По сути, вышеуказанная команда вывела текстовое содержимое сертификата, так же как если бы вы использовали команду: $ cat sample.cer

Для того чтобы OpenSSL отобразил нечто осмысленное, необходимо указать корректные параметры, например:

-subject
Вывод имени сертификата
-issuer
Вывод имени эмитента сертификата
-dates
Вывод срока действия сертификата

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

$ openssl x509 -in sample.cer -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
af:69:46:11:10:bd:82:88
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=Texas, L=Plano, O=2xoffice, OU=Architecture, CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
Validity
Not Before: May 21 21:49:10 2014 GMT
Not After : Jun 20 21:49:10 2014 GMT
Subject: C=US, ST=Texas, L=Plano, O=2xoffice, OU=Architecture, CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:b7:38:0d:e0:ab:37:18:a7:26:95:9d:9e:6f:a2:
69:b1:b9:ee:b3:7f:29:04:fb:f0:94:b3:d0:d5:55:
c0:d8:6b:14:7f:94:13:3c:d9:a2:61:bf:ba:3f:0a:
44:37:dc:18:b5:23:c7:ee:96:2d:7c:d8:92:04:48:
74:f8:c6:46:a5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
1A:A5:C9:C8:36:EA:7D:FA:B4:DF:A4:9C:11:F9:C1:BE:78:C4:42:DD
X509v3 Authority Key Identifier:
keyid:1A:A5:C9:C8:36:EA:7D:FA:B4:DF:A4:9C:11:F9:C1:BE:78:C4:42:DD
DirName:/C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
serial:AF:69:46:11:10:BD:82:88

X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
56:32:44:76:86:8c:08:92:74:71:0e:ac:a6:7d:ba:1d:7c:d3:
b6:74:ef:27:7a:5e:53:21:fc:8e:eb:26:58:e0:6e:4f:5c:01:
f1:40:ca:0a:e9:d2:0e:00:60:ae:1f:f6:a5:a4:4c:47:fb:e0:
68:7f:25:63:ab:60:38:0f:74:94

Создание самоподписанного тестового сертификата

При использовании сертификатов в реальной инфраструктуре, они должны быть подписаны и проверены корневым центром сертификации (например, Verisign или Thawte). Однако подобные сертификаты довольно дороги и, к тому же, для их получения требуется потратить много времени. Для тестирования вполне достаточно «поддельного» или самоподписанного сертификата, в котором определяется публичный ключ, и он же используется для создания подписи. Для создания подобных сертификатов в OpenSSL предусмотрена подкоманда req, которая используется вместе с параметром -x509.

$ openssl req -x509 -newkey rsa:2048
Generating a 512 bit RSA private key
...++++++++++++
...++++++++++++
writing new private key to 'privkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
...

Параметр –newkey заставляет OpenSSL сгенерировать секретный ключ, иначе вам придется ввести его самостоятельно.

Если вы не хотите выводить на экран содержимое сертификата, используйте параметр –out.

$ openssl req -x509 -newkey rsa:2048 -out selfsign.cer

По умолчанию секретный ключ записывается в файл privkey.pem (если уже существует файл с таким именем, то он перезаписывается без предупреждения!). Чтобы избежать возможных проблем, старайтесь определять самостоятельно файл для секретного ключа:

$ openssl req -x509 -newkey rsa:2048 -out selfsign.cer -keyout selfsign.key

Если вы хотите подцепить SSL на сервере Apache2 (только для тестирования!), раскомментируйте строку #Include /private/etc/apache2/extra/httpd-ssl.conf в файле /etc/apache2/httpd.conf и запустите следующую команду:

$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key

При этом вам будет предложено ввести некоторые параметры сертификата, но главное – в параметре Common Name следует указать «localhost».

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

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

Рисунок 1: Сообщение с предупреждением о недостоверном сертификате, которое выводится в браузере Chrome

Даже если пользователь кликнет на «Proceed Anyway», вебсайт в некоторых браузерах может отображаться некорректно (к примеру, Chrome не загрузит картинки у сайта с недостоверным сертификатом, если страница загружена по протоколу HTTPS). Вы не сможете сами создать «настоящий» сертификат, поскольку он должен быть подписан «настоящим» центром сертификации. Перед отправкой в центр необходимо создать запрос на подпись сертификата (certificate signing request, CSR). CSR содержит всю информацию (включая публичный ключ и домен сайта) за исключением подписи. Такой запрос можно создать в точности так же, как мы создавали ранее самоподписанный сертификат, но без параметра -x509:

$ openssl req -newkey rsa:2048 -out selfsign.cer -keyout selfsign.key

Вышеуказанная команда создает файл PKCS #10 (или запрос на подпись сертификата), который нужно загрузить в центр сертификации. Процедура получения достоверного сертификата варьируется от центра к центру, но в целом, вначале, вам нужно загрузить CSR-файл через вебформу. По завершению всех необходимых проверок, сертификат будет готов к работе. Обратите внимание, что сертификат не содержит секретный ключ (если вы еще не успели забыть, то он генерируется в отдельный файл). По сути, это часть публичной информации, которую ваш сервер будет отсылать каждому клиенту, пытающемуся подключиться по протоколу HTTPS.

Помните, когда я говорил о том, что могут возникнуть проблемы при перезаписи файла секретного ключа? Так вот, представьте себе ситуацию, когда CSR загружен в центр сертификации, а потом, нечаянно, перезаписан файл секретного ключа. Не забывайте, что секретный ключ не подлежит восстановлению (иначе инфраструктура, а которой базируется SSL, была бы уязвима). Если же ключ утерян, сгенерированный сертификат становится бесполезен (необходимо делать регулярные резервные копии подобных файлов).

Подписание запроса на создание сертификата

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

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

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

Для нечастого использования – средства OpenSSL вполне подходят, однако если вы хотите создать что-то более масштабное, необходимо развернуть серьезную инфраструктуру по управлению сертификатами.

Во-первых, как было показано выше, необходимо создать самоподписанный корневой сертификат. После этого создайте конфигурационный файл. В OpenSSL есть пример файла openssl.cnf, который находится в соответствующей папке (название директории может изменяться от версии к версии). В большинстве случаев (и особенно при тестировании) можно использовать как раз этот файл без каких-либо изменений. Если же вы планируете более плотно поработать с сертификатами, следует поподробнее ознакомиться с содержимым файла конфигурации. В нем есть несколько полезных параметров, например, местонахождение серийных номеров и списка отозванных сертификатов (Certificate Revocation List). Я не будут рассказывать обо всех опциях (если по-честному, с некоторыми из них я не сильно знаком). В большинстве случаев вы можете воспользоваться настройками по умолчанию.

Однако некоторые записи из раздела [ CA_default ] ссылаются на директории и файлы, которые, в случае их отсутствия, могут привести к проблемам при развертывании центра сертификации, и вы должны создать все необходимые файлы и папки перед тем, как подписывать CSR. В составе OpenSSL идет простая утилита CA.pl, которая упрощает весь процесс (на самом деле просто создается структура директорий, на которые ссылается файл openssl.cnf). За создание папок отвечает следующая секция:

mkdir demoCA
mkdir demoCA/certs
mkdir demoCA/crl
mkdir demoCA/newcerts
mkdir demoCA/private
touch demoCA/index.txt
echo "01" | demoCA/crlnumber

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

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

openssl ca -config ca.cnf -in csr.pem -out certificate.pem

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

Если вы посмотрите на содержимое сгенерированного сертификата, то увидите текстовое описание (в точности такое же, какое сгенерировала бы команда openssl x509 -noout –text). Этот раздел, включаемый по умолчанию, создает проблемы в некоторых системах. Чтобы текстовое описание не добавлялось, используйте параметр –notext или же просто удалите его вручную.

Рассмотрим еще раз весь алгоритм при развертывании центра сертификации:

Создаем конфигурационный файл. Его минимальное содержимое должно быть следующим:

2. [ ca ]
3. default_ca = miniCA
4.
5. [ miniCA ]
6. certificate = ./cacert.pem
7. database = ./index.txt
8. private_key = ./cakey.pem
9. new_certs_dir = ./certs
10. default_md = sha1
11. policy = policy_match
12. serial = ./serial
13. default_days = 365
14.
15. [policy_match]
16. commonName = supplied
17. Создаем структуру директорий:
18. $ mkdir certs
19. $ touch index.txt
20. $ echo "01" | serial
21. Создаем корневой сертификат
22. $ openssl req -x509 -newkey rsa:2048 -out cacert.pem -keyout cakey.pem
23. Generating a 2048 bit RSA private key
24. ...........+++
25. .................................................+++
26. writing new private key to 'cakey.pem'
27. Enter PEM pass phrase:
28. Verifying - Enter PEM pass phrase:
29. -----
30. You are about to be asked to enter information that will be incorporated
31. into your certificate request.
32. What you are about to enter is what is called a Distinguished Name or a DN.
33. There are quite a few fields but you can leave some blank
34. For some fields there will be a default value,
35. If you enter '.', the field will be left blank.
36. -----
37. Country Name (2 letter code) [AU]:US
38. State or Province Name (full name) [Some-State]:Texas
39. Locality Name (eg, city) []:Plano
40. Organization Name (eg, company) [Internet Widgits Pty Ltd]:2xoffice
41. Organizational Unit Name (eg, section) []:Architecture
42. Common Name (e.g. server FQDN or YOUR name) []:Certificate Authority
43. Email Address []:joshua.davies.tx@gmail.com

Если вы намереваетесь использовать центр сертификации для серьезных целей, установите сильный пароль для защиты файла cakey.pem и выставьте соответствующие права доступа:

$ chmod 400 cakey.pem

Сам по себе сертификат (в данном случае cakey.pem) будет размещен в конечных пунктах, где будут утверждаться подписанные сертификаты (к примеру, веб сервера, которые сконфигурированы для запроса клиентских сертификатов).

  1. Создайте запрос на подписание сертификата
  2. $ openssl req -newkey rsa:2048 -out csr.pem -keyout privkey.pem
  3. Подпишите запрос. Перед этим вы, возможно, захотите обратить внимание на содержимое директории с сертификатами для того, чтобы понимать механику процесса подписания сертификата.
  4. $ ls
  5. ca.cnf certs index.txt serial
  6. cacert.pem cakey.pem

Команда для подписания запроса:

$ openssl ca -config ca.cnf -in csr.pem -out signed.pem
Using configuration from ca.cnf
Enter pass phrase for ./cakey.pem:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'US'
stateOrProvinceName :PRINTABLE:'Texas'
localityName :PRINTABLE:'Plano'
organizationName :PRINTABLE:'2xoffice'
organizationalUnitName:PRINTABLE:'Architecture'
commonName :PRINTABLE:'Joshua Davies'
emailAddress :IA5STRING:'joshua.davies.tx@gmail.com'
Certificate is to be certified until May 29 14:54:35 2015 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Смотрим обновленное содержимое директории:

$ ls
ca.cnf certs index.txt.attr serial
cacert.pem index.txt.old serial.old
cakey.pem index.txt signed.pem

Были добавлены новые файлы: index.txt.attr, index.txt.old и serial.old

Также в директории certs появилась копия подписанного сертификат:

$ ls certs/
01.pem

Этот файл идентичен файлу signed.pem.

Следует отметить на поле subject у подписанного сертификата:

$ openssl x509 -in signed.pem -noout -subject
subject= /CN=Joshua Davies

Оно не совпадает с тем же самым полем из запроса:

$ openssl req -in csr.pem -noout -subjec
subject=/C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com

Причина в содержимом раздела [ policy ], который находится в конфигурационном файле. Там я указал, чтобы выводился только атрибут commonName. Если бы я заходил отобразить другие атрибуты, то указал бы их отдельно:

countryName = optional
stateOrProvinceName = optional

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

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

Подписание сертификата с начальной прошлой датой

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

$ openssl ca -in csr.pem -startdate 140529000000Z

Передача информации для поля subject через командную строку

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

#!/bin/sh

if [$# -ne 1]
then
echo "Usage: $0 "
exit
fi

openssl req -subj /C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=$1

Коды полей можно посмотреть в соответствующей спецификации:

CN

Common Name

L

Locality (city)

ST

State (or province)

O

Organization (for example, company)

OU

Organizational Unit

C

Country

Единственное обязательное значение, которое нужно указать при создании сертификата, - common name (CN), и оно должно совпадать с именем хоста.

$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key -subj /CN=localhost

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

$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key -subj /CN=localhost/emailAddress=joshua.davies.tx@gmail.com

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

Проверка на соответствие между публичным и секретным ключами

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

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

$ openssl rsa -in privkey.pem -noout -text
Enter pass phrase for privkey.pem:
Private-Key: (512 bit)
modulus:
00:b7:ed:99:89:e3:37:fa:28:54:7e:1e:4c:72:1b:
d1:b3:be:d1:99:50:59:83:8e:bf:8a:42:2f:42:fb:
38:2a:d1:3f:31:9e:20:26:7f:2e:c2:02:62:e8:b4:
8d:fc:1b:60:49:b6:78:f6:7d:74:21:56:c7:f5:f9:
53:ae:e3:a9:59
publicExponent: 65537 (0x10001)
privateExponent:
00:9e:98:13:b2:5f:e8:5e:9d:f3:ed:23:b7:0b:15:
8d:c6:8d:9d:31:b3:a4:db:d9:74:b3:84:ca:37:d9:
62:df:17:43:1a:56:21:eb:02:3e:44:04:b1:4c:48:
72:ef:cc:9e:a2:e5:d3:1d:da:57:83:d8:48:ad:e0:
19:8d:ec:55:01
prime1:
00:eb:15:16:7b:3c:69:2b:df:a8:e3:78:98:a4:3b:
c6:99:2e:24:ec:33:c4:52:e1:18:30:1a:06:3e:bf:
98:23:71
prime2:
00:c8:4b:46:90:06:6f:60:70:aa:46:1b:d4:b3:cb:
bb:28:5d:14:f1:60:90:dc:09:c3:fc:7b:8d:92:80:
7f:20:69
exponent1:
00:8d:77:e8:4a:8b:45:43:48:da:6a:e1:75:02:48:
92:b0:36:0b:b4:35:46:ed:15:56:a8:03:d1:44:4b:
aa:73:91
exponent2:
00:9f:b7:87:19:2a:48:7e:3a:d9:4c:f6:bc:72:73:
2f:57:4c:82:7a:c8:6a:3b:4c:7e:40:43:b5:ec:f1:
12:6e:a1
coefficient:
00:88:14:47:88:9a:c1:31:b0:16:74:1a:2d:5d:9e:
17:a9:c8:ef:c4:b4:72:4a:9d:8b:19:ec:c7:b2:4f:
a8:54:eb

Первые два блока представляют собой публичный ключ (секция modulus и public exponent), третья секция – секретный ключ (секция private exponent) и оставшиеся пять секций – компоненты секретной экспоненты, используемые для ускорения расчета секретного ключа. По умолчанию файлы идут в зашифрованном виде (поэтому чтобы просмотреть его структуру, необходимо вести пароль). Содержимое файла представляет собой примерно следующее:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,DCD8BE451A81F09A
bc6tsFhLlJ9bouUgr6H4F4u8ROSqZBrIABX1/oUlqbESK30Ubjz2ZINCkpuyW6QS

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

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

Выводим секцию modulus у секретного ключа:

$ openssl rsa -in privkey.pem -noout -modulus
Enter pass phrase for privkey.pem:

Modulus=B7ED9989E337FA28547E1E4C721BD1B3BED1995059838EBF8A422F42FB
382AD13F319E20267F2EC20262E8B48DFC1B6049B678F67D742156C7F5F953AEE3A959

Делаем то же самое для сертификата:

$ openssl x509 -in selfsign.cer -noout -modulus
Modulus=B7ED9989E337FA28547E1E4C721BD1B3BED1995059838EBF8A422F42FB
382AD13F319E20267F2EC20262E8B48DFC1B6049B678F67D742156C7F5F953AEE3A959

Способ работает, если вы используйте RSA или DSA (хотя почему вы все еще используете DSA?)

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

Сертификаты и ключи могут находиться в одном файле в формате PKCS #12 (например, в браузере клиентский сертификат экспортируется именно в таком формате). У самого файла может быть расширение .p12 или .pfx. В OpenSSL есть подкоманда pkcs12, которая может манипулировать информацией в формате PKCS #12. К примеру, чтобы выгрузить содержимое файла в консоль, используйте следующую команду:

$ openssl pkcs12 -in private.pfx

Как и в случае с подкомандами x509 и rsa на выходе вы получите сертификат и секретный ключ закодированные в base64. В отличие от x509 и rsa в подкоманде pkcs12 не предусмотрена опция –text для получения общих сведений о файлах в формате PKCS #12. На выходе вы увидите примерно следующее:

MAC verified OK
Bag Attributes
friendlyName: Client Certificate
localKeyID: A3 78 69 B4 A2 12 96 A7
subject=/CN=Joshua Davies/OU=Architecture/O=2xoffice
issuer=/CN=Joshua Davies/OU=Architecture/O=2xoffice
-----BEGIN CERTIFICATE-----
MIIFqTCCBJGgAwIBAgIIcho1mMr1AE0wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...
vBdHySICRxmp3onOOj86v/+SdRyvHLc6Nl4aP6J/l4lF/IVfni2flWXgB5pPjBx1
f/T4I5bCAqzvQTdfPw==
-----END CERTIFICATE-----

Разработчики OpenSSL реализовали в подкоманде x509 парсинг содержимого сертификата между маркерами BEGIN CERTIFICATE и END CERTIFICATE, и для вывода общих сведений о сертификате в формате PKCS #12, вы можете использовать связку следующих команд:

$ openssl pkcs12 -in private.pfx | openssl x509 -noout -text

При этом вас попросят ввести пароль два раза: первый раз для файла .pfx, а второй – для секретного ключа. Поскольку у нас нет необходимости выводить секретный ключ, мы будем использовать параметр –nokeys:

$ openssl pkcs12 -nokeys -in private.pfx | openssl x509 -noout -text

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

Модификация стандартных параметров

Ранее я упоминал, что если вы создаете запрос на подпись сертификата и не указывайте имени файла секретного ключа, по умолчанию будет создан файл privkey.pem. Имя стандартного файла можно изменить в файле openssl.cnf (если не забыли, существует стандартный файл с настройками). Помимо того что файл используется в центре сертификации, он же является основным при использовании OpenSSL в целом. Этот файл, к примеру, можно найти в директории etc/pki/tls или /usr/share/ssl.

В секции [ req ] есть такая запись:

default_keyfile = privkey.pem

Ранее упоминалось, что если не указать параметр –keyout при генерации самоподписанного сертификата или запроса на подпись, OpenSSL перезапишет файл privkey.pem без предупреждения. Можно избежать этого, если удалить имя файла в параметре default_keyfile:

default_keyfile =

Теперь, если вы попробуйте сгенерировать запрос на подпись сертификата без указания параметра default_keyfile, то возникнет ошибка:

$ openssl req -x509 -newkey rsa:2048 -config openssl.cnf
Generating a 512 bit RSA private key
.++++++++++++
.............++++++++++++
writing new private key to ''
No such file or directory
2995:error:02001002:system library:fopen:No such file or directory:/SourceCache
/OpenSSL098/OpenSSL098-50/src/crypto/bio/bss_file.c:356:fopen('','w')
2995:error:20074002:BIO routines:FILE_CTRL:system lib:/SourceCache/OpenSSL098
/OpenSSL098-50/src/crypto/bio/bss_file.c:358: