При проверке HTTPS-сервера, например с помощью SSL Labs, можно встретить предупреждение:

This server does not support PQC (Post-Quantum Cryptography) key exchange.

Первая мысль: что это означает, зачем веб-серверу постквантовая криптография и неужели квантовые компьютеры уже используются для массового взлома HTTPS?

На практике всё несколько проще. Достаточно мощных квантовых компьютеров, способных практически атаковать современную интернет-криптографию, пока нет. Однако развитие квантовых вычислений представляет реальную долгосрочную угрозу прежде всего для широко используемых алгоритмов с открытым ключом – RSA, классического Diffie–Hellman и криптографии на эллиптических кривых.

Поэтому переход к PQC начинается заранее. Особенно это важно из-за сценария harvest now, decrypt later: злоумышленник может сохранить зашифрованный сегодня трафик и попытаться расшифровать его в будущем, когда необходимые вычислительные возможности станут доступны.

Постер статьи

Что такое ML-KEM?

В августе 2024 года Национальный институт стандартов и технологий США (NIST) утвердил стандарт FIPS 203, описывающий ML-KEM – Module-Lattice-Based Key-Encapsulation Mechanism.

ML-KEM предназначен не для непосредственного шифрования передаваемых данных, а для безопасного установления общего секрета между сторонами соединения. Уже из этого секрета TLS получает симметричные ключи, которыми и защищается дальнейший трафик.

Стандарт определяет три набора параметров:

  • ML-KEM-512;
  • ML-KEM-768;
  • ML-KEM-1024.

Для TLS особенно интересны гибридные схемы, в которых классический алгоритм объединяется с постквантовым.

Один из таких вариантов: X25519MLKEM768

Он сочетает:

  • X25519 — современный классический механизм обмена ключами;
  • ML-KEM-768 — постквантовый механизм инкапсуляции ключей.

Именно гибридная схема позволяет сохранить классическую криптографическую защиту и одновременно добавить защиту от потенциальных квантовых атак.

Поддержка PQC в OpenSSL 3.5

Начиная с OpenSSL 3.5, библиотека получила нативную поддержку ML-KEM и гибридных механизмов обмена ключами для TLS 1.3.

OpenSSL 3.5 поддерживает, в частности:

  • X25519MLKEM768;
  • SecP256r1MLKEM768;
  • SecP384r1MLKEM1024.

Причём X25519MLKEM768 включён в стандартный набор групп OpenSSL 3.5 и имеет высокий приоритет при согласовании TLS 1.3. Проверить установленную версию OpenSSL можно командой:

openssl version

А версию OpenSSL, с которой работает Nginx:

nginx -V 2>&1 | grep -E 'nginx version|OpenSSL'

Начиная с Debian 13 подходящая версия OpenSSL уже входит в стандартный дистрибутив.

Настройка X25519MLKEM768 в Nginx

При использовании OpenSSL 3.5 в большинстве случаев стандартного значения:

ssl_ecdh_curve auto;

Уже достаточно: OpenSSL самостоятельно использует актуальный список поддерживаемых TLS-групп. Однако если необходимо явно определить порядок групп, в конфигурации Nginx можно указать:

ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;

Здесь:

  • X25519MLKEM768 — гибридный постквантовый механизм обмена ключами;
  • X25519 — современный классический механизм;
  • prime256v1 — NIST P-256;
  • secp384r1 — NIST P-384.

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

nginx -t

И применим:

systemctl reload nginx

Как проверить поддержку X25519MLKEM768

В OpenSSL 3.5 список доступных групп TLS 1.3 можно посмотреть командой:

openssl list -tls1_3 -tls-groups

Теперь проверим непосредственно HTTPS-соединение:

openssl s_client \
        -connect domain.ru:443 \
        -servername domain.ru \
        -tls1_3 \
        -groups X25519MLKEM768

При успешном согласовании в выводе должна присутствовать информация о группе:

Negotiated TLS1.3 group: X25519MLKEM768

Нужно ли менять SSL-сертификат?

Нет. X25519MLKEM768 используется на этапе обмена ключами TLS, поэтому существующий сертификат можно продолжать использовать.

Это два разных механизма:

  • сертификат подтверждает подлинность сервера;
  • X25519MLKEM768 участвует в безопасном установлении общего секрета для TLS-сессии.

Поэтому наличие обычного RSA- или ECDSA-сертификата само по себе не мешает использовать постквантовый обмен ключами.

Что делать, если обновиться до Debian 13 невозможно?

Если сервер работает, например, на Debian 12 с OpenSSL 3.0 и обновление всей операционной системы пока невозможно, существует несколько вариантов.

Вариант 1. Обновить операционную систему

Это предпочтительный вариант.Debian 13 содержит OpenSSL 3.5 с нативной поддержкой ML-KEM и X25519MLKEM768, поэтому нет необходимости устанавливать дополнительный криптографический провайдер или самостоятельно пересобирать системные библиотеки.

Вариант 2. Использовать OQS Provider

Для OpenSSL 3 существует проект Open Quantum Safe, предоставляющий oqs-provider. Он позволяет подключать дополнительные постквантовые алгоритмы через механизм OpenSSL Provider без замены системной libssl. Однако этот способ следует рассматривать прежде всего как экспериментальный или временный вариант. Сам проект Open Quantum Safe предупреждает, что oqs-provider предназначен главным образом для исследований и прототипирования и пока не рекомендуется для защиты чувствительных production-данных.

Вариант 3. Пересобрать Nginx с другой версией OpenSSL

Технически можно собрать отдельную версию Nginx с необходимой версией OpenSSL. Но для обычного production-сервера такой вариант наиболее сложен: придётся самостоятельно следить за обновлениями OpenSSL, Nginx и исправлениями безопасности. Поэтому без веской причины этот путь лучше не использовать.

OQS Provider для Nginx на Debian 12

Дальнейшая часть статьи рассматривает экспериментальный вариант подключения OQS Provider к отдельному процессу Nginx. Важно: мы не будем заменять системный OpenSSL и не будем глобально подключать дополнительный provider для всей системы.

Установка инструментов сборки

Установим необходимые пакеты:

apt-get update
apt-get install -y \
    build-essential \
    git \
    cmake \
    ninja-build \
    libssl-dev \
    pkg-config

Перед продолжением ещё раз проверим OpenSSL:

openssl version

Нельзя вручную заменять системную libssl только ради этой настройки: это может нарушить работу Nginx, apt, curl, PHP и других программ, которые используют системный OpenSSL.

Сборка liboqs

Перейдём в каталог исходного кода:

cd /usr/local/src

Получим исходники:

git clone https://github.com/open-quantum-safe/liboqs.git
cd liboqs

На момент написания статьи актуальным релизом является liboqs 0.16.0, содержащий в том числе исправления безопасности:

git checkout 0.16.0

Подготовим сборку:

cmake \
    -S . \
    -B build \
    -GNinja \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DOQS_DIST_BUILD=ON \
    -DBUILD_SHARED_LIBS=ON
    

Соберём библиотеку:

ninja -C build

Запустим тесты:

ctest --test-dir build

Если тесты завершились успешно, установим библиотеку:

ninja -C build install
ldconfig

Проверим, что динамический загрузчик видит её:

ldconfig -p | grep oqs

Сборка oqs-provider

Теперь получим исходный код OpenSSL-провайдера:

cd /usr/local/src
git clone https://github.com/open-quantum-safe/oqs-provider.git
cd oqs-provider

Здесь есть важный нюанс: версии oqs-provider и liboqs должны быть совместимы. Перед публикацией конфигурации на production-сервере необходимо свериться с release notes проекта и использовать проверенную комбинацию версий. Использование ветки main означает сборку текущего разрабатываемого кода, который со временем может измениться. Для тестового стенда сборка выполняется следующим образом:

cmake \
    -S . \
    -B build \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build -j"$(nproc)"

И устанавливаем provider:

cmake --install build
ldconfig

Где установлен oqsprovider.so?

Найдём библиотеку:

find /usr/local /usr/lib \
    -type f \
    -name 'oqsprovider.so' \
    2>/dev/null

В зависимости от архитектуры и настроек системы путь может выглядеть, например, так:

/usr/local/lib/x86_64-linux-gnu/ossl-modules/oqsprovider.so

или:

/usr/local/lib64/ossl-modules/oqsprovider.so

Точный путь понадобится на следующем этапе.

Отдельная конфигурация OpenSSL для Nginx

Не стоит подключать OQS Provider в системный /etc/ssl/openssl.cnf. Вместо этого создадим отдельную конфигурацию, которая будет использоваться только процессом Nginx:

nano /etc/ssl/openssl-nginx-oqs.cnf

Добавим:

openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
oqsprovider = oqsprovider_sect

[default_sect]
activate = 1

[oqsprovider_sect]
activate = 1
module = /usr/local/lib/x86_64-linux-gnu/ossl-modules/oqsprovider.so

Путь в строке module необходимо заменить на полученный на предыдущем этапе.

Проверяем загрузку OQS Provider

Запустим:

OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf \
    openssl list -providers

В выводе должны присутствовать оба provider:

Providers:
  default
    name: OpenSSL Default Provider
    status: active

  oqsprovider
    name: OpenSSL OQS Provider
    status: active

Теперь можно проверить конфигурацию Nginx. Если выполнить обычную команду:

nginx -t

при наличии:

ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;

стандартный OpenSSL Debian 12 может вернуть ошибку примерно следующего вида:

SSL_CTX_set1_curves_list("X25519MLKEM768:...") failed

Это означает не то, что конфигурация Nginx неправильная, а то, что при данном запуске дополнительный OpenSSL Provider не был загружен. Запустим проверку с нашей конфигурацией:

OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf \
    nginx -t

При успешной настройке получим:

syntax is ok
test is successful

Подключаем OQS Provider только к службе Nginx

Создадим systemd override:

systemctl edit nginx

Добавим:

[Service]
Environment="OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf"

Проверим:

systemctl cat nginx

В конце вывода должно появиться:

# /etc/systemd/system/nginx.service.d/override.conf

[Service]
Environment="OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf"

Перечитаем конфигурацию systemd:

systemctl daemon-reload

Проверим Nginx ещё раз:

OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf nginx -t

После успешной проверки перезапустим службу:

systemctl restart nginx

И убедимся, что она работает:

systemctl status nginx

Финальная проверка PQC

Теперь проверим соединение:

OPENSSL_CONF=/etc/ssl/openssl-nginx-oqs.cnf \
    openssl s_client \
    -connect domain.ru:443 \
    -servername domain.ru \
    -tls1_3 \
    -groups X25519MLKEM768

Если клиент и сервер успешно согласовали гибридную группу, соединение TLS 1.3 будет использовать X25519MLKEM768.

Итог

Постквантовая криптография в HTTPS — это уже не исключительно экспериментальная технология. Начиная с OpenSSL 3.5 ML-KEM и гибридный механизм X25519MLKEM768 поддерживаются непосредственно библиотекой, а Debian 13 поставляется с подходящей версией OpenSSL. Поэтому для нового или обновляемого production-сервера оптимальный вариант выглядит просто:

  • использовать Debian 13 или другую систему с OpenSSL 3.5 и новее;
  • использовать актуальную версию Nginx;
  • оставить стандартный список TLS-групп OpenSSL либо явно добавить X25519MLKEM768;
  • проверить результат с помощью openssl s_client и SSL Labs.

Использование OQS Provider на старой системе возможно как временное или экспериментальное решение, однако для production-сервера предпочтительнее перейти на OpenSSL с нативной поддержкой стандартизованных PQC-алгоритмов.

Если Вам понравилась заметка, обязательно делитесь ее со своими друзьями, если же есть пожелания или замечания – сообщите о них.

Использование материалов на сторонних ресурсах, без разрешения автора, запрещено.