Настройка ГОСТ-TLS через КриптоПро

Материал из YourcmcWiki
Версия от 19:01, 30 ноября 2017; VitaliyFilippov (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

В протоколе https:// можно использовать криптографию ГОСТ (ГОСТ Р 34.10-2001, ГОСТ Р 34.10-94).

Для этого на Linux сервере есть 2 варианта реализации:

  • Opensource, добавленная в OpenSSL 1.0.* и входящая в комплект его поставки, и отделённая в https://github.com/gost-engine/engine, начиная с OpenSSL 1.1. Реализована компанией КриптоКом, НЕ сертифицирована.
  • Реализация через КриптоПро CSP и gost_capi. КриптоПро сертифицировано ФСБ, есть 3.9 и 4.0, 4.0 отличается дополнительным наличием поддержки чуть более нового стандарта ГОСТ Р 34.10-2012, однако для совместимости со старыми версиями КриптоПро (3.6, 3.9) и opensource реализацией его использовать не надо.

Настройка OpenSource реализации (КриптоКом)

Самая простая в установке реализация ГОСТ — opensource. Установка сводится к 2 пунктам:

  1. Найти в комплекте поставки ИЛИ собрать engine «/usr/lib64/openssl/libgost.so»
  2. Включить её в конфигурации OpenSSL

Если ваша версия OpenSSL 1.0.x, ГОСТ может быть уже в комплекте поставки. Нужно найти директорию с engines OpenSSL (Debian: /usr/lib/x86_64-linux-gnu/openssl*/engines или /usr/lib/x86_64-linux-gnu/engines-1.1, RHEL: /usr/lib64/openssl/engines) и посмотреть, есть ли там файл с именем «libgost.so» или «libgost_engine.so». Если есть — можно переходить к редактированию конфигурации. Если нет — нужно скачать исходные коды вашего пакета OpenSSL и включить gost в его конфигурации сборки.

Если ваша версия OpenSSL 1.1.x, нужно склонировать репозиторий https://github.com/gost-engine/engine, установить пакеты cmake и libssl-dev (Debian) или openssl-devel (RHEL), зайти в склонированную директорию и выполнить команды

mkdir build
cd build
cmake ..
make -j4

После чего взять libgost_engine.so из поддиректории bin клонированного репозитория и скопировать его в папку engines.

Далее отредактировать конфигурацию — добавить перед первой секцией INI-файла openssl.cnf следующий блок:

openssl_conf = openssl_def

[openssl_def]
engines = engine_section

[engine_section]
gost = gost_section

[gost_section]
soft_load = 1
dynamic_path = /usr/lib/x86_64-linux-gnu/engines-1.1/libgost_engine.so
engine_id = gost
default_algorithms = ALL
CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet

После этого всё ПО, использующее OpenSSL (в частности, nginx) сможет использовать ГОСТ в протоколе TLS.

Самоподписанный ГОСТ-сертификат можно сгенерировать так:

openssl req -days 3650 -x509 -newkey gost2001 -pkeyopt paramset:A -nodes -keyout gost_test.key -out gost_test.crt

Чтобы сконвертировать ключевой контейнер КриптоПро в нормальный ASN.1/PEM формат, нужно использовать утилиту http://svn.yourcmc.ru/vitalif/trunk/scripts/cryptopro-key-to-openssl.c?view=co (источник: https://habrahabr.ru/post/275039/)

Установка КриптоПро на RHEL 7.2

Инструкция по установке КриптоПро CSP на сервер RHEL 7.2 в nginx.

Установка пакетов

  • Установить nginx >= 1.11 с официального сайта http://nginx.org/
  • Установить пакет redhat-lsb-core
  • Скачать дистрибутив КриптоПро CSP, например, 3.9
  • Установить пакеты КриптоПро: lsb-cprocsp-base, lsb-cprocsp-capilite-64, lsb-cprocsp-kc1-64, lsb-cprocsp-kc2-64, lsb-cprocsp-pkcs11-64, lsb-cprocsp-rdr-64, cprocsp-curl-64, cprocsp-cpopenssl-64, cprocsp-cpopenssl-base, cprocsp-cpopenssl-gost, опционально: lsb-cprocsp-devel, cprocsp-cpopenssl-devel
  • Убедиться, что сервис cryptsrv запущен (ps ax|grep cryptsrv), если нет — запустить (service cprocsp start), убедиться, что включён автозапуск (systemctl enable cprocsp)
  • Выполнить команду
    /opt/cprocsp/sbin/amd64/cpconfig -ini '\config\apppath' -add string libcurl.so /usr/lib64/libcurl.so.4

Установка сертификата и ключа

Вначале устанавливаем закрытый ключ — для этого нужно взять директорию с ключами (см. #Формат ключа) и скопировать в /var/opt/cprocsp/keys/root/ под именем XXXXXXXX.000 (любое имя вида «8 латинских букв, точка, 3 цифры»). «Контейнер ключа/ключей» в терминологии КриптоПро — это и есть ключ.

Далее — установка сертификата.

Если сертификат НЕ в формате X.509/PEM, его нужно сконвертировать в этот формат.

В частности, один из наших тестовых сертификатов был получен в формате PEM (кусок текста в кодировке base64), но без заголовка — в этом случае нужно добавить заголовок, то есть в начало добавить строку -----BEGIN CERTIFICATE-----, а в конец — строку -----END CERTIFICATE-----.

Второй вариант — сертификат может быть в бинарном формате (X509/DER, расширение обычно *.cer) — тогда его надо сконвертировать в PEM командой
/opt/cprocsp/cp-openssl/bin/amd64/openssl x509 -inform der -in file.cer -out file.pem
Получив сертификат в формате PEM, нужно скопировать его в /etc/nginx/ssl-gost.pem и выполнить
/opt/cprocsp/bin/amd64/certmgr -inst -file /etc/nginx/ssl-gost.pem -ask-cont

КриптоПро должно предоставить выбор ключевого контейнера, в списке должен быть 1 элемент (ключ, скопированный на предыдущем шаге). Следует ввести цифру 1 и нажать Enter, таким образом выбрав единственный вариант. Если ключ защищён паролем, будет предложено ввести пароль.

Если ключ защищён паролем (если пароль запрашивался на предыдущем шаге), пароль нужно снять — командой
/opt/cprocsp/bin/amd64/csptest -passwd -container '<ИмяКонтейнера>' -change '' -passwd '<старый_пароль>'

<ИмяКонтейнера> взять с прошлого шага из списка.

Проверить установку сертификата можно командой /opt/cprocsp/bin/amd64/certmgr -list. Должен быть выведен сертификат со строкой PrivateKey Link: Yes и указан ключевой контейнер — это будет означать, что сертификат установлен корректно.

Настройка nginx

Далее добавить в конфигурацию виртуального хоста nginx строки (то, что начинается с # — комментарии/пояснения, можно не добавлять):

listen 443 ssl;
# ГОСТ сертификат
ssl_certificate /etc/nginx/ssl-gost.pem;
# "Иванов" - первое слово (без пробелов) имени сертификата (поля CN) (да, можно и так извратиться)
ssl_certificate_key engine:gost_capi:Иванов;
# RSA сертификат
ssl_certificate /etc/nginx/ssl-rsa.pem;
# RSA ключ
ssl_certificate_key /etc/nginx/ssl-rsa.key;
# шифры, приоритет ГОСТ, потом шифры семейства RSA высокой стойкости
ssl_ciphers GOST2001-GOST89-GOST89:HIGH;
ssl_prefer_server_ciphers on;
# gost_capi работает только с TLS 1.0
ssl_protocols TLSv1;
# параметры сессии
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

Такая конфигурация говорит о том, что:

  • Для клиентов, поддерживающих ГОСТ — будет использоваться ГОСТ
  • Для остальных — будет использоваться RSA
Далее нужно перенаправить nginx на библиотеку OpenSSL, поставляемую с КриптоПро — для этого надо скопировать файл /usr/lib/systemd/system/nginx.service в /etc/systemd/system/nginx.service и отредактировать его, добавив в секцию [Service] строку
Environment=LD_LIBRARY_PATH=/opt/cprocsp/lib/amd64:/opt/cprocsp/cp-openssl/lib/amd64

Кроме того, нужно выполнить команды:

ln -s libcrypto.so.1.0.0 /opt/cprocsp/cp-openssl/lib/amd64/libcrypto.so.10
ln -s libssl.so.1.0.0 /opt/cprocsp/cp-openssl/lib/amd64/libssl.so.10

А также

touch /var/opt/cprocsp/tmp/openssl.log
chown nginx:nginx /var/opt/cprocsp/tmp/openssl.log

После этого выполнить команду

systemctl daemon-reload

Примечание: так получается сделать по той причине, что и в КриптоПро, и в RHEL 7.2 используется OpenSSL 1.0.x, то есть версии совместимы. При несовместимости версий нужно будет собирать nginx из исходных кодов, следующими командами:

./configure --user=nginx --group=nginx --prefix=/usr --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --with-http_ssl_module --with-cc-opt='-I/opt/cprocsp/cp-openssl/include/' --with-ld-opt=-L/opt/cprocsp/cp-openssl/lib/amd64/
make -j4
make install

Однако для RHEL/CentOS 7.2 этого можно не делать.

Настройка SELinux и прав доступа

Далее, если на сервере не отключён SELinux (по умолчанию в RHEL 7.2 включён), нужно установить политику SELinux: http://svn.yourcmc.ru/vitalif/trunk/cryptopro-nginx-rhel7. Команды для установки:

semodule -i cpro_nginx.pp
restorecon -R /var/opt

После этого — перезапустить nginx: systemctl restart nginx.

Альтернативный путь (упрощённый): остановить nginx, если запущен (systemctl stop nginx), установить пакет policycoreutils-python и далее повторять следующие 3 команды до тех пор, пока nginx не стартует:

systemctl start nginx
grep denied /var/log/audit/audit.log | audit2allow -a -M cryptopro-nginx
semodule -i cryptopro-nginx.pp

Проверка работы

Для проверки нужно использовать openssl s_client на сервере.

Для проверки работы RSA: /usr/bin/openssl s_client -connect localhost:443 (с помощью системной OpenSSL без поддержки ГОСТ).

Для проверки работы ГОСТ: /opt/cprocsp/cp-openssl/bin/amd64/openssl s_client -connect localhost:443 (с помощью OpenSSL КриптоПро).

При условии нормальной работы TLS на экран в обоих случаях должен быть выведен сертификат сервера, детали соединения (Cipher — шифр, в первом случае вида …RSA…, во втором GOST2001-GOST89-GOST89), и openssl должен остаться включённым с приглашением ко вводу, то есть, при вводе «GET / <Enter>» должен быть выведен HTTP ответ сервера, а следующую команду должно быть можно ввести только после отправки запроса (GET /) или нажатия Ctrl-C.

Если обе проверки удаются — соединение из клиентского браузера тоже будет работать.

Ошибки

В случае, если первый s_client (RSA) выводит строки «no peer certificate available» и «New, (NONE), Cipher is (NONE)» — следует проверить наличие в конфигурации nginx (/etc/nginx/nginx.conf, /etc/nginx/conf.d/*.conf) строк ssl_certificate и ssl_certificate_key с RSA-сертификатом и ключом.

В случае, если первый s_client (RSA) отрабатывает и выводит приглашение ко вводу, а второй (ГОСТ) выводит детали соединения и шифр GOST2001-GOST89-GOST89, но после этого сразу выходит в терминал — следует проверить права на файл /var/opt/cprocsp/tmp/openssl.log — владельцем файла должен быть пользователь nginx, а права должны стоять 644 (см. выше команду по смене владельца chown). Несмотря на то, что КриптоПро в инструкции по установке требует запускать nginx именно под пользователем root, наличия прав доступа к openssl.log должно быть достаточно для выполнения nginx под пользователем nginx.

Если права корректны, но ГОСТ s_client всё равно сразу выходит в терминал — следует поменять user nginx; на user root; в /etc/nginx/nginx.conf, перезапустить nginx и проверить s_client ещё раз.

Если и после этого ГОСТ s_client сразу выходит в терминал — можно проверить, прописана ли на сервере актуальная лицензия КриптоПро командой: /opt/cprocsp/sbin/amd64/cpconfig -license -view. Если лицензия невалидна, в выводе будет «the license is expired or not yet valid», а сервер тихо откажется работать. Также при этом в syslog/journalctl будут сообщения о невалидности лицензии от cryptsrv. Устанавливается лицензия командой /opt/cprocsp/sbin/amd64/cpconfig -license -set <КЛЮЧ>.

Некритичные ошибки

При запуске или перезапуске nginx возможны сообщения:

/usr/sbin/nginx: /opt/cprocsp/cp-openssl/lib/amd64/libssl.so.10: no version information available (required by /usr/sbin/nginx)
/usr/sbin/nginx: /opt/cprocsp/cp-openssl/lib/amd64/libcrypto.so.10: no version information available (required by /usr/sbin/nginx)

— данные ошибки некритичные, работе не мешают.

В журнале ошибок nginx /var/log/nginx/error.log возможно сообщение:
[alert] ignoring stale global SSL error (SSL: error:140DD112:SSL routines:SSL_CERT_DUP:library bug) while handshaking

— это известное поведение библиотеки КриптоПро, работе не мешает.

При выполнении s_client в строке «Verify return code», в зависимости от сертификата, допустимы сообщения:

Verify return code: 21 (unable to verify the first certificate)
Verify return code: 18 (self-signed certificate)

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

Формат ключа

Формат ключа КриптоПро — не стандартный ASN1/PEM (-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----), а директория, содержащая файлы header.key, masks.key, masks2.key, name.key, primary.key, primary2.key.

Под Windows ключи хранятся аналогично, но в реестре, в ветке HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Crypto Pro\Settings\Users\<Пользователь>\Keys и в hex-кодировке. Для конвертации нужно выгрузить эту ветку в файл и подветки превратить в директории, а ключи с именами, аналогичными файлам выше — превратить в файлы путём перекодирования из hex в бинарный формат. Автоматически это можно сделать скриптом http://svn.yourcmc.ru/vitalif/trunk/scripts/convert-cryptopro.sh?view=co (скормив ему выгруженный файл *.reg)

Также под Windows есть поддержка экспорта сертификата и ключей в формат *.pfx. Но такие ключи потом невозможно импортировать в Linux-версию КриптоПро.