Настройка ГОСТ-TLS через КриптоПро
В протоколе 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 пунктам:
- Найти в комплекте поставки ИЛИ собрать engine «/usr/lib64/openssl/libgost.so»
- Включить её в конфигурации 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
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-версию КриптоПро.