- Linux
- Госты
- Использование образа в работе с языками программирования
- Конфигурирование stunnel
- Настройка openssl
- Настройка гост openssl под ubuntu 18.04
- Подготовительный шаг
- Поддержка гост-алгоритмов в php
- Поддержка гост-сертификатов в nginx
- Примеры использования openssl gost-engine
- Проверка подписи эцп
- Проверка сертификата
- Сборка openssl, gost-engine, curl
- Список установленных сертификатов
- Ссылки
- Установка openssl
- Установка и настройка криптопровайдера
- Экспорт сертификатов и ключей из windows
- Заключение
Linux
Устанавливаем пакет openssl, debian:aptitude install openssl
Госты
ГОСТ 28147-89 симметричный алгоритм шифрованияГОСТ Р 34.10-2021 электронная цифровая подписьГОСТ Р 34.11-2021 хеш-функция
Использование образа в работе с языками программирования
Если язык программирования позволяет исполнять установленные в системе программы, то задача использования ГОСТ-алгоритмов проще всего решается копированием бинарников собранных openssl и curl в конце Dockerfile языка программирования с использованием multi-stage build. Например:
FROM rnix/openssl-gost AS openssl-gost
# Replace with any other image based on Debian x86_64
FROM debian:stretch-slim
COPY --from=openssl-gost /usr/local/ssl /usr/local/ssl
COPY --from=openssl-gost /usr/local/ssl/bin/openssl /usr/bin/openssl
COPY --from=openssl-gost /usr/local/curl /usr/local/curl
COPY --from=openssl-gost /usr/local/curl/bin/curl /usr/bin/curl
COPY --from=openssl-gost /usr/local/bin/gostsum /usr/local/bin/gostsum
COPY --from=openssl-gost /usr/local/bin/gost12sum /usr/local/bin/gost12sumДаже необязательно копировать в /usr/bin, это можно сделать в любой каталог, а затем вызывать из вашей программы, передав полный путь и все аргументы.
Конфигурирование stunnel
Осталось только правильно настроить наш туннель. Для этого создадим файл stunnel.conf с настройками Stunnel по умолчанию и напишем туда следующее:
Настройка openssl
В windows ищем конфиг в папке OpenSSL (Например, «C:OpenSSL-Win32binopenssl.cfg»). В linux обычно это /etc/ssl/openssl.cnfВ конфиге до секций «[бла_бла_бла]» пишем:
openssl_conf = openssl_def[openssl_def]engines = engine_section[engine_section]gost = gost_section[gost_section]engine_id = gostdynamic_path = /usr/lib/i386-linux-gnu/openssl-1.0.0/engines/libgost.sodefault_algorithms = ALLCRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet
dynamic_path в linux можно найти просто:locate libgost.soБез опции CRYPT_PARAMS — не будет работать опция -gost89. А без -gost89 при шифровании данных вместо GOST 28147-89 используется rc2-cbc. КриптоАРМ не примет такое шифрование, вернёт ошибку вида:—————————КриптоАРМ—————————Произошла ошибка при расшифровании сообщения.
Ошибка сохранения сообщения (0x80004005)Произошла ошибка при расшифровании сообщения. (0x80004005)Произошла ошибка при расшифровке сообщенияНеправильное значение индекса. (0x80091008) (0x80004005)—————————ОК—————————
Настройка гост openssl под ubuntu 18.04
Подготовительный шаг
Нам понадобится:
- OpenSSL
- Stunnel
- rtengine
- Доступ к тестовым серверам КриптоПро, для проверки соединения по TLS
OpenSSL для Windows можно взять отсюда, а для пользователей линукса — из репозиториев или собрать самому, скачав свежую версию отсюда. Также его можно взять из Rutoken SDK, из директории opensslopenssl-tool-1.
Поддержка гост-алгоритмов в php
PHP, конечно, позволяет делать вызовы системных команд, используя, например, exec. Но, глядя на то, как собирается PHP-FPM в Dockerfile, мне показалось, что можно легко собрать PHP с кастомными сборками OpenSSL и cURL. Как оказалось дальше, я ошибся, что это легко. Всё равно собрал.
По какой-то причине, я начал с PHP-FPM 7.1. Идея была в том, чтобы использовать multi-stage build. Для этого надо заменить в их Dockerfile инструкцию FROM на мою FROM rnix/openssl-gost AS openssl-gost, затем прописать копирования собранных openssl и curl до начала сборки самого php и, наконец, указать в опции сборки путь до этих библиотек –with-openssl-dir=/usr/local/ssl и –with-curl=/usr/local/curl заменив оригинальные.
Сюрпризы ждали отовсюду. Одним из значительных было то, что при сборки php 7.1 используется pkg-config, а явная установка libcurl4-openssl-dev, libssl-dev прописывали в pkg-config версии из пакетов. В результате собиралось не то, что нужно. Если убрать их установку, то /configure php падал, ссылаясь на отсутствие openssl в pkg-config.
Пришлось дополнительно копировать из кастомных сборок openssl и curl их lib/pkgconfig /*. После десятков таких сюрпризов сборка начала проходить. Дальше выяснилось, что зависимости устанавливали openssl, тем самым перезатирая ранее скопированный бинарник моей кастомной сборки. Пришлось дополнительно копировать его в самом конце. Но это не всё.
Поддержка гост-сертификатов в nginx
Возможность работать из языков программирования это уже много, но хотелось еще две возможности:
Примеры использования openssl gost-engine
Не буду сильно вдаваться в подробности работы с докер-образами, лишь приведу одну команду для начала работы внутри образа:
docker run --rm -i -t rnix/openssl-gost bashДля начала можно убедиться, что алгоритмы GOST2021-GOST8912-GOST8912 и GOST2001-GOST89-GOST89 есть в списке поддерживаемых:
openssl ciphersПроверка подписи эцп
Для верифицирования сертификатов нужен сертификат удостоверяющего центра и актуальный список отзыва сертификатов,
либо настроенный для этого revocation provider.
Корневой сертификат УЦ, список отзыва сертификата является одним из реквизитов самого сертификата.
Контрагенты когда открывают подписи в КриптоАРМ используют revocation provider, он делает проверки отзыва сертификата онлайн.
Как реализована проверка в Шарепоинте не знаю. Знаю только что используется библиотека Крипто.Net
cryptcp -verify-nochain
Проверка конкретной подписи из локального хранилища по его хешу:
cryptcp -verify-thumbprint 255c249150efe3e48f1abb3bc1928fc8f99980c4 -nochain test.txt.sig
Проверить, взяв сертификат из file1.sig, подпись файла file2.sig. Практически, надо использовать один и тот же файл:
cryptcp -verify-norev-f file1.sig file2.sig
Ответ:
Certificates found: 2 Certificate chains are checked. Folder './': file.xls.sig... Signature verifying... Signer: Старший инженер, Иванов Иван Иванович, Отдел закупок, ООО «Верес», Москва, RU, info@site.ru Signature's verified. Signer: Генеральный директор, Сидоров Иван Петрович, Руководство, ООО «Кемоптика», Москва, RU, info@site.ru Signature's verified. [ReturnCode: 0]
Результат:
Проверка сертификата
certmgr -list-f file.sig
Ответ:
1------- Issuer : E=cpca@cryptopro.ru, C=RU, L=Москва, O=ООО КРИПТО-ПРО, CN=УЦ KPИПTO-ПPO Subject : E=info@site.ru, C=RU, L=г. Москва, O="ООО ""Верес""", OU=Руководство, CN=Иванов Иван Иванович, T=Генеральный директор Serial : 0x75F5C86A000D00016A5F SHA1 Hash : 0x255c249150efe3e48f1abb3bc1928fc8f99980c4 Not valid before : 08/12/2021 09:04:00 UTC Not valid after : 08/12/2021 09:14:00 UTC PrivateKey Link : No
Сборка openssl, gost-engine, curl
Сборка стороннего продукта для тех, кто делает это редко, может быть нетривиальной задачей. Для сборки OpenSSL, GOST-engine и cURL пришлось разобраться с кучей опций и перепробовать несколько комбинаций версий. Если в Dockerfile вы заметите странное, то, скорее всего, это осталось от таких экспериментов.
Я зафиксировал все версии проектов для сборки, чтобы исключить ситуацию, что из-за обновления что-то перестанет работать. Например, я собирал OpenSSL 1.1.0h GOST-engine и команда openssl ciphers не содержала GOST-алгоритмов, хотя openssl engine показывала GOST-engine в списке.
Собирая сам GOST-engine, я не сразу обратил внимание на наличие файла INSTALL.md в master-ветке, потому что собирал из ветки openssl_1_1_0 по неизвестно откуда взятой документации. Та версия собиралась с кастомной сборкой OpenSSL командой
cmake -DCMAKE_C_FLAGS='-I/usr/local/ssl/include -L/usr/local/ssl/lib' ..Но master-ветка так собираться перестала, появились ошибки об отсутствии DOPENSSL_ROOT_DIR и подобное. В итоге решение было найдено и зафиксировано.
Для сборки cURL с кастомной сборкой OpenSSL гораздо больше документации, тем не менее, документация успевала устаревать, и с опциями пришлось много экспериментировать.Результат работы выложен здесь.Образ запушен в Docker Hub.
Список установленных сертификатов
certmgr -list, например:
1------- Issuer : E=support@cryptopro.ru, C=RU, L=Moscow, O=CRYPTO-PRO LLC, CN=CRYPTO-PRO Test Center 2 Subject : CN=test2 Serial : 0x120007E4E683979B734018897B00000007E4E6 SHA1 Hash : 0x71b59d165ab5ea39e4cd73384f8e7d1e0c965e81 Not valid before : 07/09/2021 10:41:18 UTC Not valid after : 07/12/2021 10:51:18 UTC PrivateKey Link : Yes. Container : HDIMAGE\test2.000F9C9 2------- Issuer : E=support@cryptopro.ru, C=RU, L=Moscow, O=CRYPTO-PRO LLC, CN=CRYPTO-PRO Test Center 2 Subject : CN=webservertest Serial : 0x120007E47F1FD9AE0EDE78616600000007E47F SHA1 Hash : 0x255c249150efe3e48f1abb3bc1928fc8f99980c4 Not valid before : 07/09/2021 09:56:10 UTC Not valid after : 07/12/2021 10:06:10 UTC PrivateKey Link : Yes. Container : HDIMAGE\webserve.0012608
Ссылки
- Репозиторий со всеми решениями на GitHub
- Образ на Docker Hub с OpenSSL GOST cURL
- ГОСТ Р 34.10-2021 на Википедии со списком сертифицированных решений
- Репозиторий GOST-engine
- О возможностях и ограничениях GOST-engine
- Пример того, как решают вопрос в продакшн-окружении
Установка openssl
Нужен OpenSSL c gost-движком.
Установка и настройка криптопровайдера
В примерах я буду использовать виртуальную машину с CentOS 7, но ты не ограничен в выборе аппаратного обеспечения и дистрибутива Linux. Все действия и команды будут такими же.
Первым делом создадим локального пользователя, под которым будет работать ПО, использующее подпись документов.
Экспорт сертификатов и ключей из windows
Для шифрования нужен сертификат, для подписывания приватный ключ.В certmgr.msc экспортировать можно только сертификаты, приватные ключи экспортируются в странном формате. Если пытаться этот формат скормить в openssl, получим неизвестный PBE 1.2.840.113549.1.12.1.80:$ openssl pkcs12 -in certmgr_msc_exported_private_key.pfx -out priv.pem -engine gost -nodes -clcertsengine “gost” set.
Enter Import Password:MAC verified OKError outputting keys and certificates140283454142144:error:06074079:digital envelope routines:EVP_PBE_CipherInit:unknown pbe algorithm:evp_pbe.c:167:TYPE=1.2.840.113549.1.12.1.80140283454142144:error:23077073:
Приватные ключи мoжно экспортировать из контейнеров КриптоПро при помощи P12FromGostCSP.exe (выбирается ключ из списка установленных, и имя файла вывода; формат вывода pkcs12, DER).
Конвертирование pkcs12-ключа в pem-формат:$ openssl pkcs12 -in priv.pfx -out priv.pem -engine gost -nodes -clcertsКонвертирование сертификата в pem-формат:$ openssl x509 -inform DER -in pub.cer -out pub.crt
Заключение
Мной изучена проблема работы с ГОСТ-алгоритмами в системах Linux, предоставлено решение в виде docker-образов, все это сопровождено документацией и примерами. Решение оформлено в виде репозитория на GitHub.
Стоит сказать о безопасности использования такого решения. Главное, не стоит доверять образам на Docker Hub, даже если там написано Automated Build. Я все равно могу собрать образ с любыми правками всех используемых библиотек и систем и запушить его в свой Docker Hub под любым тегом.
Собирая образ самостоятельно, вы можете убедиться, что в код не попали злонамеренные правки, потому что сборка происходит только из открытого кода, который доступен для просмотра всем желающим. Тем не менее, это не гарантирует, что в нем нет ошибок и уязвимостей.

Никто не знает, можно как-то красивенько замутить? Типа настройки ГОСТ вынести в отдельный конфиг, а потом просто заинклудить. Вот типа этого:
У меня не получпется. Хочу просто сделать красиво.