Проверка подписанных коммитов git?

96

В более новых версиях gitможно подписывать отдельные коммиты (в дополнение к тегам) с помощью ключа PGP:

git commit -m "some message" -S

И вы можете показать эти подписи в выводе git logс помощью --show-signatureопции:

$ git log --show-signature
commit 93bd0a7529ef347f8dbca7efde43f7e99ab89515
gpg: Signature made Fri 28 Jun 2013 02:28:41 PM EDT using RSA key ID AC1964A8
gpg: Good signature from "Lars Kellogg-Stedman <lars@seas.harvard.edu>"
Author: Lars Kellogg-Stedman <lars@seas.harvard.edu>
Date:   Fri Jun 28 14:28:41 2013 -0400

    this is a test

Но есть ли способ программно проверить подпись для данного коммита, кроме как путем grepping вывода git log? Я ищу эквивалент фиксации git tag -v- что-то, что предоставит код выхода, указывающий, была ли действительная подпись для данной фиксации.

ларски
источник
1
Я думаю , что должно быть git commit ...и git log .... Насколько я знаю, gpgне добавлены подкоманды, которые передаются gitпрозрачно ... У меня нет репозиториев для тестирования, но git show --show-signature <commitish>работает ли?
twalberg
show_signatureтолько добавляет элементы в вывод (см. github.com/git/git/blob/master/log-tree.c#L370 ).
Emil Sit
Примечание: скоро у вас будет --rawдля git verify-tag/ git verify-commit. Смотрите мой ответ ниже
VonC
1
Примечание: С GIT 2,11 (Q4 2016), git logвводит дополнительные коды состояния E, X, Y, Rдля ERRSIG, EXPSIG, EXPKEYSIG, и REVKEYSIG, таким образом , что пользователь %G?получает больше информации. См. Мой отредактированный ответ ниже
VonC
1
В Git 2.26 (Q1 2020) новая конфигурация gpg.minTrustLevelможет помочь при использовании git verify-tag/ verify -commit. См. Мой отредактированный ответ ниже .
VonC

Ответы:

115

На всякий случай, если кто-то зайдет на эту страницу через поисковую систему, как это сделал я: Новые инструменты стали доступны за два года, прошедшие с момента публикации вопроса: Теперь есть команды git для этой задачи: git verify-commitи git verify-tagих можно использовать для проверки коммитов и теги соответственно.

тарлеб
источник
34

Примечание: до git 2.5 git verify-commitи git verify-tagотображало только удобочитаемое сообщение.
Если вы хотите автоматизировать проверку, git 2.6+ (Q3 2015) добавляет еще один результат.

См. Commit e18443e , commit aeff29d , commit ca194d5 , commit 434060e , commit 8e98e5f , commit a4cc18f , commit d66aeff (21 Jun 2015) by brian m. Карлсон ( bk2204) .
(Объединено Junio ​​C Hamano - gitster- в фиксации ba12cb2 , 3 августа 2015 г.)

verify-tag/ verify-commit: добавить параметр для печати необработанной информации о статусе gpg

verify-tag/ verify-commitпо умолчанию отображает удобочитаемый вывод при стандартной ошибке.
Однако также может быть полезно получить доступ к необработанной информации о статусе gpg, которая машиночитаема, что позволяет автоматизировать реализацию политики подписи .

Добавьте --rawпараметр для verify-tagсоздания информации о статусе gpg при стандартной ошибке вместо удобочитаемого формата.

Плюс:

verify-tagзавершается успешно, если подпись верна, но ключ ненадежен. verify-commitвыходит безуспешно.
Такое расхождение в поведении неожиданно и нежелательно.
Поскольку verify-tagсуществовал ранее, добавьте тест с ошибкой, чтобы проверить поведение общего verify-commitресурса verify-tag.


git 2.9 (июнь 2016 г.) обновите документ git merge :

См. Коммит 05a5869 (13 мая 2016 г.) Келлера Фукса (``) .
Помощник: Junio ​​C Hamano ( gitster) .
(Объединено Junio ​​C Hamano - gitster- в фиксации be6ec17 , 17 мая 2016 г.)

--verify-signatures:
--no-verify-signatures:

Убедитесь, что окончательная фиксация объединяемой боковой ветви подписана действительным ключом, т. Е. Ключом с действительным uid: в модели доверия по умолчанию это означает, что ключ подписи был подписан доверенным ключом.
Если фиксация подсказки боковой ветви не подписана действительным ключом, слияние прерывается
.


Обновление Git 2.10 (3 квартал 2016 г.)

См. Коммит b624a3e (16 августа 2016 г.) Линуса Торвальдса ( torvalds) .
(Объединено Junio ​​C Hamano - gitster- в фиксации 83d9eb0 , 19 августа 2016 г.)

gpg-interface: предпочитать "длинный" ключевой формат вывода при проверке подписей pgp

" git log --show-signature" и другие команды, отображающие статус проверки подписи PGP, теперь показывают более длинный идентификатор ключа, как 32-битный идентификатор ключа в прошлом веке.

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


Git 2.11+ (4 квартал 2016 г.) будет еще точнее.

См. Commit 661a180 (12 октября 2016 г.) Майкла Дж. Грубера ( mjg) .
(Объединено Junio ​​C Hamano - gitster- в коммите 56d268b , 26 октября 2016 г.)

Статус проверки GPG, показанный в " %G?" описателе формата pretty, был недостаточно богат, чтобы различать подпись, сделанную с помощью ключа с истекшим сроком действия, подпись, сделанную отозванным ключом, и т. Д.
Для их выражения были назначены новые выходные письма .

Согласно gpg2doc/DETAILS :

Для каждой подписи только один из кодов GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIGили ERRSIGбудет выбрасываться.

git pretty-formatДокументация теперь включает в себя:

  • ' %G?': показать
    • " G" для хорошей (действительной) подписи,
    • " B" за плохую подпись,
    • " U" для хорошей подписи с неизвестным сроком действия,
    • " X" для хорошей подписи, срок действия которой истек,
    • " Y" для хорошей подписи просроченным ключом,
    • " R" для хорошей подписи отозванным ключом,
    • " E", если подпись не может быть проверена (например, отсутствует ключ) и "N", если подпись отсутствует

Git 2.12 (Q1 2017) " git tag" и " git verify-tag" научились помещать статус проверки GPG в свой " --format=<placeholders>" выходной формат .

См. Commit 4fea72f , commit 02c5433 , commit ff3c8c8 (17 января 2017 г.) Сантьяго Торрес ( SantiagoTorres) .
См. Коммит 07d347c , коммит 2111aa7 , коммит 94240b9 (17 января 2017 г.) Лукаса Пюрингера (``) .
(Объединено Junio ​​C Hamano - gitster- в коммите 237bdd9 , 31 января 2017 г.)

Добавление --formatto git tag -vотключает стандартный вывод проверки GPG и вместо этого печатает отформатированный объект тега.
Это позволяет вызывающим абонентам перекрестно проверять тэг из ссылок / тэгов с тэгом из заголовка объекта тэга после проверки GPG.


Git 2.16 (первый квартал 2018 г.) позволит еще больше автоматизировать проверку подписи фиксации с merge.verifySignaturesпомощью переменной конфигурации.

См. Commit 7f8ca20 , commit ca779e8 (10 декабря 2017 г.) Ханс Джерри Илликайнен (``) .
(Объединено Junio ​​C Hamano - gitster- в коммите 0433d53 , 28 декабря 2017 г.)

merge: добавить параметр конфигурации для verifySignatures

git merge --verify-signatures может использоваться для проверки правильности подписи окончательной фиксации объединяемой ветки, но обременительно указывать это каждый раз.

Добавьте параметр конфигурации, который включает это поведение по умолчанию, которое можно переопределить с помощью --no-verify-signatures.

На git mergeстранице руководства по конфигурации теперь говорится:

merge.verifySignatures:

Если true, это эквивалентно параметру --verify-signaturesкомандной строки.


Git 2.19 (Q3 2018) еще более полезен, так как " git verify-tag" и " git verify-commit" были обучены использовать статус выхода базового " gpg --verify", чтобы сигнализировать о плохой или ненадежной подписи, которую они нашли.

Примечание: с Git 2.19, gpg.formatкоторый может быть установлен в " openpgp" или " x509", и gpg.<format>.programэто используется для указания, какую программу использовать для работы с форматом), чтобы разрешить использование сертификатов x.509 с CMS через " gpgsm" вместо openpgpиспользования " gnupg".

См. Commit 4e5dc9c (09 августа 2018 г.), автор Junio ​​C Hamano ( gitster) .
Помощники: Войтех Мысливец ( VojtechMyslivec) , brian m. Карлсон ( bk2204) и Джефф Кинг ( peff) .
(Объединено Junio ​​C Hamano - gitster- в фиксации 4d34122 , 20 августа 2018 г.)

gpg-interface: распространить статус выхода gpgобратно на вызывающих абонентов

Когда API gpg-interface унифицировал поддержку кодовых путей проверки подписи для подписанных тегов и подписанных коммитов в середине 2015 года примерно на v2.6.0-rc0 ~ 114, мы случайно ослабили проверку подписи GPG.

Перед этим изменением подписанные коммиты проверялись путем поиска " G" подписи ood от GPG, игнорируя статус выхода gpg --verifyпроцесса, в то время как подписанные теги проверялись путем простой передачи статуса выхода "gpg --verify"сквозной".

Унифицированный код, который у нас есть в настоящее время, игнорирует статус выхода " gpg --verify" и возвращает успешную проверку, когда подпись совпадает с ключом, срок действия которого не истек, независимо от уровня доверия к ключу (т.е. в дополнение к " G" мы принимаем " U" доверенные).

Сделайте так, чтобы эти команды сигнализировали об ошибке с их статусом выхода, когда базовая " gpg --verify" (или пользовательская команда, заданная " gpg.program" переменной конфигурации) делает это.
Это существенно меняет их поведение обратно несовместимым способом, чтобы отклонять подписи, которые были сделаны с ненадежными ключами, даже если они правильно проверяют, как это " gpg --verify" ведет себя.

Обратите внимание, что код по-прежнему отменяет нулевой статус выхода, полученный из " gpg" (или gpg.program), если в выходных данных не говорится, что подпись является хорошей или вычисляется правильно, но сделана с ненадежными ключами, чтобы отловить плохо написанную оболочку вокруг " gpg", которую пользователь может дать нам .

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


ключ должен быть доверенным / подписан перед любым шифрованием

На стороне доверия есть прогресс: в
Git 2.26 (Q1 2020) gpg.minTrustLevelбыла введена конфигурационная переменная, которая сообщает различным кодовым путям проверки подписи требуемый минимальный уровень доверия.

См. Коммит 54887b4 (27 декабря 2019 г.) Ханса Джерри Илликайнена ( illikainen) .
(Объединено Junio ​​C Hamano - gitster- в коммите 11ad30b , 30 января 2020 г.)

gpg-interface: добавить minTrustLevel как параметр конфигурации

Подписано: Ханс Джерри Илликайнен

Ранее проверка подписи для операций слияния и извлечения проверяла, имел ли ключ уровень доверия либо TRUST_NEVERили TRUST_UNDEFINEDin verify_merge_signature().

Если это было так, процесс die()d.

Остальные пути кода, в которых выполнялась проверка подписи, полностью полагались на код возврата из check_commit_signature().

И подписи, сделанные с использованием хорошего ключа, независимо от уровня доверия, считались действительными check_commit_signature().

Это различие в поведении может побудить пользователей ошибочно предположить, что уровень доверия ключа в их связке ключей всегда учитывается Git, даже для операций, где это не так (например, во время verify-commitили verify-tag) .

Это работало путем gpg-interface.cсохранения результатов состояния ключа / подписи и двух самых низких уровней доверия в resultчлене signature_checkструктуры (последняя из этих строк состояния, которые были встречены, записывалась result).

Они задокументированы в GPG в подразделах General status codesи Key relatedсоответственно.

В документации GPG о TRUST_ statusкодах говорится следующее :


Это несколько похожих кодов состояния:

- TRUST_UNDEFINED <error_token>
- TRUST_NEVER     <error_token>
- TRUST_MARGINAL  [0  [<validation_model>]]
- TRUST_FULLY     [0  [<validation_model>]]
- TRUST_ULTIMATE  [0  [<validation_model>]]

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


Моя интерпретация заключается в том, что уровень доверия концептуально отличается от действительности ключа и / или подписи.

Похоже, что это также было предположением старого кода, в check_signature()котором результат G«(как в GOODSIG) и U» (как в TRUST_NEVERили TRUST_UNDEFINED)оба считались успешными.

Два случая, когда результат ' U' имел особое значение, были in verify_merge_signature()(где это приводило gitк die()) и in format_commit_one()(где это влияло на вывод %G?спецификатора формата).

Я думаю, имеет смысл провести рефакторинг обработки TRUST_ statusстрок, чтобы пользователи могли настраивать минимальный уровень доверия, который применяется глобально, вместо того, чтобы отдельные части git(например, слияние) выполняли это самостоятельно (за исключением льготного периода с обратной совместимостью).

Я также думаю, что имеет смысл не хранить уровень доверия в том же члене структуры, что и статус ключа / подписи.

Хотя наличие TRUST_ statusкода действительно означает, что подпись исправна (см. Первый абзац во включенном фрагменте выше), насколько я могу судить, порядок строк состояния в GPG не определен четко; таким образом, казалось бы правдоподобным, что уровень доверия может быть перезаписан статусом ключа / подписи, если они хранились в одном элементе signature_checkструктуры.

Этот патч вводит новую опцию конфигурации: gpg.minTrustLevel.

Он объединяет проверку уровня доверия gpg-interface.cи добавляет в структуру нового trust_levelчлена signature_check.

Обратная совместимость поддерживается за счет введения особого случая verify_merge_signature(), когда, если пользовательские настройки gpg.minTrustLevelне заданы, то применяется старое поведение отклонения TRUST_UNDEFINEDи TRUST_NEVERпринудительного исполнения.

Если, с другой стороны, gpg.minTrustLevelустановлено, то это значение отменяет старое поведение.

Точно так же %G?спецификатор формата будет продолжать показывать " U" для подписей, сделанных с помощью ключа, который имеет уровень доверия TRUST_UNDEFINEDили TRUST_NEVER,даже если Uсимвол " " больше не существует в resultчлене signature_checkструктуры.

Также представлен новый описатель формата %GTдля пользователей, которые хотят показать все возможные уровни доверия для подписи.

Другой подход состоял бы в том, чтобы просто отказаться от требования уровня доверия verify_merge_signature().

Это также сделало бы поведение совместимым с другими частями git, которые выполняют проверку подписи.

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

Например, система сборки, используемая проектом Qubes OS, в настоящее время анализирует необработанный вывод от verify-tag, чтобы подтвердить минимальный уровень доверия для ключей, используемых для подписи тегов git .

git config gpgСтраница человека теперь включает в себя:

gpg.minTrustLevel:

Задает минимальный уровень доверия для проверки подписи.
Если этот параметр не установлен, тогда для проверки подписи для операций слияния требуется ключ как минимум с marginalдоверием.
Для других операций, выполняющих проверку подписи, требуется ключ как минимум с undefinedдоверием.
Установка этого параметра отменяет требуемый уровень доверия для всех операций. Поддерживаемые значения в порядке возрастания значимости:

  • undefined
  • never
  • marginal
  • fully
  • ultimate

В Git 2.26 (Q1 2020) " git show" и другие давали имя объекта в необработанном формате в выводе ошибок, который был исправлен, чтобы дать его в шестнадцатеричном формате.

show_one_mergetag: распечатать не-родительский в шестнадцатеричной форме.

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

Протестировано git -C shallow log --graph --show-signature -n1 plain-shallowпослеgit clone --depth 1 --no-local . shallow


В Git 2.27 (второй квартал 2020 г.) код для взаимодействия с GnuPG был переработан.

См. Commit 6794898 , commit f1e3df3 (4 марта 2020 г.) Ханс Джерри Илликайнен ( illikainen) .
(Объединено Junio ​​C Hamano - gitster- в фиксации fa82be9 , 27 марта 2020 г.)

gpg-interface: предпочитаю check_signature()для проверки GPG

Подписано: Ханс Джерри Илликайнен

Эта фиксация рефакторирует использование за verify_signed_buffer()пределами gpg-interface.cдля использования check_signature()вместо этого.

Он также превращается verify_signed_buffer()в локальную для файла функцию, поскольку теперь вызывается только изнутри check_signature().

Раньше для проверки подписи GPG в разных частях Git использовались две глобальные функции: verify_signed_buffer()и check_signature().

Сейчас только check_signature()используется.

Эта verify_signed_buffer()функция не защищает от дублирования подписей, как описано Михалом Горным .

Вместо этого он обеспечивает только безошибочный код выхода из GPG и наличие хотя бы одного GOODSIGполя статуса.

Это отличается от того, check_signature()что возвращает ошибку, если встречается более одной подписи.

Более низкая степень проверки делает использование verify_signed_buffer()проблематичным, если вызывающие абоненты не анализируют и не проверяют сами различные части сообщения о состоянии GPG.

И обработка этих сообщений кажется задачей, которую следует зарезервировать для gpg-interface.cфункции check_signature().

Кроме того, использование verify_signed_buffer()делает трудным внедрение новых функций, которые зависят от содержимого строк состояния GPG.

Теперь все операции, выполняющие проверку подписи, имеют единую точку входа в gpg-interface.c.

Это упрощает распространение измененных или дополнительных функций проверки подписи GPG на все части Git без странных крайних случаев, которые не выполняют одинаковую степень проверки .

VonC
источник
4

Беглый просмотр кода подсказывает, что такого прямого метода не существует.

Все тесты в исходном коде git полагаются на grepping вывод git show(см. Тесты t / t7510-signed-commit.sh ).

Вы можете настроить вывод, используя что-то вроде --pretty "%H %G?%"упрощения синтаксического анализа.

Похоже, вы можете попросить git mergeпроверить подпись, но опять же, его тесты полагаются на grep(см. T / t7612-merge-verify-signatures.sh ). Похоже, что недействительная подпись приведет git mergeк выходу с плохой подписью, поэтому вы потенциально можете сегодня обойти это, выполнив где-нибудь тестовое слияние и выбрасывая это слияние, но это кажется хуже, чем просто вызов grep.

Эмиль Сит
источник