В 1991г в США Филом Циммерманом были опубликованы исходные текстов программы PGP (Pretty Good Privacy – замечательная приватность). Эта программа выводила на гражданский рынок самые современные на тот момент алгоритмы шифрования с ассиметричными ключами RSA, ВSA и ElGamal (расширение Diffi-Helman). На тот момент в США действовали довольно жёсткие законы в отношении экспорта криптографических программ и Фил в течении трёх лет подвергался судебному преследованию, но был оправдан, поскольку удалось убедить судей, что исходные тексты программы, это литературное произведение, попадающее под первую поправку к конституции США.
Права на программу PGP несколько раз переходили от одной компании к другой. С начала 2000-х и по настоящее время программой владеет компания Symantec, которая закрыла доступ к исходным кодам программы.
В 1997 году на основе реализации PGP v.5 была разработана группа стандартов OpenPGP. Стандарты описывает требования к алгоритмам шифрования, форматы хранения данных, взаимодействие с почтовыми программами и т.п.
В 1999 в рамках проекта GNU и при финансировании правительства Германии была разработана свободно распространяемая программа шифрования совместимая с OpenPGP – GnuPG версии 1, а в 2006 году - GnuPG версии 2.
В 2014 году вышла версия GnuPG 2.1.0, которая значительно отличается от предшественников (включая версии 2.0.x) по формату файлов. Миграция с 2.0.x на 2.1.x происходит автоматически, обратное преобразование потребует ручного выполнения экспорта-импорта ключей. Кроме того, начиная с версии 2.1.0 прекращена поддержка исторического формата ключей PGP-2. Тем не менее, GnuPG всех версий совместима с классической программой PGP версии 5 и старше.
В 2017 вышла версия GnuPG 2.2.0, которая не сильно отличается о 2.1.x. До этой версии команда gpg
означала GnuPG 1.x, а для новых версий GnuPG использовалась команда gpg2
. Начиная с версии 2.2 во всех новых дистрибутивах команда gpg
означает GnuPG 2.2 и старше.
Реализации GnuPG существуют для всех популярных ОС. Реализация GnuPG для Linux включена во все дистрибутивы, реализация GnuPG для Windows - Gpg4win, для Android OpenKeychain.
Документацию и последние версии GnuPG можно получить на http://www.gnupg.org. На русском языке подробную информацию можно получить на сайте http://www.pgpru.com.
Для интеграции PGP в почтовые программы можно воспользоваться следующими продуктами: Linux, Windows, OS X - плагин для почтового клиента Thunderbird - Enigmail; Android - K9 mail + OpenKeychain; Серверное web-приложение Roundcubemail (ver.>1.2); Gmail и т.п. - расширение для браузеров Mailvelop.
Если не вдаваться в подробности (которые очень важны, если криптография используется по назначению, а не в качестве игрушки), то процесс работы с GnuPG делится на следующие этапы:
На данной странице описаны базовые команды GnuPG 2.x.
Обобщённый формат вызова GnuPG:
gpg --опция ... --команда [имя ключа]
Команды указывают желаемое действие, а опции - параметры для выполнения этого действия. Опции указываются до команд. Некоторые команды переводя gpg в интерактивный режим.
В качестве имени ключа может использоваться цифровой отпечаток (fingerprint), идентификатор ключа (key ID) или e-mail владельца. В дальнейшем имя ключа будет заменяться на mykey .
gpg --gen-key
В GnuPG версии 2.1.x* и старше --gen-key предлагает ввести только имя, e-mail и пароль для секретного ключа, подставляя остальные параметры по умолчанию. Для полного диалога в этих версиях необходимо использовать команду --full-gen-key, возможно с опцией --expert, которая добавляет расширенный выбор алгоритмов шифрования.
В результате выполнения команды --gen-key генерируется два ключа: мастер-ключ, он же ключ подписи, и ключ шифрования. Оба ключа используют алгоритм шифрования rsa2048 и имеют срок жизни два года. Кроме того автоматически формируется сертификат отзыва.
В процессе создания ключа у для него будет создан длинный шестнадцатеричный цифровой отпечаток (fingerprint) который может использоваться для выбора ключа при последующих операциях.
Немного о вводимых параметрах:
Идентификатор владельца ключа (UID) в OpenPGP имеет формат "Полное имя (комментарий) <адрес e-mail>". Идентификатор связывает ключ с определенным человеком. Поскольку OpenPGP в значительной мере ориентирован на использование совместно электронной почтой, то основным идентификатором является e-mail, а полное имя, это лишь вспомогательный элемент.
Пароль для шифрования секретного ключа должен быть достаточно сложным для взлома. Утеря секретного ключа сводит на нет всю систему шифровальной защиты и потому ключ хранится на диске в зашифрованном виде. В идеальном случае ключ должен храниться на съемном носителе (флешке) в физически защищенном месте. Если злоумышленник получит доступ к файлу секретного ключа, то пароль к нему будет последней линией обороны.
Если ключ сертификат отзыва мастер-ключа (revoсation certificate) не был создан во время генерации, то его следует создать, используя команду --gen-revoke. Если секретный ключ будет похищен или утерян, то этот сертификат может быть разослан для уведомления о том, что открытый ключ нельзя больше использовать.
gpg --output revoke.asc --gen-revoke mykey
Сертификат отзыва сохраняется в текстовой кодировке.
К одному ключу можно добавить несколько пользовательских идентификаторов (UID), например, личный и рабочий адреса электронной почты. Операция выполняется в диалоговом режиме.
gpg --edit-key mykey
В диалоговом режиме ввести команду adduid
gpg> adduid
Real Name: My work email
E-mail: my@example.com
После создания нового идентификатора следует отметить степень доверия к нему и назначить, какой UID будет основным. Команда uid
gpg> uid <number>
gpg> trust
(5 = ultimate trust)
gpg> uid <number>
gpg> primary
gpg> save
Удаление идентификатора
gpg> uid <number>
gpg> deluid
Отзыв идентификатора
gpg> uid <number>
gpg> revuid
Перед тем как послать кому-либо открытый ключ необходимо экспортировать его командой --export:
gpg --armor --output alice.gpg --export my@example.com
Опция --armor указывает, что ключ будет сохранён в формате ASCII.
После обмена ключами открытый ключ партнера может быть добавлен к связке открытых ключей при помощи команды --import:
gpg --import blake.asc
gpg --list-keys
/home/alice/.gnupg/pubring.gpg
pub 1024R/B115BDB6 2002–05–01 Alice (test key) <alice@wonderland.uk>
pub 1024R/01A1FE63 2002–05–01 Blake (dumb) <blake@anywhere.ru>
sub 1024R/526C7F7F 2002–05–01 [expires: 2003–05–01]
Для того, чтобы проверить достоверность ключа используется цифровой отпечаток (fingerprint) ключа. После проверки ключ заверяется подписью, для подтверждения того, что он достоверен. Ожидаемый отпечаток ключа передается через надёжный канал связи, например зачитывается владельцем по телефону.
Отпечаток ключа можно просмотреть командой --fingerprint.
gpg --fingerprint alice@wonderland.uk
pub 1024R/B115BDB6 2002–05–01 Alice (test key) <alice@wonderland.uk>
Key fingerprint = DE49 CDEF 12A3 8B7B 272B A572 C73A 9987 B115 BDB6
Или
gpg --fingerprint
/home/test/.gnupg/pubring.gpg
pub 1024R/B115BDB6 2002–05–01 Alice (test key) <alice@wonderland.uk>
Key fingerprint = DE49 CDEF 12A3 8B7B 272B A572 C73A 9987 B115 BDB6
pub 1024R/01A1FE63 2002–05–01 Blake (dumb) <blake@anywhere.ru>
Key fingerprint = 80B8 1955 7D68 FE4F D882 DAD1 D85C 124A 01A1 FE63
sub 1024R/526C7F7F 2002–05–01 [expires: 2003–05–01]
Для подписи ключа необходимо перейти в режим редактирования ключа при помощи команды --edit-key:
gpg --edit-key blake@anywhere.ru
В диалоговом режиме ввести команду sign:
gpg> sign
Подтвердить желание подписать ключ и ввести пароль секретного ключа
Указать, с какой степенью достоверности проверен ключ
gpg> trust
Укажите, насколько Вы доверяете данному пользователю в вопросах проверки
достоверности ключей других пользователей (проверяет паспорт,
сверяет отпечатки ключей из разных источников и т.п.)
1 = Не знаю или не буду отвечать
2 = НЕ доверяю
3 = Доверяю ограниченно
4 = Полностью доверяю
5 = Абсолютно доверяю
Выход из режима редактирования и сохранение изменений
gpg> quit
Для шифрования документа используется команда --encrypt. Для шифрования необходимо иметь открытые ключи предполагаемых получателей. Программа ожидает в качестве параметра имя шифруемого документа или, в случае его отсутствия, шифрует стандартный ввод. Зашифрованный результат помещается в стандартный вывод, если не указана опция --output. Для повышения защиты перед шифрованием документ дополнительно сжимается.
gpg --output message.gpg --encrypt --recipient blake@anywhere.ru message.txt
Опция --recipient может повторяться несколько раз для каждого из предполагаемых получателей и имеет в качестве аргумента идентификатор открытого ключа, которым должен быть зашифрован документ.
При шифровании документа создаётся одноразовый случайный ключ для симметричного шифрования документа, а в зашифрованный документ добавляются несколько копий этого одноразового ключа, каждая из которых зашифрована публичным ключом одного из получателей.
Для расшифровки сообщения используется команда --decrypt. Зашифрованный документ может быть расшифрован только тем, чей секретный ключ соответствует одному из указанных открытых ключей. В частности, отправитель не можете расшифровать зашифрованный им документ, если он не включил свой открытый ключ в список получателей.
gpg --output message.txt --decrypt message.gpg
Для доступа к секретному ключу необходимо ввести пароль
You need a passphrase to unlock the secret key for
user: «Blake (dumb) <blake@anywhere.ru>"
1024-bit RSA key, ID 526C7F7F, created 2002–05–01 (main key ID 01A1FE63)
Enter passphrase:
Документы можно шифровать и без открытого ключа. Вместо этого используется симметричный алгоритм для шифрования документа. Ключ, используемый при шифровании, образуется из ключевой фразы. Для большей безопасности эта ключевая фраза не должна совпадать с той, которая используется для защиты секретного ключа. Симметричный шифр применим, когда есть возможность обменяться ключевой фразой. Для использования симметричного шифра применяется команда --symmetric.
gpg --output message.gpg --symmetric message.txt
Enter passphrase:
Цифровая подпись удостоверяет создателя и дату создания документа. Если документ будет каким-либо образом изменен, то проверка цифровой подписи будет неудачной. При подписи документа используется закрытый ключ подписывающего, а проверяется подпись с использованием его открытого ключа.
Для подписи документов используется команда --sign.
gpg --output file.sig --sign file.bin
You need a passphrase to unlock the secret key for
user: «Alice (test key) <alice@wonderland.uk>"
1024-bit RSA key, ID B115BDB6, created 2002–05–01
Enter passphrase:
Перед подписью документ сжимается. Подписанный документ выводится в двоичном формате.
У подписанный документ можно либо просто проверить подпись, либо проверить подпись и восстановить исходный документ. Для проверки подписи используется команда --verify. Для проверки подписи и извлечения документа используется команда --decrypt.
gpg --output file.bin --decrypt file.sig
gpg: Signature made Sat May 4 19:04:21 2002 MSD using RSA key ID B115BDB6
gpg: Good signature from «Alice (test key) <alice@wonderland.uk>"
Обычно цифровые подписи применяются для отправки электронной почты. При этом нежелательно сжимать подписываемые документы. Команда --clearsign добавляет к документу цифровую подпись в формате ASCII, не изменяя при этом сам документ.
gpg --output doc.asc --clearsign doc.txt
Можно получить подпись, хранящуюся отдельно от документа
gpg --output doc.sig --detach-sign doc.txt
Для проверки подписи необходимы и подпись, и сам документ. Для проверки используется команда --verify.
gpg --verify doc.sig doc.txt
gpg: Signature made Sat May 4 19:34:08 2002 MSD using RSA key ID B115BDB6
gpg: Good signature from «Alice (test key) <alice@wonderland.uk>"
В криптографии существует несколько моделей доверительных отношений:
В модели непосредственного доверия мы самостоятельно проверяем ключи партнёра не полагаясь ни на кого больше. Такая модель доверия используется в SSH, где публичные ключи сервера и клиента представляет из себя набор параметров шифрования и не содержит никакой удостоверяющей информации. Проверка ключа производится самостоятельно путём сличения его цифрового отпечатка с имеющимся в наличии (закэшированном в предыдущем сеансе или размещённого в специальном файле).
В модели иерархического доверия существуют некие изначально доверенные корневые сертификаты, принадлежащие уважаемому центру аутентификации (Central authority, CA). Данный центр подписывает сертификаты доверенных удостоверяющих центров, которые, в свою очередь, подписывают сертификаты серверов и пользователей. Каждый сертификат хранит цепочку подписей, ведущую к корневым сертификатам и позволяет, таким образом, отследить на персональную ответственность за выдачу сертификата. Корневые сертификаты распространяются некоторым надёжным способом, например, как часть дистрибутива ОС или браузера. Эта модель используется в SSL.
Модель сети доверия объединяет обе предыдущие модели. В сети доверия каждый самостоятельно проверяет достоверность чужих сертификатов, но, после проверки, может выступить в качестве удостоверяющего центра для других участников сети. В отличие от централизованной модели здесь никогда не может быть стопроцентной уверенности в подлинности сертификата, но наличие многих участников, независимо подтверждающих достоверность какого-либо сертификата, оказывается вполне достаточным для большинства практических задач.
Для того, чтобы избежать MitM атаки (Man in the middle - расшифровка сообщений в канале передачи) необходимо, удостовериться в том, что публичный ключ партнёра не был подменён. Для достижения этой цели в сертификате ключа OpenPGP хранятся подписи от других участников сети доверия, подтверждающие достоверность хозяина ключа. Хочу обратить внимание, что подписывается не сам ключ, а идентификатор пользователя, привязанный к данному ключу. Так, вы можете быть уверены, что человек действительно использует один из e-mailов, привязанных к ключу, и ничего не знать про другие его e-mailы.
Уровень достоверности того, что сертификат ключа действительно выпущен своим хозяином, высчитывается по количеству подписей и уровня доверия к этим подписям. Получив от нового партнёра по переписке публичный ключ, подписанный людьми, чьи ключи помечены как доверенные, мы повышаем свою уверенность в достоверности полученного ключа.
В оригинальном PGP существовало три степени доверия к подписывающим ключ и три уровня достоверности сертификата.
Уровни доверия:
Уровни достоверности:
В версии GnuPG 2.x появился уровень "Абсолютное доверие" для своих собственных сертификатов.
Чтобы сертификат считался подлинным требуется собственноручная подпись сертификата, или хотя бы одна подпись от полностью доверенного владельца ключа, или две подписи от частично доверенных владельцев ключей.
На самом нижнем уровне этой сети находится личный ключ и личная связка сертификатов. Личный ключ считается абсолютно достоверным а его хозяин (я) абсолютно доверенным. Добавляя чей-либо публичный ключ в связку можно подписать сертификат ключа своим личным ключом, что даст ему статус подлинного сертификата. При этом уровень доверия к владельцу можно установить по своему желанию.
Возможно, что вам не известен уровень доверия к ключам, использованным для подписи ключа партнёра. Тогда вам придётся искать цепочку ключей от известных доверенных ключей к проверяемому. Кроме того, существует некоторая вероятность, что подписавшие ключ люди сговорились (принадлежат к одной тайной организации) и совместно выпустили фальшивый ключ. Поэтому, чем больше людей в мире участвует в подписании ключей, тем проще найти подтверждающую цепочку и тем меньше вероятность сговора. Процедура взаимного подписания ключей при личных контактах, или подписания при абсолютной уверенности в достоверности ключей (например путём сличения цифровых отпечатков по телефону) и создаёт сеть доверия пользователей OpenPGP.
Пример локальной сети доверия можно посмотреть на странице ключей команды разработчиков Arch Linux.
Редактирование уровня доверия к хозяину ключа:
$> gpg --edit-key DA3CE9CE6DF2C45843AB2392D5560606D3C9EE9B
...
gpg> trust
sec rsa2048/D5560606D3C9EE9B
создан: 2020-04-17 годен до: 2022-04-17 назначение: SC
доверие: абсолютное достоверность: абсолютное
ssb rsa2048/C6FF5CA708A972CD
создан: 2020-04-17 годен до: 2022-04-17 назначение: E
[ абсолютно ] (1). Jon Dow <user@example.com>
Укажите, насколько Вы доверяете данному пользователю в вопросах проверки
достоверности ключей других пользователей (проверяет паспорт,
сверяет отпечатки ключей из разных источников и т.п.)
1 = Не знаю или не буду отвечать
2 = НЕ доверяю
3 = Доверяю ограниченно
4 = Полностью доверяю
5 = Абсолютно доверяю
Выдержка из GnuPG FAQ Ru
gpg --edit-key [ID его сертификата] sign
gpg --armor --output signed_cert.asc --export [ID его сертификата]
Следуя этой процедуре, вы сначала убеждаетесь, что говорите с нужным человеком. Сравнивая отпечаток сертификата с тем, который вам сообщили, вы убеждаетесь, что получили нужный сертификат. Еще одна проверка делается, чтобы убедиться, что данный вам адрес перечислен в сертификате. Как только это сделано, вы получаете уверенность, что связали сертификат с реальным человеком. Что и подтверждаете всему миру, подписав сертификат и вернув свежеподписанный сертификат владельцу.
Термин "сертификат" в OpenPGP чаще всего используется в словосочетании "сертификат отзыва", а для структуры данных, связанной с ключом используется просто слово "ключ". На этой странице термин "сертификат" используется, для того, чтобы отличать ключи, как параметры алгоритма шифрования, от ключей, как структур данных.
Структура данных сертификата ключа в OpenPGP позволяет хранить в нём различные дополнительные поля. Подключи - это ключи, которые хранятся в сертификате другого ключа, который называют первичным или мастер-ключом.
Подключи помечаются флагами, которые определяют функциональное назначение подключа. Флаги имеют внутреннее числовое представление, а в информационных утилитах GnuPG помечаются буквами.
0x01 “C” Key Certification
0x02 “S” Sign Data
0x04 “E” Encrypt Communications
0x08 “E” Encrypt Storage
0x20 “A” Authentication
Мастер-ключ автоматически помечается флагами ключа подписи и ключа выпуска сертификатов (CS), поскольку он используется для подписывания подключей и для создания сертификатов отзыва. Отличие ключа шифрования от ключа подписи в том, что ключ подписи действует в будущем. Если его украдут, то злоумышленники смогут в будущем подписывать документы от вашего имени. Поэтому ключ подписи должен иметь ограниченный срок действия и (в случае компрометации) должен быть отозван до окончания срока, чтобы предупредить его использование злоумышленниками. Ключ шифрования действует в прошлом. Его компрометация ведёт к тому, что злоумышленники смогут расшифровать переписку, которая велась с его использованием и никакие отзывы здесь не помогут.
В GnuPG версии 2.1 и старше команда --gen-key создаёт мастер-ключ с функцией подписи и дополнительный подключ с функцией шифрования.
При создании нового подключа задаётся вопрос о его назначении:
$> gpg --edit-key jd@example.com
...
gpg> addkey
Выберите тип ключа:
(3) DSA (только для подписи)
(4) RSA (только для подписи)
(5) Elgamal (только для шифрования)
(6) RSA (только для шифрования)
(14) Existing key from card
Ваш выбор?
Для создания ключа аутентификации необходимо запускать gpg с опцией --expert
Как и во всех системах с асимметричным шифрованием, каждый ключ в OpenPGP представлен парой из публичного и приватного ключа. Публичный используется для шифрования и проверки подписи, а приватный - для подписи и дешифровки.
Для идентификации ключей используется два типа идентификации:
Идентификатор пользователя имеет формат: "Полное имя <адрес e-mail>". Этот идентификатор связывает ключ с определенным человеком. Очевидно, что человек, создающий много ключей, скорее всего, будет использовать для них одинаковые UIDы. К одному ключу можно привязать несколько идентификаторов пользователя, например UIDы для различных почтовых ящиков. Поиск ключа можно вести по полному тексту UID, по e-mail, по полному имени или по его подстроке.
Отпечаток ключа - это хэш SHA-1 длиной 160 бит, вычисляемый на основе открытого ключа и метки времени создания ключа. Для ввода/вывода отпечатка в интерфейсе пользователя используется шестнадцатеричная запись. Длина отпечатка - 40 шестнадцатеричных цифр, которые для удобства разбивают на 10 групп по 4 цифры.
$> gpg --fingerprint -k
...
-----------------------
pub rsa2048 2020-04-17 [SC] [ годен до: 2022-04-17]
DA3C E9CE 6DF2 C458 43AB 2392 D556 0606 D3C9 EE9B
uid [ абсолютно ] John Dow <jd@example.com>
sub rsa2048 2020-04-17 [E] [ годен до: 2022-04-17]
В некоторых ситуациях (при использовании агента) используется ещё один идентификатор ключа - keygrip, который вычисляется как хэш публичного ключа без добавления времени создания.
$> gpg --with-keygrip -k
...
pub rsa2048 2020-04-17 [SC] [ годен до: 2022-04-17]
DA3CE9CE6DF2C45843AB2392D5560606D3C9EE9B
Keygrip = 5D3F2A0BA1DCC59210761397A5CEC5E3393FB111
uid [ абсолютно ] John Dow <jd@example.com>
sub rsa2048 2020-04-17 [E] [ годен до: 2022-04-17]
Keygrip = 0AF602B0376E373F4158E230D0E5E3E9F32F4619
Для экономии времени на ввод идентификатора (или его диктовку по телефону) могут использоваться младшие байты цифрового отпечатка. 16 последних шестнадцатеричных цифр отпечатка называются длинным идентификатором (long ID), а последние 8 символов - коротким идентификатором (short ID). Использование длинного и короткого идентификатора считается плохой практикой, поскольку для них легко сгенерировать коллизии - т.е. различные ключи с совпадающими укороченными ID (но с несовпадающими отпечатками).
В некоторых случаях в начале идентификатора нужно добавлять символы 0x, чтобы подчеркнуть, что это число в шестнадцатеричном виде.
Для того, чтобы не пересчитывать символы руками, команда просмотра публичных ключей --list-keys (-k) позволяет указать опцию --keyid-format, которая может принимать значения 0xLONG, LONG, 0xSHORT, SHORT.
$> gpg --keyid-format 0xSHORT --list-keys
/home/user/.gpg/pubring.kbx
-----------------------
pub rsa2048/0xD3C9EE9B 2020-04-17 [SC] [ годен до: 2022-04-17]
DA3CE9CE6DF2C45843AB2392D5560606D3C9EE9B
uid [ абсолютно ] John Dow <jd@example.com>
sub rsa2048/0x08A972CD 2020-04-17 [E] [ годен до: 2022-04-17]
Личный мастер-ключ должен храниться в очень безопасном месте, желательно на внешнем носителе в физически защищенном месте. Однако использовать такой ключ крайне неудобно: каждый раз, когда вам нужно что-то подписать придётся извлекать ключ из хранилища и использовать его на компьютере с надёжной антивирусной защитой, чтобы избежать перехвата расшифрованного ключа в процессе подписи.
Альтернативой является создание подключей для текущей работы. С помощью мастер-ключа подключам можно назначать небольшой срок жизни, чтобы уменьшить ущерб при их похищении. Так же с помощью мастер-ключа можно отзывать скомпрометированные ключи.
Мастер-ключ извлекается из хранилища и используется в следующих случаях:
Можно использовать различные стратегии устаревания:
Ошибка в GnuPG 2.x: Can’t connect to the agent: Invalid value passed to IPC возникает при выполнении команды:
gpg –-homedir . –-gen-key
Причина: Вся работа с секретными ключами идёт в GnuPG 2.x идёт через gpg-agent, который запускается в фоне при первой необходимости. В данном случае gpg-agent уже запущен и создал сокет в стандартном каталоге * ~/.gpg*
Исправление:
pkill -KILL gpg-agent
gpg-agent --homedir="$(pwd)" --daemon
gpg –-homedir --homedir="$(pwd)" –-gen-key
В 1988 году Международный союз электросвязи (International Telecommunication Union - ITU) опубликовал рекомендации по методам аутенификации в протоколе доступа к службе каталогов (Direcrotry access protocol - DAP). Все рекомендации союза по компьютерным сетям (реализация модели ISO/OSI) маркировались буквой "X" и номером. Серия посвященная службе каталогов получила номера с X.500 и далее. Система аутенификации на основе публичных ключей и сертификатов получила название X.509. В дальнейшем, часть рекомендаций X.500 была реализована в протоколе LDAP, а фреймворк предложенный в X.509 была использована в вебе для реализации протокола SSL и связанной с ним иерархией отношений доверия (RFC 5280).
В частности, X.509 ввёл понятия:
Для реализации стандарта X.509 и связанных с ним стандартов (алгоритмы шифрования, форматы хранения даннных и т.п.) была разработана библиотека OpenSSL, которая поставляется с утилитой командной строки openssl
, и позволяет выполнять все основные криптографические операции. Библиотека Openssl реализована для всех основных ОС, в том числе Linux, Windows, Mac OS, Android и т.д.
Для корректной работы многих сервисов в современном интернете требуется наличие сертификатов. В качестве примера можно привести HTTPS, SMTP поверх TLS, OpenVPN. В зависимости от сферы применения к сертификатам предъявляются разные требования:
Веб сервер с поддержкой SSL (HTTPS). Необходим серверный сертификат подписанный официальным удостоверяющим центром, сертификат которого есть в поставке популярных браузеров.
Почтовый сервер с поддержкой SSL (SMTP поверх TLS, POP3S, IMAPS). Для SMTP обычно достаточно самоподписанного серверного сертификата. Для POP3S, IMAPS желательно иметь официальный сертификат, поскольку почтовые клиенты (например Thunderbird) выдают предупреждения о неизвестных или некорректных сертификатах.
С OpenVPN поставляется собственный удостоверяющий центр, который позволяет создавать сертификаты сервера и клиента. Сертификат этого центра генерируется локально и добавляется в файл конфигурации клиента и сервера.
Проект LetsEncrypt направлен на массовое внедрение HTTPS в интернете. Он предоставляет бесплатный удостоверяющий центр и наборы скриптов (для разных ОС разные), которые автоматически генерируют пару ключей, создают запрос на выпуск сертификата, отправляют его в удостоверяющий центр LetsEncrypt, а затем автоматически добавляют полученный сертификат в настройки популярных веб-серверов (Apache,Nginx, IIS).
Для почтового сервера достаточно прописать путь к файлу сертификата LetsEncrypt и использовать его совместно с веб-сервером.
Вместе с OpenVPN поставляется набор скриптов easyrsa
(есть под Linux и Windows), которые вызывают openssl для выполнения основных манипуляций с сертификатами. В набор скриптов входят:
Версии с добавлением -pass потребуют ввода пароля для шифрования приватного ключа.
В файле openssl.cnf
хранятся различные параметры openssl. Многие из них ссылаются переменные окружения, поэтому реальные настройки находятся в файле vars.sh
(vars.bat
).
vars.sh (фрагмент)
export KEY_SIZE=1024
export CA_EXPIRE=3650
export KEY_EXPIRE=3650
# Атрибуты сертификата
# могут быть изменены в диалоговом режиме
# при создании сертификата
export KEY_COUNTRY="RU"
export KEY_PROVINCE="EKB"
export KEY_CITY="Ekaterinburg"
export KEY_ORG="IMM"
export KEY_EMAIL=""
Внутри скриптов EasyRSA находятся вызовы openssl. Следует помнить, что часть параметров, такие как тип и размер ключа, ключ CA и т.п. находятся в файлt openssl.cnf.
Создание ключа CA без сертификата
#запрос на сертификат сроком на 10 лет
openssl req -days 3650 -nodes -new -x509 -keyout ca.key -out ca.csr -config openssl.cnf
Создание пары ключ-сертификат клиента
#запрос на сертификат сроком на 10 лет
openssl req -days 3650 -nodes -new -keyout client.key -out client.csr -config openssl.cnf
#подпись сертификата ключом CA
openssl ca -days 3650 -out client.crt -in client.csr -config openssl.cnf
то же для сервера
#запрос на сертификат сроком на 10 лет
openssl req -days 3650 -nodes -new -keyout srv.key -out srv.csr -config openssl.cnf
#подпись сертификата ключом CA
openssl ca -days 3650 -extensions server -in srv.csr -out srv.crt -config openssl.cnf
Экспорт в формат PKCS#12
#запрос на сертификат сроком на 10 лет
openssl req -days 3650 -nodes -new -keyout client.key -out client.csr -config openssl.cnf
#подпись сертификата ключом CA
openssl ca -days 3650 -in client.csr -out client.crt -config openssl.cnf
# конвертация пары ключ/сертификат в файл pkcs#12.
openssl pkcs12 -export -inkeyclient.key -in client.crt -certfile ca.crt -out client.p12
Стандарт X.509 предполагает, что все структуры данных, связанные с сертификатами описываются в формате ASN.1. ASN.1 - это архитектурно-независимое представление данных, пригодное для хранения произвольных иерархических структур. На практике, структура ASN.1 кодируется в двоичное представление DER (Distinguished Encoding Rules), описанное в X.690.
Все объектов в ASN.1 имеют уникальные идентификаторы OID (Object Identifier), для которых определены базовые типы данных (числа, строки, коллекции и т.п). OID - это последовательность положительных целых чисел, однозначно идентифицирующая объект. В текстовой записи OID выглядит как десятичные числа, разделяемые точкой - 1.2.345.6.79. Структура OID описывает дерево, корень которого расположен в начале записи. При записи в человекочитаемой форме корневой OID заменяют на некую мнемоническую строку, которую продолжают числовой последовательностью. Например корневой OID ветки, описывающей объекты алгоритма RSA, выглядит так: 1.2.840.113549.1. На специализированном сайте можно выяснить, что это: {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)}. Российский сегмент OID {iso(1) member-body(2) ru(643)} по соглашению с Росстандартом обслуживает ОАО "Инфотекс Интернет Траст". Объекты, связанные с российской криптографией, находятся в ветке 1.2.643.100 и описаны в Приказе ФСБ РФ от 27 декабря 2011 г. N 795 "Об утверждении Требований к форме квалифицированного сертификата ключа проверки электронной подписи".
Для обеспечения уникальности, те или иные OIDы регистрируются некими официальными организациями при координации ISO и ITU. К таким регистрирующим организациям относится IANA, которая выделяет OIDы, необходимые для протоколов сети Интернет (например, LDAP и SNMP). Частная организация может получить стартовый OID, и строить от него поддерево для внутреннего использования. В России регистрацией частных OID занимается ОАО "Инфотекс Интернет Траст".
Просмотр ASN.1 структуры ключа:
openssl asn1parse -in x509-key.pem
Кроме того, серия документов Public-Key Cryptography Standards (PKCS), созданная корпорацией RSA, описывает различные типы сертификатов X.509. Документы имеют порядковую нумерацию, записанную через #.
Основной формат хранения сертификатов X.509 - DER, однако для удобства пересылки по электронной почте его часто дополнительно кодируют в формат PEM (Privacy Enhanced Mail RFC 1421). PEM сам по себе довольно большой стандарт, но из взято только кодирование по алгоритму Base64 и обрамление полученного текста границами:
-----BEGIN label -----
-----END label -----
Для секретных ключей RSA (PKCS#1) используется традиционная форма label, похоже, не описанная в стандартах - RSA PRIVATE KEY.
RFC 7468 описывает форматы label для разных типов ключей и сертификатов
За пределами границ BEGIN и END в файл с сертификатом может быть добавлена человекочитаемая версия данных.
Вывод в человекочитаемом формате. noout - отключение вывода в формате PEM:
openssl x509 -in certificate.cer -noout -text
Конвертация PEM -> DER и наоборот:
openssl x509 -inform pem -in certificate.pem -outform der -out certificate.cer
openssl x509 -inform der -in certificate.cer -outform pem -out certificate.pem
Создание файла PFX:
openssl pkcs12 -export -out certificate.pfx -inkey private.key -in certificate.crt -certfile CA.crt
Извлечение приватного ключа RSA из PKCS#8:
openssl pkcs8 -nocrypt -in pkcs8.pem -out pkcs1.pem
CA Bundle - связка CA - это не особый формат, а просто набор открытых ключей (сертификатов) доверенных центров сертификации в формате PEM, склеенных в один текстовый файл. Формат придуман фирмой Netscape. В Linux CentOS 7 файл /etc/pki/tls/certs/ca-bundle.crt
ставится с пакетом ca-certificates-2018.2.22-70
. Создать CA Bundle из отдельных файлов можно стандартными средствами ОС:
cat *.pem > ca_bundle.crt
Статья про кроссплатформенное средство просмотра сертификатов
Краткая сводка полезных команд (исключая работу с сертификатами)
Генерация случайных данных/паролей
#сгенерировать 12 байт/16 символов в base64
openssl rand -base64 12
Хэш пароля. Первый вариант - классический DES из passwd, второй - MD5 из shadow. Если salt опустить, то будет сгенерирована случайная строка.
openssl passwd -salt 8E MySecret
openssl passwd -1 -salt sXiKzkus MySecret
Криптографический дайджест файла. В Linux можно использовать эквивалентные команды md5sum, sha1sum.
openssl dgst -md5 filename
openssl dgst -sha1 filename
(Де)Кодирование в BASE64
openssl enc -base64 < file.txt
openssl enc -base64 -in file.txt
openssl enc -base64 -in file.txt -out file.txt.enc
#Декодирование
openssl enc -base64 -d < file.txt.enc
Шифрование симметричными шифрами. Пароль можно вводить интерактивно, читать из файла или указывать в командной строке
#список алгоритмов
openssl list-cipher-commands
#шифрование
openssl enc -des -in file.txt -out file.enc
openssl enc -des -in file.txt -out file.enc -pass pass:mySillyPassword
openssl enc -des -in file.txt -out file.enc -pass file:/path/to/secret/password.txt
#шифрование + кодирование в base64
openssl enc -des -a -in file.txt -out file.asc
#дешифрование
openssl enc -d -des -a -in file.asc -out file.txt
SSL/TLS клиент. На STDERR выводится информация о сертификате. После подключения можно вручную вводить команды соответствующего протокола. TLS доступен только для определённых протоколов.
openssl s_client -connect remote.host:443
openssl s_client -connect remote.host:25 -starttls smtp
Сохранение сертификата в файл penssl s_client -connect remote.host:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p'
Веб сервер с корнем в текущем каталоге. По умолчанию слушает порт 4433.
openssl s_server -accept 443 -cert mycert.pem -WWW
И SSH и OpenPGP используют(могут использовать) алгоритм RSA для аутенификации/шифрования. Соответственно, пары открытый/секретный ключ могут использоваться совместно в двух программах, поскольку это просто числа, соответствующие некой формуле. Основное отличие между ключами в OpenPGP и SSH - это инфраструктура и формат хранения.
Не совсем понятно, зачем это надо, поскольку публичные ключи SSH (обычно) распространяются без какой либо верификации, а сами ключи (обычно) не содержат никакой информации о владельце. Соответственно, цифровая подпись, сделанная ключом SSH, не может считаться хоть сколько-нибудь значимой, поскольку невозможно удостовериться в принадлежности открытого ключа автору подписи.
Для конвертации потребуются скрипты от monkeysphere. Процедура импорта описана ЗДЕСЬ.
В gpg-agent встроена поддержка протокола ssh-agent. Соответственно, можно сгенерировать ключи средствами GPG и поместить их в gpg-agent, затем импортировать публичный ключ стандартным образом через ssh-add -L
.
Процедура генерации ключа описана ЗДЕСЬ Примерно то же самое + использование ybkey- ССЫЛКА.
GPG4Win совместим с pagent. ИНСТРУКЦИИ.
Некоторые шифры, используемые в TLS/SSL, со временем признаются ненадёжными и отключаются в стандартной конфигурации OpenSSL. В результате возникают проблемы при взаимодействии со старыми серверами/клиентами. В частности OpenLDAP-клиент в CentOS 8 и старше не может получить доступ по SSL к серверам АД Windows 2012 R2 и младше.
Чтобы включить поддержку старых алгоритмов шифрования в OpenSSL (а также в GnuTLS, OpenSSH, BIND, Jav JDK и т.д.) надо выполнить команду
update-crypto-policies --set LEGACY
update-crypto-policies
— это python-скрипт, который редактирует конфигурационные файлы следующих программ и библиотек:
update-crypto-policies
доступен в CentOS и в Ubuntu.
Генерация ключей SSH и сохранение их в пару файлов (mykey,mykey.pub)
ssh-keygen -t rsa -b 4096 -f mykey
Приватные ключи по умолчанию сохраняются в формате PEM PKCS#1. Ключи, созданные в "новом" формате OpenSSH (опция -o
) не совместимы с другими криптографическими системами.
Формат PEM можно отличить по строкам
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
в файле приватного ключа. В новом формате они заменены на строки
-----BEGIN OPENSSH PRIVATE KEY-----
-----END OPENSSH PRIVATE KEY-----
Публичный ключ так же нужно сконвертировать в формат PEM PKCS#8 (Можно это будет сделать на лету в момент шифрования):
ssh-keygen -f mykey.pub -e -m pkcs8 > mykey.pkcs8.pub
#или
openssl rsa -in mykey -pubout -outform PKCS8 > mykey.pkcs8.pub
Обмениваемся публичными ключами с партнёрами. Чтобы это подчеркнуть, при шифровании я буду использовать чужой публичный ключ anotherkey.pub
.
Генерируем одноразовый сеансовый ключ (32 байта):
openssl rand -base64 32 -out key.bin
Шифруем передаваемые данные симметричным ключом:
openssl enc -aes-256-cbc -salt -in bigdata.dat -out bigdata.dat.enc -pass file:./key.bin
Шифруем сеансовый ключ публичным ключом в формате PKCS#8:
openssl rsautl -encrypt -pubin -inkey anotherkey.pkcs8.pub -in key.bin -out key.bin.enc
# возможна конвертация на лету
openssl rsautl -encrypt -pubin -inkey <(ssh-keygen -e -m PKCS8 -f anotherkey.pub) -in key.bin -out key.bin.enc
Удаляем одноразовый ключ:
rm key.bin
По открытому каналу пересылаем bigdata.dat.enc
и key.bin.enc
.
Расшифровываем секретным ключом сеансовый ключ. В реальной жизни вместо специально сгенерированного ключа mykey
надо будет использовать стандартный ключ ~/.ssh/id_rsa
:
openssl rsautl -decrypt -inkey mykey -in key.bin.enc -out key.bin
Расшифровываем данные:
openssl enc -d -aes-256-cbc -in bigdata.dat.enc -out bigdata.dat -pass file:./key.bin
Для передачи файлов в несколько байт или килобайт можно сразу зашифровать их асимметричным алгоритмом.
# Encrypt openssl rsautl -encrypt -inkey <(ssh-keygen -e -m PKCS8 -f ~/.ssh/id_rsa.pub) -pubin -in small.dat -out small.dat.enc # Decrypt openssl rsautl -decrypt -inkey ~/.ssh/id_rsa -in small.dat.enc -out small.dat