Одной из характерных проблем в экосистеме 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://openpgpkey.example.org/.well-known/openpgpkey/example.org/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q

По этому адресу GnuPG и совместимые клиенты ожидают найти ключи, ассоциированные с тем адресом, в бинарном виде. Клиенты учитывают HTTP переадресацию, потому можно разместить ключи на другом хосте, если настроить соответствующую переадресацию.

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

Также можно разместить ключи прямо на корневом домене, по адресу подобному тому, что ниже:

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

И есть возможность задать домен с ключами с помощью SRV записи. В этом руководстве мы будем рассматривать только вариант с поддоменом.

Настройка

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

$ gpg --version
gpg (GnuPG) 2.2.18

За раздачу файлов у нас будет отвечать 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 $1/hu
touch -a $1/policy

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

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

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

chmod +x /var/www/html/openpgpkey/install.sh
/var/www/html/openpgpkey/install.sh example.com 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
...

Также можно использовать тест самого низкого уровня:

gpg-connect-agent --dirmngr --hex 'wkd_get username@example.com' /bye