OpenPGP crypto key


Привет.
Я думаю над проектом устройства, реализующего необходимые для конфиденциальной переписки криптографические функции. Мотив в том, чтобы предотвратить доступ к хранилищу ключей с потенциально скомпрометированного компьютера. Вопрос – как организовать интерфейс взаимодействия устройства с хостом. В конечном счёте, хотелось бы получить решение, полностью совместимое с протоколом openpgp: формат ключей, сообщений, подписей и прочее. Чтобы мне не изобретать велосипеды, может быть, вы подскажете какие стандартные решения в этой области применимы? Читал, что есть стандарт PKCS #11, но пока не ознакомился с документацией. Он будет пригоден для моей задачи?
Спасибо!

Комментарии
— SATtva (06/04/2014 15:48, исправлен 06/04/2014 15:49)   

Он решает ровно эту задачу. GnuPG и PGP поддерживают хранение закрытых ключей на PKCS#11-совместимых смарт-картах.

Гость (07/04/2014 06:38)   

Токенов и так существует дофига (при том, что их безопасность — довольно-таки условная штука), а интерфейсов для работы с ключом из-под другой ОС или другого юзера в той же ОС нет. Лучше бы вы их сделали. Нужно, чтоб работа с приватным ключом велась под другой ОС, доступной по сети (допустим, на каком-то порту крутится демон). Клиент мог бы предоставлять демону данные на шифрование, расшифрование и подпись, но не мог бы заставить его выдать сам приватный ключ. И надо ещё интегрировать поддержку этого дела в тот софт, что завязан на PGP (mail-клиенты, jabber), чтоб прозрачно всё работало.
— SATtva (09/12/2014 09:08)   
Если в новогодние каникулы не возникнет срочной работы, сделаю такую штуку. Единственно, поддерживать она будет только gpg, но не gpgme.
Гость (10/12/2014 02:12)   

И это тоже сделаете? :-)
— SATtva (10/12/2014 11:57, исправлен 10/12/2014 12:00)   

Если приложение использует обычный командный интерфейс gpg вместо линковки с gpgme, всё должно работать из коробки.


Решение видится следующим. Клиент-серверное приложение на питоне, используется простейший сетевой протокол а-ля telnet (никакого канального шифрования, его пользователь может навесить сам с помощью ssh-туннеля). Клиент, которым заменяется бинарник gpg, принимает набор команд и возможный ввод с stdin и без изменений шлёт серверу. Сервер отфильтровывает небезопасные команды (типа --export-secret-keys и таких, которые модифицируют связку, хотя скорее всего там будет настраиваемый белый список) и передаёт их локальному gpg. Полученный результат повторно фильтруется на предмет PRIVATE KEY BLOCK и возвращается клиенту. Клиент выводит данные.

Гость (10/12/2014 18:29)   
Спасибо, понятно.
Гость (11/12/2014 01:01)   

А если я ему передам на шифрование какой-нибудь третий приватный ключ, он его зашифрует? Или если слова «PRIVATE KEY BLOCK» будут в тексте, который надо будет зашифровать или подписать, он это сделает?
— Извращенец (11/12/2014 01:07)   
... к примеру, делаю запрос сделать --clearsign-подпись какого-нибудь приватного ключа.

Если какие-то внешне валидные штуки вдруг будут запрещены, в некоторых автоматических протоколах (типа tkabber XMPP[link1]) другая сторона потенциально сможет отличать обычных юзеров gpg от заSATtva'енных ⇒ брешь в анонимности.
— SATtva (11/12/2014 10:52, исправлен 11/12/2014 10:59)   

<irony> Ой, и правда, если в jabber-клиенте дыра, и он почему-то не сливает закрытый ключ противнику, — это та ещё деанонимизация. </irony> Лол, а Вы хотели и рыбку съесть, и сковородку не запачкать? Но вообще под запрет должны попасть только реально небезопасные действия, которые программы-пользователи gpg и так не должны выполнять. Я даже пока не уверен, нужно ли в действительности отфильтровывать PRIVATE KEY BLOCK — это скорее перестраховка (тем более, что вывод может быть запрошен без --armor, а разбирать бинарный формат у меня нет никакого желания).

Гость (11/12/2014 11:36)   

И я к тому, что перестраховка в некоторых случаях может дать тривиальный различитель. Пример с tkabber плохой, но, допустим, у нас есть некоторое приложение, работающее с сетью в сколь-нибудь автоматическом режиме. Сторона потенциального противника может добиться, чтобы я ему что-то подписал. Если вдруг оказывается, что мой клиент отправляет противнику все обычные сообщения, а после вставки в них определённой строки уже не отправляет, противник понимает, что моя версия gpg необычная.

К примеру, в почтовом письме абонент укажет где-то слова PRIVATE KEY BLOCK, а я должен буду их процитировать при ответе на письмо, подписать и отправить. Там, конечно, неавтоматически делается (поэтому пример тоже плохой), но смысл примерно в этом. Я клоню к тому, что стоит ли такое делать (перестраховку), если не знать всех подводных камней, где, кем и как такая обвязка может использоваться. Например, перестраховку можно сделать опциональной и отключаемой.
— unknown (11/12/2014 12:21, исправлен 11/12/2014 12:21)   

gpg не предназначен для анонимности путём сокрытия версий. Даже если там есть --no-emit-version, то я бы этому не доверял, у разработчиков стойкая неразличимость, скорее всего, не в приоритете.

— SATtva (11/12/2014 12:28)   
Гость, я так понимаю, говорит о том, что если на стандартный ввод gpg возвращает нестандартный вывод (который может быть доступен противнику), противник может заключить, что пользователь использует gpg в нестандартном окружении. Получается достаточно уникальный профиль, снижающий анонимность до псевдонимности.
Гость (11/12/2014 16:53)   

Да, или никакого.


Да, об этом и речь. Дело не в том, что противник узнает версию и тем самым сузит поиск, а в том, что если такой программой пользуются полтора анонима, то ваш профиль будет светиться везде и всюду (особенно если вы такое gpg будете использовать как в анонимном, так и в неанонимном своих аккаунтах).
— SATtva (11/01/2015 14:43)   
Небольшой status report. Работаю над программой, осталось не так много. Увы, как бы мне того ни хотелось, полностью выдержать принцип KISS не удалось из-за поддержки обработки файлов — это потянуло за собой заметное усложнение кода. Плюс потребовалось более тонко разбирать аргументы командной строки, чтобы не сделать сервер уязвимым к раскрытию информации: в тривиальном случае клиент мог бы передать серверу путь к файлу в его (сервера) файловой системе, тот скормил бы его GPG и вернул клиенту.
Гость (11/01/2015 15:19)   
Хорошо, будем посмотреть. Результат будет в виде чего? Питон-скрипт? Deb-пакет? Gentoo-ebild?
— SATtva (11/01/2015 15:24)   
Скрипты и документация.
— SATtva (17/01/2015 17:29)   
Раньше как-то не придавал значение такой штуке, но тут она, конечно же, всплыла во всей красе. Изначально была надежда, что если не вайтлистить опции типа --import, то связка будет фактически только для чтения. Хрен бы там! GPG настолько умён, что читает мысли пользователя парсит стандартный ввод в зависимости от контекста.

Скажем, если кинуть ему в stdin ключ (не важно, открытый или закрытый), он автоматически импортирует его на связу(и), не задавая никаких вопросов. Более того, он сделает это, независимо от того, в какой части ввода поймает хидеры ключа. Зато если вызвать gpg -e, то ключ, он, конечно же не импортирует, а зашифрует.

Программу я всеми силами старался сделать context-agnostic. Единственная опция, являющаяся спэшл-кейсом в обработке — это --output/-o. Такой подход я считаю правильным, т.к. пытаться детально эмулировать поведение GnuPG в зависимости от контекста — всё равно, что прыгнуть в бездонный колодец; плюс GnuPG в любой момент может изменить своё поведение, открывая какие-то дырки на уровне выше.

Короче, как и думалось[link2] изначально, попытки выковыривать неудобные данные из stdin совершенно бесперспективны. Хотя лично мне не особо нравится, что клиент может безнаказанно кидать серверу на связку какие-то левые ключи, всё-таки не вижу в этом большого риска,1 поэтому, если только кто-нибудь не сможет предложить элегантное решение, выведу модификацию связки из модели угрозы. В конечном счёте, на административном уровне решение существует: запускать сервер от пользователя, не имеющего доступ на запись файлов связок.

К слову, из-за того же моего нежелания разбирать контекст возникают некоторые другие неочивидные отличия в поведении программы.2 В частности, если вызвать процесс gpg без параметров или с параметрами -s, -e и т.п., не передав ему ничего в stdin, он почему-то считает, что надо ожидать ввод из TTY и наглухо залипает. Подозреваю, что это можно как-то победить (хотя пока не знаю как), но до тех пор при пустом stdin передаю туда пустую строку — аналог cat /dev/null | gpg [...], из-за чего он может выплюнуть какой-то шифртекст или системную ошибку.


1 Я думал над этим, но не могу перевести такую "особенность" в вектор атаки, разве что в крайнем случае DoS, если клиент засрёт серверу связку/диск ключами.
2 Кстати, не нужно думать, будто в остальном поведение будет стандартным. Там куча отличий, специфических сообщений об ошибках и т.д.
Гость (17/01/2015 20:04)   

Fxd


Проверяете вывод на наличие там блоков PRIVATE KEY?


Вы издеваетесь что ли? Вот вам три атаки[link3]. Могу раскрыть любую одну из них. Не продолжайте работу, пока не найдёте другие две.

  1. Как почтовые и джаббер-программы определяют, какой приватный ключ использовать? Правильно, по KeyID'у (нередко ещё и укороченному). Атакующий добавляет на связку свой ключ с такими же параметрами и таким же[link4] укороченным uid'ом — всё, теперь ваши сообщения будут подписываться ключом атакующего. Правда, вы не сможете расшифровать вам приходящие сообщения (они будут зашифрованы настоящим ключом). Впрочем, это решаемый вопрос, если аналогичную атаку провести и на стороне вашего абонента. Могут быть нюансы, когда это всё же не сработает — допустим, на приватный ключ стоит пароль, который атакующий не знает.

  1. То же, что и в предыдущем пункте, но не для вашего ключа, а для ключа ваших абонентов. В настроках почты и джаббера сидят всё те же KeyID'ы. Достаточно подобрать ключ с таким же KeyID'ом и сунуть его вам на связку, как вы начнёте шифровать сообщения этим подставным ключом, а не настоящим.3 Если делаем классический MITM, получается всё вообще шикарно. А ещё круче — это когда такая атака делается на обоих сторонах связи, тогда расшифровать можно весь поток сообщений в обе стороны.

  1. Я не привык подписывать своим ключом другие. Если главный ключ связи хранится отдельно, а подпись надо сделать lsign, подписывание превращается в настоящий геморой — видимо, надо будет каждый раз стирать и копировать pubring. Когда я проверяю подпись, допустим, на TBB, я не помню наизусть отпечток Erinn, и на моей связке десятки ключей. Если однажды на ней появится подставной ключ Erinn с другим отпечатком, и подпись сверится по нему, подстава может пройти незамеченной.


Да, это хорошее замечение. Правда, не знаю, как это будет выглядеть технически. Дело в том, что в ~/.gnupg хранится в т.ч. регулярно обновляемый random_seed. Наверно, на ~/.gnupg надо выставить права rx, а на pubring.gpg и secring.gpgr.4


А разе в командной строке он не так же себя ведёт? Наберите gpg и нажмите Eneter — он будет ждать ввода с TTY. Пока не нажмёте Ctrl+C (прерывание) или Ctrl+D (корректное завершение потока), он так и будет висеть:
$ gpg
gpg: Go ahead and type your message ...

P.S. Основная мысль: понять, какие опции нужны GnuPG для автоматической работы с почтой и джаббером, и разрешить только их. Т.е., белый лист вместо чёрного. Ну, и как ещё одна организационная мера — иметь много связок, каждая для своей цели, не класть все яйца в одну корзину. Например, там, где происходит ручная работа с командной строкой и под доверенным пользователем, этими навороченными интерфейсами можно вообще не пользоваться.


3 Могут быть нюансы с выбором приоритетов, но я про это не в курсе. Если бы это делалось в командной строке, GnuPG бы предложил выбрать один из двух ключей, т.к. KeyID не фиксирует конкретный, или нет? Не знаю, как с этим будет работать автоматика, когда это вызывается джаббером или почтовой программой.
4 Если на ~/.gnupg будет rwx, атакующий не сможет поменять существующие pubring.gpg и secring.gpg, но сможет просто их стереть и вместо них создать свои новые с такими же именами.
— SATtva (18/01/2015 00:02)   

Там впереди частица "не", которую Вы, видимо, не заметили. У Вас получается, что если --import не заблэклищен (т.е. разрешён), то связка будет только для чтения.


Нет, это излишне.


Это ещё вопрос, кто тут издевается. :) Всё, перечисленное Вами — косяки на стороне пользователя и клиентских приложений. Ну, ещё можно кошку высушить в микроволновке, а потом подать в суд на производителя за то, что она кошка сломалась. GnuPG позволяет указывать ключи по полным отпечаткам, а если используете короткий keyID, да ещё без подписей, то просто дразните судьбу.


Эти файлы лежат в homedir, а связки не обязаны находиться там же. Всё это настраиваемо как через gpg.conf, так и непосредственно в конфиге сервера: можно указать, с какими опциями ему вызывать gpg, независимо даже от того, что содержится в gpg.conf.


Разница в том, что при вызове из консоли есть тот самый TTY, из которого можно ждать ввод, а при запуске процесса — нет. Но, как уже сказал, причина может быть в моих кривых руках.
Гость (18/01/2015 00:46)   

Нет, дело не в этом, просто смысл не уловил сразу. Замечение принято.


Ну найдите нам другие приложения. Как вашему tkabber'у ключ задать? Можно по полному отпечатку? Мой клиент требует 16-ричный KeyID, насчёт полного отпечатка я не в курсе.

И, в конце концов, весь смысл этого проекта — костыль для латания дыр на стороне пользователя и его приложений, да. Если дыр нет, можно считать, что ключ никто не похитит.

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


В большинстве клиентских команд указывается 8-значный KeyID. Считается, что отпечаток однажды проверили, а двух ключей с одинаковыми KeyID'ами на связке нет.
— SATtva (18/01/2015 12:08)   

Цель проекта — не дать пользователю вытащить закрытый ключ; это такая смарт-карта "для бедных", если хотите. Подпорки и костыли для UI и программных интерфейсов в клиентском ПО — это настолько out of the scope, насколько вообще возможно.


Разумеется, читать текущую переписку никто ему не запретит, это ведь именно дырявое клиентское ПО или атакующий передаёт gpg данные для шифрования.

Что касается импорта, я выше писал, что с удовольствием бы его запретил, существуй для этого какое-то лаконичное решение. Обучение программы семантике опций gpg таковым явно не является. Более того, оно и недостаточно, учитывая, что ввод может быть чисто бинарным (т.е. в нём может и не быть никаких PRIVATE/PUBLIC KEY BLOCK). Поэтому административное решение с блокированием записи связок представляется мне вполне достаточным и элегантным. Найдёте лучше — милости прошу.
Гость (19/01/2015 00:34)   

Пожалуй, соглашусь.

Хотелось бы понять по поводу вайтлистинга. Его поддержка будет? Чтобы руками можно было задать, какие конкретно команды gpg могут быть выполнены [возможно, вплоть до конкретных KeyID'ов] (а все остальные должны блокироваться).
— SATtva (19/01/2015 09:37)   

Кстати, всё-таки больше, чем смарт-карта за счёт возможности работы в распределённом режиме — сервер может крутиться на любой удалённой системе.


Заложена изначально. Фильтрации keyID нет в виду отсутствия разбора семантики. Хотя добавить фильтрацию параметров, в принципе, возможно, хорошая идея.
Гость (19/01/2015 16:27)   

Я не вижу, чем KeyID'ы (значения опций) принципиально отличаются от собственно опций. Если есть фильтрация по опциям, то там же можно зафиксировать и параметры этих опций.

GPGIndustries:
W[link5]hat Could you Expect from GPGServer? We plan to release on 15th of June! Give us all you would expect from this server! We will do our best to implement it!

15-ое июня 2011-го уже прошло.
— SATtva (19/01/2015 18:51)   

По сути, так и есть (технические детали несколько сложнее). Уже сделал.


Хех. Я обозвал поделие GPGRemote.
Гость (19/01/2015 19:11)   
Тогда уж лучше назвать «GPG Remote» (раздельно), а сам исполнимый файл — как-то типа gpg-remote (по аналогии с gpg-agent, gpg-zip и т.д.).
— SATtva (19/01/2015 19:16)   
Принято.
Гость (19/01/2015 19:34)   
Remote — плохое слово, в IT оно обычно соседствует с такими словами как exploit и exploitable. Но, ладно, это уже придирки. Если будет дыра, будут стебать в виде «gpg remote is indeed so remote!» :-)
— SATtva (19/01/2015 19:46)   
Значит, в очередной раз подтвердим "как корабль назовёте..." :)

Код готов, документация плюс-минус тоже. Хочу ещё немного потестить, дописать юниттестов. Выложу для публичного тестирования через пару дней.
Гость (19/01/2015 20:03)   
Спасибо. На github'е будет или тут?
— SATtva (19/01/2015 20:09)   
Здесь. Финальную версию скорее всего выложу на bitbucket.
— SATtva (23/01/2015 11:29)   
Бета-версия вот:

file:gpgremote-0.9b1.tar.bz2[link6]
file:gpgremote-0.9b1.tar.bz2.sig[link7]
— SATtva (23/01/2015 12:53, исправлен 23/01/2015 13:20)   

Тут же обнаружил небольшую ошибку: в конструкциях типа "--output -" одиночный дефис воспринимается как опция. Уже исправлено (пока только у меня). Ох уж эти спэшл-кейсы. :\

Гость (23/01/2015 14:30)   

Впечатляет. И не подумал бы, что в, казалось бы, такой простой задаче требуется так много кода.

Английский в README:

for various of reasons

→ variety of reasons? Я сам не знаю.

Finally, gpg is called, and its output (comprised of that includes STDERR, STDOUT, exit code, as well as newly generates files) is sent back to client.

Я бы так сделал.

Make sure you have Python 3.2.x or later installed on all systems you intend to use for client and server operation.

Вместо intend лучше plan или want. Это более формально. Intend — это ближе к «намереваться, замышлять», слишком художественный смысл (хотя тоже используется в тех. текстах).

Both client and server modules are self-contained

Не уверен, что это называется self-contained, хотя я понял, что вы хотите сказать. Обычно пишут что-то типа stand-alone.

Running GPG Remote Client as a drop-in replacement for system-wide gpg requires that gpgremote_client.py script to be placed moved to or symlinked from with the file in /usr/bin/gpg

Вот как-то так я бы написал. Оборот to be to там напрашивается сам собой, и, как нас учили, надо писать не "о", а "что". Не описательно, а конкретно.

which can be overridden with

Мне кажется, в этих случаях все пишут overwritten (параметр переписывается новым конфигом, а не "отменяется", да ещё и в юридическом смысле поди).

However, specific path

However лучше всегда ставить в начало. По правилам, после него всегда запятая. Вроде так.

which gpg processes it contextually

Иначе рунглиш.

Please bear in mind that

Слишком нефорамльно и художественно. Техницизмы: remind, recall, take into account, note, notice.

Additional Another potential risk

У "additional" есть слишком "additional" смысл, и если вы не о нём, то лучше сказать another.

This however requires correct

However, this requires... Я не уверен про this vs it, но чаще пишут именно it.

in respect to

А не with respect to?

placeholder

Кажется, нетехническое и неуместное слово — раз, смысл я с первых прочтений не понял — два.

which they may contain sensitive cleartext data

Рунглиш. Which — это наше всё, нельзя им злоупотреблять. Это только мы его в каждое предложение суём по поводу и без.

where S is the package size limit, and T is the threads count.

По-моему, запятая не нужна: "а и b", хотя "а, b, и c". Кажется, так.

the server can only operate with unprotected private keys.

Жаль.

Язык очень хороший (поделитесь с unknown'ом и gegel'ем, им явно не хватает), но много где, на мой вкус, слишком неформальный и гуманитарный. К математическим объектам у вас применяются слова, которые обычно используются для описания вещей.

Надо бы ещё сам код потестить, и можно ждать бету гамму с дельтой. :)
Гость (23/01/2015 14:32)   

+remember
— SATtva (23/01/2015 15:39)   

Непосредственно логики там не так уж много. Если выкинуть комментарии (aka docstrings), дублированный кусок кода сетевого интерфейса и весь обвес с логами и обработкой ошибок, объём сократится раза в два.


Правильно, как есть.


Разница между "состоящий из" и "включающий" в том, что второе — implicitly открытый перечень ("включает это и, возможно, что-то ещё"). Первоначально написал тут именно "includes", но позднее при правке заменил ради большей однозначности.


Тут речь о том, что не имеют зависимостей в виде внешних модулей (аналог статической линковки в C/C++), это общепринятый термин.


Тут неточность в моей формулировке привела к тому, что Вы неправильно поняли весь пассаж — "overridden" относится не к конфигу, а к пути, где программа будет его искать (т.е. как в предыдущем абзаце). Исправил.


Это одно и то же. Например.[link8]


В данном конкретном случае употребление оправдано.


Обращал внимание, что англоязычные ставит запятую даже в перечислениях из двух элементов. Вероятно, это распространённая ошибка — глянул сейчас правила, и, формально, там то же, что и в русском: серия из трёх и более либо сложное предложение.

С остальным согласен, спасибо за замечания.


Это относится к случаю, когда клиент и сервер находятся на разных машинах. В противном случае, если настроен gpg-agent с графическим pinentry, вылетит птичка окошко для ввода пароля. А по поводу удалённого вызова см. один из пунктов TODO. У gpg-agent вроде бы есть какой-то IPC-интерфейс, но в деталях не разбирался. Меня больше смущает тот факт, что парольная фраза пойдёт через питонокод, а у него безопасность данных в памяти отсутствует как класс (как у всех интерпретируемых языков, собственно), т.е. "забыть" пароль не удастся, он там и будет торчать в памяти сервера, пока ОС не сольёт всё в своп. Так что пока не уверен, стоит ли вообще связываться с передачей паролей.
— SATtva (23/01/2015 19:26)   
Запостил в репозиторий: https://bitbucket.org/sattva/gpg-remote
Гость (24/01/2015 00:17)   

Имхо, как раз includes — включение без конкретизации, всё ли это. В иных случаях используется formed by или consists of. Правда, опять же, это больше для вещей (как и comprize), а не объектов. Для последних используется что-то уместное для конкретного случая (to be или др. глагол). Наверно, я бы в вашем случае написал consists of, хотя не исключено, что есть более удачные варианты.
— SATtva (24/01/2015 11:09)   

Так я ровно об этом и пишу. :) Касаемо замечания относительно comprized, это уже по большей части вкусовщина, чем конструктив. Доки уже совершенно понятны, и они меня на самом деле меньше всего волнуют — куча функций совсем не покрыта тестами.
Гость (25/01/2015 01:34)   

Да, упустил я. :) В общем, больше пока замечаний нет.
— SATtva (27/01/2015 17:56)   
Сделал специальную страничку[link9], дальнейшее обсуждение можно вести там. Также зафиксировал вторую бету с несколькими незначительными изменениями.

Ссылки
[link1] https://www.pgpru.com/comment41042

[link2] https://www.pgpru.com/comment85024

[link3] https://www.pgpru.com/comment86061

[link4] https://www.pgpru.com/comment71148

[link5] http://forum.gsmhosting.com/vbb/f675/what-could-you-expect-gpgserver-1270346/

[link6] https://www.pgpru.com/forum/kriptografija/openpgpcryptokey/files?get=gpgremote-0.9b1.tar.bz2

[link7] https://www.pgpru.com/forum/kriptografija/openpgpcryptokey/files?get=gpgremote-0.9b1.tar.bz2.sig

[link8] http://idioms.thefreedictionary.com/with%20respect%20to

[link9] https://www.pgpru.com/razrabotki/gpgremote