
В этой статье я хочу показать, как настроить Stunnel на использование российских криптографических алгоритмов в протоколе TLS. В качестве бонуса покажу, как шифровать TLS-канал, используя алгоритмы ГОСТ, реализованные в криптоядре Рутокен ЭЦП 2.0.
Но для начала давайте вообще разберёмся для чего нужен Stunnel. В двух словах — это программа, на которую можно переложить всю логику шифрования трафика между сервером и клиентом. Делается это следующем образом: допустим у вас есть клиент и сервер, которые общаются между собой без использования шифрования, аутентификации и проверки целостности. Вы могли бы переписать клиент и сервер так, чтобы все исходящие и входящие сообщения передавались между собой с учётом всех этих моментов, но для чего такие сложности, если можно это просто переложить на плечи другому приложения? Для реше��ия такой задачи как раз подойдёт Stunnel.
Вам нужно просто настроить клиент таким образом, чтобы весь свой трафик он передавал на клиентский Stunnel, в свою очередь, он устанавливает безопасное соединение с сервером, отправляя данные на серверный Stunnel. Stunnel на сервере расшифровывает пришедший трафик и перенаправляет данные на вход серверу. Вышесказанное проще осознать глядя на эту диаграмму

Стоит заметить, что на сервере не обязательно должен стоять именно Stunnel, для работы с криптографическими алгоритмами. Здорово, что есть готовые демонстрационные стенды, которые поддерживают российскую криптографию, список которых есть в презентации с РусКрипто'2019.
Нам нужны стабильно работающие серверы, осуществляющие двухстороннюю аутентификацию.
Мы выбрали серверы КриптоПро как наиболее надёжные с полной реализацией стандарта ГОСТ TLS. Спасибо им за это :)
Звучит достаточно просто, давайте попробуем организовать этот процесс.
Подготовительный шаг
Нам понадобится:
- OpenSSL
- Stunnel
- rtengine
- Доступ к тестовым серверам КриптоПро, для проверки соединения по TLS
OpenSSL для Windows можно взять отсюда, а для пользователей линукса — из репозиториев или собрать самому, скачав свежую версию отсюда. Также его можно взять из Rutoken SDK, из директории openssl\openssl-tool-1.1, этот архив нам будет полезен и дальше, т.к. в нём находится интересующий нас rtengine. Stunnel можно найти здесь. Для работы необходима версия >= 5.56.
Скачать rtengine можно из Rutoken SDK, он лежит в директории openssl\rtengine\bin. Закинуть его нужно туда, где хранятся все движки openssl. Узнать путь до них можно с помощью
openssl.exe version -aНо просто переместить движок в нужную папку — мало, нужно ещё сконфигурировать сам openssl для работы с ним. Узнаём где лежит файл с конфигурацией openssl.cnf с помощью той же команды, что указана выше (под виндой stunnel идёт с собственной версией openssl, поэтому файл с конфигурацией лежит в path\to\stunnel\config\openssl.cnf
# В начале напишем:
openssl_conf = openssl_def
...
# В конце файла:
# OpenSSL default section
[openssl_def]
engines = engine_section
[engine_section]
rtengine = gost_section
[gost_section]
dynamic_path = /path/to/rtengine.so
MODULE_PATH = /usr/lib/librtpkcs11ecp.so
default_algorithms = CIPHERS, DIGEST, PKEY, RANDДавайте проверим, что rtengine подключился, для этого подключим токен и выведем список всех алгоритмов шифрования:
openssl ciphers -vНапомню, что в Windows нужно проверять на openssl, который лежит рядом с stunnel
Если среди них будут присутствовать наши ГОСТы, значит всё настроено верно.
Настало время самого интересного: проверка установки соединения по ГОСТу с тестовыми серверами КриптоПро. Список данных серверов описан здесь (https://www.cryptopro.ru/products/csp/tc26tls). Каждый из этих серверов работает со своими алгоритмами для аутентификации и шифрования. Более того на портах 443, 1443, 2443,… запущены сервисы, которые воспринимают только определённые парамсеты. Так, например, по адресу http://tlsgost-256auth.cryptopro.ru происходит шифрование с аутентификацией с использованием алгоритмов GOST2012-GOST8912-GOST8912 и 256-битным ключом. Так же на порту 443 используется XchA-ParamSet, на порту 1443 — XchB-ParamSet, на порту 2443 — A-ParamSet и т.д.
Теперь, когда мы знаем, какой ключ нам нужен, давайте получим корневой сертификат от тестового сервера, выработаем ключи для работы и подпишем запрос на наш сертификат.
Простой способ (работает под Windows и Linux)
- Для того, чтобы получить корневой сертификат, зайдём на сайт тестового УЦ ООО "КРИПТО-ПРО". И нажмём на кнопку для получения сертификата. Отобразится новая вкладка, на которой нужно будет выбрать метод шифрования Base64 и нажать на кнопку "Загрузка сертификата ЦС". Полученный файл certnew.cer сохраняем.
- Переходим по ссылке. Устанавливаем все плагины, которые от нас просят. Нажимаем на кнопку ”Создать ключ”, и выбираем для генерации алгоритм "ГОСТ Р 34.10-2012 256-бит". Далее создаём запрос на сертификат, в графе "Применение" можно выбрать все. В графе Дополнительное применение: Аутентификация клиента и Пользователь центра регистрации КриптоПро.
- Опять открываем сайт тестового УЦ, но на этот раз нажимаем на кнопку "Отправить готовый запрос PKCS#10 или PKCS#7 в кодировке Base64". Вставляем в поле содержимое нашего запроса, нажимаем на клавишу “Выдать” и загружаем сертификат user.crt в формате Base64. Полученный файл сохраняем.
Через командную строку
Для того, чтобы получить корневой сертификат, зайдём на сайт тестового УЦ ООО "КРИПТО-ПРО". И нажмём на кнопку для получения сертификата. Отобразится новая вкладка, в которой нужно будет выбрать метод шифрования Base64 и нажать на кнопку "Загрузка сертификата ЦС". Полученный файл certnew.cer сохраняем.
Теперь генерируем ключи.
pkcs11-tool --module /usr/lib/librtpkcs11ecp.so --keypairgen --key-type GOSTR3410-2012-256:B -l --id 45 # 45 -- код символа ASСII id ключа (E)
Стоит заметить, что сгенерированные на токене ключи не могут быть скопированы с токена. В этом состоит одно из ос��овных преимуществ их использования.
Создадим запрос на сертификат:
openssl req -engine rtengine -new -key="pkcs11:id=E" -keyform engine -out client.req
Опять открываем сайт тестового УЦ, но на этот раз нажимаем на кнопку "Отправить готовый запрос PKCS#10 или PKCS#7 в кодировке Base64". Вставляем в поле содержимое нашего запроса, нажимаем на кнопку Выдать и загружаем сертификат user.crt в формате Base64. Полученный файл сохраняем
Остался последний вопрос: Для чего всё это??? Зачем мы получали все эти сертификаты, ключи и запросы?
Дело в том, что они нужны протоколу TLS для двусторонней аутентификации. Работает это очень просто.
У нас есть сертификат сервера, и мы считаем его доверенным.
Наш клиент проверяет, что сервер, с которым мы работаем имеет аналогичный сертификат.
Сервер же хочет убедиться, что работает с пользователем, который ему известен. Для этого мы и создавали запрос на сертификат для работы через наши ключи.
Мы отправили этот запрос и сервер подписал её своей ЭЦП. Теперь мы можем каждый раз предъявлять этот сертификат, подписанный корневым УЦ, тем самым подтверждая, что мы — это мы.
Конфигурирование Stunnel
Осталось только правильно настроить наш туннель. Для этого создадим файл stunnel.conf с настройками Stunnel по умолчанию и напишем туда следующее:
; уровень логирования и путь до лог-файла
debug = 7
output = /path/to/stunnel.log
; устанавливаем протокол защиты TLSv1
sslVersion=TLSv1
; подгружаем движок.
engine=rtengine
; настраиваем туннель на клиенте
[remote system]
client=yes
; указываем engine, необходимый для подгрузки ключей
engineId=rtengine
; устанавливаем верификацию 2 (принудительную проверку сертификата)
verify = 2
; путь до корневого сертификата
CAFile = /path/to/certnew.cer
; путь до сертификата клиента
cert=/path/to/user.crt
; путь до ключа на токене.
key=pkcs11:model=Rutoken%20ECP;manufacturer=Aktiv%20Co.;id=E
; указываем откуда Stunnel принимает соединение и куда посылает
accept = localhost:8080
connect = tlsgost-256auth.cryptopro.ru:2443
Теперь, если всё сделано правильно, можно запустить Stunnel с нашей конфигурацией и подключиться к серверу:
stunnel.exe /path/to/stunnel.confОткроем браузер и зайдём по адресу localhost:8080. Если всё верно, то отобразится следующее:

Если же нет, то смотрим логи и используем отладчик, чтобы понять в чём же всё-таки проблема.
Если у вас остались какие-то вопросы, то милости просим в комментарии :)
