Одной из характерных проблем в экосистеме OpenPGP — проблема получения ключей. Хотите вы отправить зашифрованное письмо шапочному знакомому (не смотря на то, что шифрованная переписка средствами PGP — не лучшая идея в первую очередь из-за отсутствия PFS), или же хотите проверить цифровую подпись какого-то файла или какого-то коммита в Git, как вы можете получить ключи того человека? Как вы можете знать что это ключи именно того человека, а не кого-то, выдающего себя за этого человека? Можно ли им доверять?

Проблему получения ключей должна были решить сервера ключей, а сегодня эту проблему решает распределенная сеть серверов ключей. Проблему доверия и проверки ключей должна была решить Web of Trust, или, как ее можно назвать по-русски, сеть доверия.

Нельзя сказать что сервера ключей и сеть доверия полностью решили все упомянутые проблемы. Да, теперь нет проблемы получить какой-то ключ по его отпечатку с сервера ключей, и даже можно попробовать найти ключ по адресу электронной почты, и да, при проведении некоторой детективной работы можно сделать предположение, что найденный ключ — того самого человека. Вся эта эта процедура лишена автоматизма и оставляет место для человеческой ошибки и всевозможных манипуляций.

Широкие возможности для манипуляций открывает отсутствие каких-либо проверок на подлинность загружаемых ключей на публичных серверах ключей кроме, может быть, формальной математической корректности их параметров. Потому, например, нет ничего, что помешало бы кому-то сделать ключ с имейлом любого другого человека, и нет проблемы подобрать короткий ID ключа чтобы тот совпадал с любым другим известным ключом.

Другой проблемой уже идеи сети доверия является общая сложность процесса создания сети доверия включая, например, формально заявленную необходимость личных встреч, с одной стороны, и небрежность в подписании ключей множеством пользователей, с другой стороны. Например, посмотрите, сколько человек подписали ключи роботов 4AEE18F83AFDEB23 и 2F3898CEDEE958CF, которые, мы имеем все основания предполагать, не ходят на встречи для обмена подписями.

Попыткой решить эти проблемы было хранение ключей в DNS используя ли записи CERT из RFC 4398, используя DANE, или специальные записи PKA. Эти попытки в целом провалились из-за неспешного внедрения DNSSEC и общей подверженности MITM системы DNS. Дошло до того что сами разработчики GnuPG не рекомендуют использовать эти методы.

Что разработчики GnuPG рекомендуют — это Web Key Directory.

Что такое Web Key Directory?

Web Key Directory, или, сокращенно, WKD - это способ получить ключи кого-то зная только адрес электронной почты. В отличии от получения ключей через DNS, для WKD не нужно менять настройки зоны и нет проблемы с приватностью так как запросы к ключам и передача самих ключей осуществляется по HTTPS. В отличии от серверов ключей, на которых тоже в принципе можно найти ключи по имейлу, с WKD вы можете быть уверены что ключи на сервер загрузил владелец домена или авторизованное лицо, а не кто-то посторонний.

Например, для адреса joe.doe@example.org мы получаем ссылку вида:

https://example.org/.well-known/openpgpkey/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q

По этому адресу GnuPG и совместимые клиенты ожидают найти ключи, ассоциированные с тем адресом, в бинарном виде.

Ещё раз отметим что для работы WKD требуется настроить HTTPS. Это не должно быть проблемой с учётом того, что сегодня SSL сертификаты Let's Encrypt для сайтов не стоят ничего.

Настройка

Для настройки мы используем GnuPG версии 2.2.15. Более поздние и некоторые более ранние тоже подойдут (проверялась также версия 2.1.18).

$ gpg --version
gpg (GnuPG) 2.2.15

За раздачу файлов у нас будет отвечать NGINX. В конфигурации нашего домена добавляем директивы:

location /.well-known/openpgpkey {
  alias /var/www/html/openpgpkey;
  default_type application/octet-stream;
  add_header Access-Control-Allow-Origin "*";
}

По стандарту файлы должны отдаваться с MIME-типом application/octet-stream. Заголовок Access-Control-Allow-Origin добавляем чтобы наши ключи могли увидеть пользователи OpenPGP.js напрямую, без необходимости проксировать ваши ключи через другие сервера.

Создаем каталог для ключей как указано в конфиге (это может быть и другой каталог вроде /home/example.com/openpgpkey), помещаем в него скрипт ниже, который можно назвать, например, install.sh:

#!/usr/bin/env bash
set -o nounset -o errexit

cd $(dirname $0)
mkdir -p hu
touch -a policy

gpg --quiet --batch --recv-key "$1"
for pka in $(gpg --export-option export-pka --export "$1" | grep TYPE37 | cut -f1 -d' '); do
    gpg --export-options export-minimal,export-clean --export "$1" > hu/$pka
done

Этот скрипт исходит из того, что ваши ключи уже есть на серверах ключей.

Запускаем скрипт установки с отпечатком вашего ключа (из вывода gpg -K):

chmod +x /var/www/html/openpgpkey/install.sh
/var/www/html/openpgpkey/install.sh 532E374FEA670E8853B25D6680F8B43E2F03D644

Проверка поиска ключей

Проверяем, для чистоты эксперимента лучше не на сервере:

$ GNUPGHOME=$(mktemp -d) gpg --verbose --locate-keys username@example.com
gpg: error retrieving 'username@example.com' via Local: No public key
....
gpg: auto-key-locate found fingerprint ....
gpg: automatically retrieved 'username@example.com' via WKD
...

Все получилось! Ваш ключ получен прямо с сервера по HTTPS, используя протокол WKD.

Остается добавить команду установки ключа в crontab для запуска в случайное время дня. Поставил и забыл: для обновления ключа на сайте достаточно выгрузить новую версию на сервера ключей. И только!

Отладка возможных проблем

Если есть подозрения что ключи загружаются не с сервера напрямую, можно проинструктировать GnuPG использовать WKD и только:

gpg --verbose --auto-key-locate wkd,nodefault --locate-keys username@example.com

Должно вывести что-то похожее на следующее:

...
gpg: automatically retrieved 'username@example.com' via WKD
...