diamond АШ Tlg

OpenSSL, часть 3: Создание ключа и сертификата для клиента

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

В данной серии публикаций предполагается, что читатель знаком с концепцией криптографических систем с открытым ключом PKI. Почитать теорию можно, например, в Википедии. Для реализации PKI будем использовать свободное ПО OpenSSL. В отличии от большинства публикаций, буду параллельно описывать процедуру сразу в 2-х вариантах PKI для криптоалгоритма RSA и ГОСТ Р 34.10-2012. Синтаксис команд не отличается для различных дистрибутивов Linux и даже для Windows, полная инструкция будет состоять из следующих частей:

Основы безопасности

В норме, приватный ключ и запрос сертификата должны генерироваться на стороне запрашивающего (в нашем случае это должен делать сам клиент), а подписываться ключом УЦ со стороны администратора ИТ-безопасности. Как и в случае веб-сервера, это два разных человека каждый со своей зоной ответствености, поэтому получение сертификатов точно так же технически разделено на 2 или даже 3 этапа. При этом приватный ключ не должен покидать компьютер запрашивающего, а отправляться на подпись должен только файл-запрос CSR. Часто это правило нарушается админами, но я такое поощрять не буду: скрипты будут разделены, но вы можете объединить их в один, если иначе не обойтись.

Получение подписанного УЦ сертификата для клиента (RSA)

В качестве примера, ключ создается для клиента с именем Marcus Tullius Cicero, c электронной почтой сicero@rome.it.

ЭТАП 1: Скрипт, генерирующий приватный ключ клиента длиной 3072 бит и запрос сертификата. В OpenSSL 3.1 это делается в один заход, с применением рекомендованных параметров для конкретных задач клиента. Естественно, клиент не является высококвалифицированным специалистом PKI и обычно разработчики ПО максимально упрощают ему задачу. Создайте и отдайте вместе с инструкциями клиенту такой bash-скрипт с именем gen-client-rsa.sh, выделеные участки в начале скрипта требуется заменить на свое имя и электронный адрес:

#!/bin/bash

CLIENT="Marcus Tullius Cicero"
EMAIL="сicero@rome.it""

openssl req -newkey rsa:3072 \
    -keyform PEM \
    -outform PEM \
    -nodes \
    -keyout "./newkey/$CLIENT.key" \
    -out "./newkey/$CLIENT.csr" \
    -subj "/C=RU/CN=$CLIENT" \
    -addext "basicConstraints = CA:FALSE" \
    -addext "subjectKeyIdentifier = hash" \
    -addext "keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment" \
    -addext "extendedKeyUsage=clientAuth,codeSigning,emailProtection,timeStamping,OCSPSigning,ipsecIKE" \
    -addext "subjectAltName = email:$EMAIL"
   
openssl req -text -noout -in "./newkey/$CLIENT.csr"

При формировании запроса обратите внимание на поле extendedKeyUsage: оставляем там только то, что нужно для выполнения задач этим пользователем. Для авторизации на веб-сервере достаточно значения clientAuth, для защиты электронной почты emailProtection, для клиента VPN IPSec IKE нужен ipsecIKE, а если пользователь является ещё и программистом, то для подписывания написанных им приложений для Java, Android и др. ему нужен codeSigning и т.д.

Вывод команды:

Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = RU, CN = Marcus Tullius Cicero
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (3072 bit)
                Modulus:
                    00:ca:bd:46:0c:08:23:5b:5d:d3:0f:73:08:d8:d9:
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
            Requested Extensions:
                X509v3 Basic Constraints: 
                    CA:FALSE
                X509v3 Subject Key Identifier: 
                    38:55:9E:D4:79:D7:F7:91:CF:97:3C:39:A7:CE:07:E1:D8:AF:AE:ED
                X509v3 Key Usage: 
                    Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
                X509v3 Extended Key Usage: 
                    TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping, OCSP Signing, ipsec Internet Key Exchange
                X509v3 Subject Alternative Name: 
                    email:сicero@rome.it
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        46:cb:b0:d5:d3:81:ac:58:39:75:02:bb:1e:5c:67:a3:19:67:
        ...

ЭТАП 2: Администратор УЦ подписывает запрошенный сертификат на срок 365 дней следующим скриптом (назвать его можно например sign-client-rsa.sh), в качестве аргумента скрипту требуется передать имя файла запроса, без расширения, в кавычках:

#!/bin/bash

openssl x509 -req \
   -in "./newkey/$1.csr" \
   -CA ./ca/ca.crt \
   -CAkey ./ca/ca.key \
   -CAcreateserial \
   -days 365 \
   -out "./newkey/$1.crt" \
   --copy_extensions=copyall

openssl x509 -text -in "./newkey/$1.crt"    

Скрипт выводит на просмотр готовый сертификат, нужно проверить по выделенным полям, всё ли в порядке:

$ sign-client-rsa.sh "Marcus Tullius Cicero"

Certificate request self-signature ok
subject=C = RU, CN = Marcus Tullius Cicero
Enter pass phrase for ./ca/ca.key:
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            31:51:0f:05:c6:26:99:88:63:eb:85:e5:79:98:19:ee:03:64:19:6a
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = RU, CN = Demo Root CA 2023
        Validity
            Not Before: Oct 24 09:58:37 2023 GMT
            Not After : Oct 23 09:58:37 2024 GMT
        Subject: C = RU, CN = Marcus Tullius Cicero
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (3072 bit)
                Modulus:
                    00:ca:bd:46:0c:08:23:5b:5d:d3:0f:73:08:d8:d9:
                    ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                38:55:9E:D4:79:D7:F7:91:CF:97:3C:39:A7:CE:07:E1:D8:AF:AE:ED
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping, OCSP Signing, ipsec Internet Key Exchange
            X509v3 Subject Alternative Name: 
                email:сicero@rome.it
            X509v3 Authority Key Identifier: 
                0F:15:FA:80:32:90:70:6C:15:CA:0F:FC:E9:36:6E:C5:A2:2D:43:18
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        3b:fc:23:87:78:73:f7:27:d9:7c:a0:67:ea:ba:fe:33:3a:06:
        ...

В результате выполнения скрипта в папке newkey сохраняется файл с подписанным УЦ открытым сертификатом пользователя, имя файла будет Marcus Tullius Cicero.crt. Для некоторых программ предусмотрена раздельная установка приватного ключа и сертификата, в этом случае достаточно отдать сертификат пользователю и он сам установит всё что нужно в программу. Но в большинстве браузеров и множестве других программ требуется устанавливать все ключи и сертификаты за одну операцию, в этом случае требуется собрать всё в один файл с расширением .p12 или .pfx (без разницы, в настоящее время разделения нет, оба суть контейнер PKCS#12).

И здесь возникает дилемма, как и на Этапе 1: либо пусть сборку файла PKCS#12 делает сам пользователь, либо это сделает админ за него. Второй выбор конечно не очень хороший, так как требует выдавать приватные ключи админу, что нарушает принцип PKI: но иногда некуда деваться и всегда бывают исключения.

ЭТАП 3: Создаем скрипт c наименованием pkcs12-rsa.sh для сборки всех ключей и сертификатов в один файл PKCS#12. Скрипт, аналогично как для подписания, требует указать аргументом наименование без расширения, а также 2 раза ввести пароль для защиты приватного ключа:

#!/bin/bash
openssl pkcs12 \
    -export \
    -in "./newkey/$1.crt" \
    -inkey "./newkey/$1.key" \
    -certfile ./ca/ca.crt \
    -out "./newkey/$1.p12"
$ ./pkcs12-rsa.sh "Marcus Tullius Cicero"
Enter Export Password:
Verifying - Enter Export Password:

Если сборку PKCS#12 выполняет сам пользователь, то имеет смысл сделать ему готовый архив с вписанными его данными и всеми необходимыми файлами, чтоб ему оставалось только добавить файл со своим приватным ключом, и запустить на выполнение. В результат в папке newkey будет создан контейнер ключей в формате PKCS#12. Его можно импортировать, например в Firefox.

Получение подписанного УЦ сертификата для клиента (ГОСТ-2012)

ВНИМАНИЕ! Вы не можете использовать полученные нижеописанным способом ключи для использования в качестве квалифицированной электронной подписи для юридически значимого документооборота с государственными органами РФ! Для этого, согласно законодательству, требуется использовать только сертифицированные ФСБ программы, к коим OpenSSL никаким образом не относится. Этот опыт скорее интересен с технической стороны, т.к. алгоритмы ГОСТ-2012 являются на порядок более защищёнными и производительными, чем RSA, при одинаковой длине ключа.

ЭТАП 1: Здесь всё во многом аналогично RSA, за исключением некоторых параметров. Скрипт gen-client-gost.sh:

#!/bin/bash

CLIENT="Александръ Сергѣевичъ Пушкинъ"
EMAIL="alex.pushkin@spb.ru""
    
openssl req -engine gost \
    -utf8 \
    -newkey  gost2012_512 \
    -pkeyopt paramset:C \
    -keyform PEM \
    -outform PEM \
    -nodes \
    -keyout "./newkey/$CLIENT.key" \
    -out "./newkey/$CLIENT.csr" \
    -subj "/C=RU/CN=$CLIENT" \
    -addext "basicConstraints = CA:FALSE" \
    -addext "subjectKeyIdentifier = hash" \
    -addext "keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment" \
    -addext "extendedKeyUsage=clientAuth,codeSigning,emailProtection,timeStamping,OCSPSigning,ipsecIKE" \
    -addext "subjectAltName = email:$EMAIL"
       
    openssl req -text -noout -in "./newkey/$CLIENT.csr"
$ ./gen-client-gost.sh
Engine "gost" set.
-----
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = RU, CN = \C3\90\C2\90\C3\90\C2\BB\C3\90\C2\B5\C3\90\C2\BA\C3\91\C2\81\C3\90\C2\B0\C3\90\C2\BD\C3\90\C2\B4\C3\91\C2\80\C3\91\C2\8A \C3\90\C2\A1\C3\90\C2\B5\C3\91\C2\80\C3\90\C2\B3\C3\91\C2\A3\C3\90\C2\B5\C3\90\C2\B2\C3\90\C2\B8\C3\91\C2\87\C3\91\C2\8A \C3\90\C2\9F\C3\91\C2\83\C3\91\C2\88\C3\90\C2\BA\C3\90\C2\B8\C3\90\C2\BD\C3\91\C2\8A
        Subject Public Key Info:
            Public Key Algorithm: GOST R 34.10-2012 with 512 bit modulus
                Public key:
                    X:CFBFB4732374CB76ABC2C4BFD4CEA4BB624591552830CE9418A3D3064F12FA6C8D318A420A3E80F48F5EA5E74F9F694BB8AE3DF701BF15FF5BEE48F72FEAB2F
                    Y:5226C1D0C916E8720DDE85DCE9140BDE0C36408EAE55C3C495FD3AA7FA50D81657148D7082A5B4068FF830F157B0EFFC808F8512A0DC2FF546CA05ADC45EC40A
                Parameter set: GOST R 34.10-2012 (512 bit) ParamSet C
        Attributes:
            Requested Extensions:
                X509v3 Basic Constraints: 
                    CA:FALSE
                X509v3 Subject Key Identifier: 
                    AC:CC:16:3A:84:EA:A4:DA:F9:CB:5C:3C:52:74:4C:02:74:F6:99:5C
                X509v3 Key Usage: 
                    Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
                X509v3 Extended Key Usage: 
                    TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping, OCSP Signing, ipsec Internet Key Exchange
                X509v3 Subject Alternative Name: 
                    email:alex.pushkin@spb.ru
    Signature Algorithm: GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)
    Signature Value:
        3b:bb:c3:71:40:28:38:89:45:8d:06:f5:57:28:86:c2:c8:06:
        ...

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

Запрос сертификата Пушкин

ЭТАП 2: Администратор УЦ ГОСТ подписывает запрошенный сертификат на срок 365 дней (sign-client-gost.sh):

#!/bin/bash

openssl x509 -req \
    -engine gost \
    -in "./newkey/$1.csr" \
    -CA ./ca/ca.crt \
    -CAkey ./ca/ca.key \
    -CAcreateserial \
    -days 365 \
    -out "./newkey/$1.crt" \
    --copy_extensions=copyall
    
openssl x509 -text -in "./newkey/$1.crt"    
$ ./sign-client-gost.sh "Александръ Сергѣевичъ Пушкинъ"
Engine "gost" set.
Certificate request self-signature ok
subject=C = RU, CN = \D0\90\D0\BB\D0\B5\D0\BA\D1\81\D0\B0\D0\BD\D0\B4\D1\80\D1\8A \D0\A1\D0\B5\D1\80\D0\B3\D1\A3\D0\B5\D0\B2\D0\B8\D1\87\D1\8A \D0\9F\D1\83\D1\88\D0\BA\D0\B8\D0\BD\D1\8A
Enter pass phrase for ./ca/ca.key:  Вводим пароль ключа УЦ
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            31:51:0f:05:c6:26:99:88:63:eb:85:e5:79:98:19:ee:03:64:19:6b
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = RU, CN = Demo Root CA 2023
        Validity
            Not Before: Oct 24 11:37:18 2023 GMT
            Not After : Oct 23 11:37:18 2024 GMT
        Subject: C = RU, CN = \D0\90\D0\BB\D0\B5\D0\BA\D1\81\D0\B0\D0\BD\D0\B4\D1\80\D1\8A \D0\A1\D0\B5\D1\80\D0\B3\D1\A3\D0\B5\D0\B2\D0\B8\D1\87\D1\8A \D0\9F\D1\83\D1\88\D0\BA\D0\B8\D0\BD\D1\8A
        Subject Public Key Info:
            Public Key Algorithm: GOST R 34.10-2012 with 512 bit modulus
                Public key:
                    X:B69943F3BEF8067E04B9EE092DCB29FE98EE78AF111CAB83CF92BF05E3F9A2E8C4073597D763101A6BF8539CA45AB7049F8CA6BFC042E68F4D1CC6BCCFC6384
                    Y:ED95E6EAF99F691FB644C173BE138AA2F45F6359EE401570C030B58C085234E042A450452EA2356FB28B36BE2FDEFAE4F1C4DB2711523634E09EF920C414ADC9
                Parameter set: GOST R 34.10-2012 (512 bit) ParamSet C
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                28:74:B7:F6:7C:01:B8:6C:2D:54:5C:4E:CC:76:BC:F2:55:D3:89:EC
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping, OCSP Signing, ipsec Internet Key Exchange
            X509v3 Subject Alternative Name: 
                email:alex.pushkin@spb.ru
            X509v3 Authority Key Identifier: 
                0F:15:FA:80:32:90:70:6C:15:CA:0F:FC:E9:36:6E:C5:A2:2D:43:18
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        80:ae:b6:b8:3c:22:5a:e7:52:1e:7c:58:74:6c:67:af:81:84:
        ...

ЭТАП 3: Создаем скрипт c наименованием pkcs12-gost.sh для сборки всех ключей и сертификатов в один файл PKCS#12. Скрипт точно такой же как для RSA и также требует указать аргументом наименование без расширения, а также 2 раза ввести пароль для защиты приватного ключа:

#!/bin/bash 
openssl pkcs12 \
    -export \
    -in "./newkey/$1.crt" \
    -inkey "./newkey/$1.key" \
    -certfile ./ca/ca.crt \
    -out "./newkey/$1.p12"
$ ./pkcs12-gost.sh "Александръ Сергѣевичъ Пушкинъ"
Enter Export Password:
Verifying - Enter Export Password:

ВНИМАНИЕ! Полученный файл не совместим для работы с криптопровайдерами CryptoPro и ViPNet, т.к. у них отличающийся формат PFX ГОСТ (обратный порядок байтов). В разделе загрузок CryptoPro есть утилита p12tocp.zip для конвертации и загрузки ключей в КриптоПро CSP. Также на практике следует учитывать, что в расширении X509 возможно потребуется указывать особые OID, но это уже специфично для провайдера услуг и используемого ПО - здесь у каждого будут свои заморочки.