Vérifier les commits git signés?

95

Avec les nouvelles versions de, gitil est possible de signer des commits individuels (en plus des balises) avec une clé PGP:

git commit -m "some message" -S

Et vous pouvez afficher ces signatures dans la sortie de git logavec l' --show-signatureoption:

$ 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 <[email protected]>"
Author: Lars Kellogg-Stedman <[email protected]>
Date:   Fri Jun 28 14:28:41 2013 -0400

    this is a test

Mais y a-t-il un moyen de vérifier par programme la signature sur un commit donné autrement qu'en grepping la sortie de git log? Je recherche l'équivalent de commit de git tag -v- quelque chose qui fournira un code de sortie indiquant s'il y avait ou non une signature valide sur un commit donné.

larsks
la source
1
Je pense que cela devrait être git commit ...et git log .... Autant que je sache, gpgn'a pas ajouté de sous-commandes qui sont transmises de manière gittransparente ... Je n'ai pas de repos à tester, mais cela git show --show-signature <commitish>fonctionne-t-il?
twalberg
show_signaturen'ajoute que des éléments à la sortie (voir github.com/git/git/blob/master/log-tree.c#L370 ).
Emil Sit
Remarque: vous en aurez bientôt --rawpour git verify-tag/ git verify-commit. Voir ma réponse ci
VonC
1
Note: Avec git 2,11 (4ème trimestre 2016), git logintroduit des codes d'état supplémentaires E, X, Y, Rpour ERRSIG, EXPSIG, EXPKEYSIGet REVKEYSIG, de sorte qu'un utilisateur %G?obtient plus d' informations. Voir ma réponse modifiée ci
VonC
1
Avec Git 2.26 (Q1 2020), la nouvelle configuration gpg.minTrustLevelpeut aider lors de l'utilisation de git verify-tag/ verify -commit. Voir ma réponse modifiée ci-dessous .
VonC le

Réponses:

114

Juste au cas où quelqu'un accède à cette page via un moteur de recherche, comme je l'ai fait: de nouveaux outils ont été mis à disposition dans les deux ans qui ont suivi la publication de la question: il existe maintenant des commandes git pour cette tâche: git verify-commitet git verify-tagpeuvent être utilisées pour vérifier les commits et balises, respectivement.

tarleb
la source
34

Remarque: jusqu'à git 2.5, git verify-commitet git verify-tagn'affichait qu'un message lisible par l'homme.
Si vous souhaitez automatiser la vérification, git 2.6+ (Q3 2015) ajoute une autre sortie.

Voir commit e18443e , commit aeff29d , commit ca194d5 , commit 434060e , commit 8e98e5f , commit a4cc18f , commit d66aeff (21 juin 2015) par brian m. carlson ( bk2204) .
(Merged by Junio ​​C Hamano - gitster- in commit ba12cb2 , 03 août 2015)

verify-tag/ verify-commit: ajouter une option pour imprimer les informations brutes d'état gpg

verify-tag/ verify-commitpar défaut affiche une sortie lisible par l'homme en cas d'erreur standard.
Cependant, il peut également être utile d'accéder aux informations brutes sur l'état du fichier gpg, qui sont lisibles par machine, ce qui permet une mise en œuvre automatisée de la politique de signature .

Ajoutez une --rawoption pour faire verify-tagproduire les informations d'état gpg sur l'erreur standard au lieu du format lisible par l'homme.

Plus:

verify-tagse termine avec succès si la signature est bonne mais que la clé n'est pas approuvée. verify-commitquitte sans succès.
Cette divergence de comportement est inattendue et indésirable.
Depuis verify-tagexistait plus tôt, ajoutez un test qui échoue pour avoir le comportement du verify-commitpartage verify-tag.


git 2.9 (juin 2016) met à jour le document git merge :

Voir commit 05a5869 (13 mai 2016) de Keller Fuchs (``) .
Aide: Junio ​​C Hamano ( gitster) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit be6ec17 , 17 mai 2016)

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

Vérifiez que le commit tip de la branche secondaire en cours de fusion est signé avec une clé valide, c'est-à -
dire une clé qui a un uid valide: dans le modèle de confiance par défaut, cela signifie que la clé de signature a été signée par une clé de confiance. Si la validation de la pointe de la branche latérale n'est pas signée avec une clé valide, la fusion est abandonnée .


Mise à jour de Git 2.10 (T3 2016)

Voir commit b624a3e (16 août 2016) par Linus Torvalds ( torvalds) .
(Fusionné par Junio ​​C Hamano - gitster- in commit 83d9eb0 , 19 août 2016)

gpg-interface: préférez la sortie au format de clé "longue" lors de la vérification des signatures pgp

" git log --show-signature" et d'autres commandes qui affichent l'état de vérification de la signature PGP affichent désormais le key-id plus long, comme le key-id 32 bits l'est au siècle dernier.

L'original de Linus a été rebasé pour s'appliquer à la piste de maintenance juste au cas où les distributeurs binaires bloqués dans le passé voudraient le transférer dans leur ancienne base de code.


Git 2.11+ (Q4 2016) sera encore plus précis.

Voir commit 661a180 (12 octobre 2016) par Michael J Gruber ( mjg) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 56d268b , 26 oct 2016)

L'état de vérification GPG affiché dans " %G?" joli spécificateur de format n'était pas assez riche pour différencier une signature faite par une clé expirée, une signature faite par une clé révoquée, etc. De
nouvelles lettres de sortie ont été attribuées pour les exprimer .

Selon gpg2doc/DETAILS :

Pour chaque signature que l' un des codes GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIGou ERRSIGsera émis.

La git pretty-formatdocumentation comprend désormais:

  • ' %G?': montrer
    • " G" pour une bonne signature (valide),
    • " B" pour une mauvaise signature,
    • " U" pour une bonne signature à validité inconnue,
    • " X" pour une bonne signature expirée,
    • " Y" pour une bonne signature faite par une clé expirée,
    • " R" pour une bonne signature faite par une clé révoquée,
    • " E" si la signature ne peut pas être vérifiée (par exemple, clé manquante) et "N" pour aucune signature

Git 2.12 (Q1 2017) " git tag" et " git verify-tag" ont appris à mettre le statut de vérification GPG dans leur " --format=<placeholders>" format de sortie .

Voir commit 4fea72f , commit 02c5433 , commit ff3c8c8 (17 janvier 2017) par Santiago Torres ( SantiagoTorres) .
Voir commit 07d347c , commit 2111aa7 , commit 94240b9 (17 janvier 2017) par Lukas Puehringer (``) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 237bdd9 , 31 janvier 2017)

L'ajout --formatà git tag -vcoupe la sortie par défaut de la vérification GPG et imprime à la place l'objet de balise formaté.
Cela permet aux appelants de contre-vérifier le nom de variable des références / tags avec le nom de la variable de l'en-tête de l'objet tag lors de la vérification GPG.


Git 2.16 (Q1 2018) permettra à la vérification de la signature de validation d'être encore plus automatisée, avec la merge.verifySignaturesvariable de configuration.

Voir commit 7f8ca20 , commit ca779e8 (10 décembre 2017) par Hans Jerry Illikainen (``) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 0433d53 , 28 déc 2017)

merge: ajouter une option de configuration pour verifySignatures

git merge --verify-signatures peut être utilisé pour vérifier que le dernier commit de la branche fusionnée est correctement signé, mais il est difficile de le spécifier à chaque fois.

Ajoutez une option de configuration qui active ce comportement par défaut, qui peut être remplacée par --no-verify-signatures.

La git mergepage de manuel de configuration se lit maintenant:

merge.verifySignatures:

Si vrai, cela équivaut à l' --verify-signaturesoption de ligne de commande.


Git 2.19 (Q3 2018) est encore plus utile, car " git verify-tag" et " git verify-commit" ont appris à utiliser le statut de sortie du sous-jacent " gpg --verify" pour signaler une signature incorrecte ou non approuvée qu'ils ont trouvée.

Remarque: avec Git 2.19, gpg.formatqui peut être défini sur " openpgp" ou " x509", et gpg.<format>.programqui est utilisé pour spécifier le programme à utiliser pour gérer le format) pour permettre l'utilisation des certificats x.509 avec CMS via " gpgsm" au lieu de openpgpvia " gnupg".

Voir commit 4e5dc9c (09 août 2018) par Junio ​​C Hamano ( gitster) .
Aide: Vojtech Myslivec ( VojtechMyslivec) , brian m. carlson ( bk2204) et Jeff King ( peff) .
(Merged by Junio ​​C Hamano - gitster- in commit 4d34122 , 20 août 2018)

gpg-interface: propage le statut de sortie de gpgretour vers les appelants

Lorsque l'API gpg-interface a unifié la prise en charge des chemins de code de vérification de signature pour les balises signées et les commits signés à la mi-2015 vers la version 2.6.0-rc0 ~ 114, nous avons accidentellement desserré la vérification de la signature GPG.

Avant cette modification, les validations signées étaient vérifiées en recherchant la Gsignature « » ood de GPG, tout en ignorant l'état de sortie du gpg --verifyprocessus « », tandis que les balises signées étaient vérifiées en passant simplement l'état de sortie de "gpg --verify«through».

Le code unifié que nous avons actuellement ignore le statut de sortie de " gpg --verify" et retourne une vérification réussie lorsque la signature correspond à une clé non expirée quelle que soit la confiance placée sur la clé (c'est-à-dire en plus des " G" bonnes, nous acceptons les " U" non fiables).

Faites en sorte que ces commandes signalent l'échec avec leur état de sortie lorsque le sous-jacent " gpg --verify" (ou la commande personnalisée spécifiée par la gpg.programvariable de configuration " ") le fait.
Cela modifie essentiellement leur comportement d'une manière rétrocompatible pour rejeter les signatures qui ont été faites avec des clés non approuvées même si elles vérifient correctement, car c'est ainsi que " gpg --verify" se comporte.

Notez que le code remplace toujours un statut de sortie nul obtenu à partir de " gpg" (ou gpg.program) si la sortie ne dit pas que la signature est bonne ou calcule correctement mais fait avec des clés non fiables, pour attraper un wrapper mal écrit autour de " gpg" l'utilisateur peut nous donner .

Nous pourrions exclure le Usupport " " ntrusted de ce code de secours, mais cela ferait deux modifications incompatibles vers l'arrière dans un seul commit, alors évitons cela pour le moment.
Un changement de suivi pourrait le faire si vous le souhaitez.


la clé doit être approuvée / signée avant de procéder au chiffrement

Du côté de la confiance, il y a des progrès:
avec Git 2.26 (Q1 2020), gpg.minTrustLevelune variable de configuration a été introduite pour indiquer à divers chemins de code de vérification de signature le niveau de confiance minimum requis.

Voir commit 54887b4 (27 décembre 2019) par Hans Jerry Illikainen ( illikainen) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 11ad30b , 30 janvier 2020)

gpg-interface: ajoutez minTrustLevel comme option de configuration

Signé par: Hans Jerry Illikainen

Auparavant, la vérification des signatures pour les opérations de fusion et tirez vérifié si la clé avait une confiance au niveau de l'une ou l' autre TRUST_NEVERou TRUST_UNDEFINEDdans verify_merge_signature().

Si tel était le cas, le processus die()«d.

Les autres chemins de code qui effectuaient la vérification de la signature reposaient entièrement sur le code de retour de check_commit_signature().

Et les signatures faites avec une bonne clé, indépendamment de son niveau de confiance, ont été considérées comme valides par check_commit_signature().

Cette différence de comportement peut inciter les utilisateurs à supposer à tort que le niveau de confiance d'une clé dans leur trousseau de clés est toujours pris en compte par Git, même pour les opérations où il ne l'est pas (par exemple pendant un verify-commitou verify-tag) .

La façon dont cela fonctionnait consistait à gpg-interface.cstocker le résultat de l'état de la clé / signature et des deux niveaux de confiance les plus bas dans le resultmembre de la signature_checkstructure (la dernière de ces lignes d'état rencontrées était écrite result).

Ceux-ci sont documentés dans GPG sous la sous-section General status codeset Key related, respectivement.

La documentation GPG dit ce qui suit sur les TRUST_ statuscodes :


Voici plusieurs codes d'état similaires:

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

Pour les bonnes signatures, une de ces lignes d'état est émise pour indiquer la validité de la clé utilisée pour créer la signature.
Les valeurs de jeton d'erreur ne sont actuellement émises que par gpgsm.


Mon interprétation est que le niveau de confiance est conceptuellement différent de la validité de la clé et / ou de la signature.

Cela semble également avoir été l'hypothèse de l'ancien code dans check_signature()lequel le résultat de G«(comme dans GOODSIG) et U» (comme dans TRUST_NEVERou TRUST_UNDEFINED)étaient tous deux considérés comme un succès.

Les deux cas où un résultat de « U» avait une signification particulière étaient dans verify_merge_signature()(où cela a causé gità die()) et dans format_commit_one()(où il affectait la sortie du %G?spécificateur de format).

Je pense qu'il est logique de refactoriser le traitement des TRUST_ statuslignes de sorte que les utilisateurs puissent configurer un niveau de confiance minimum qui est appliqué globalement, plutôt que de laisser des parties individuelles de git(par exemple fusionner) le faire elles-mêmes (sauf pour une période de grâce avec compatibilité descendante).

Je pense également qu'il est logique de ne pas stocker le niveau de confiance dans le même membre de structure que l'état de la clé / signature.

Bien que la présence d'un TRUST_ statuscode implique que la signature est bonne (voir le premier paragraphe dans l'extrait inclus ci-dessus), pour autant que je sache, l'ordre des lignes d'état de GPG n'est pas bien défini; il semblerait donc plausible que le niveau de confiance puisse être écrasé par l'état de la clé / signature s'ils étaient stockés dans le même membre de la signature_checkstructure.

Ce correctif introduit une nouvelle option de configuration: gpg.minTrustLevel.

Il consolide la vérification du niveau de confiance gpg-interface.cet ajoute un nouveau trust_levelmembre à la signature_checkstructure.

Compatibilité ascendante est maintenu par l' introduction d' un cas particulier de verify_merge_signature()telle sorte que si aucune configurable par l' utilisateur gpg.minTrustLevelest définie, alors l'ancien comportement de rejet TRUST_UNDEFINEDet TRUST_NEVERest appliquée.

Si, en revanche, gpg.minTrustLevelest défini, cette valeur remplace l'ancien comportement.

De même, le %G?spécificateur de format continuera à afficher « U» pour les signatures faites avec une clé qui a un niveau de confiance de TRUST_UNDEFINEDou TRUST_NEVER,même si le caractère « U» n'existe plus dans le resultmembre de la signature_checkstructure.

Un nouveau spécificateur de format,, %GTest également introduit pour les utilisateurs qui souhaitent afficher tous les niveaux de confiance possibles pour une signature.

Une autre approche aurait simplement été de supprimer l'exigence de niveau de confiance verify_merge_signature().

Cela aurait également rendu le comportement cohérent avec d'autres parties de git qui effectuent la vérification de signature.

Cependant, exiger un niveau de confiance minimum pour la signature des clés semble avoir un cas d'utilisation réel.

Par exemple, le système de construction utilisé par le projet Qubes OS analyse actuellement la sortie brute de verify-tag afin d'affirmer un niveau de confiance minimum pour les clés utilisées pour signer les balises git .

La git config gpgpage de manuel comprend désormais:

gpg.minTrustLevel:

Spécifie un niveau de confiance minimum pour la vérification de la signature.
Si cette option n'est pas définie, la vérification de signature pour les opérations de fusion nécessite une clé avec au moins marginalconfiance.
D'autres opérations qui effectuent une vérification de signature nécessitent une clé avec au moins undefinedconfiance.
La définition de cette option remplace le niveau de confiance requis pour toutes les opérations. Valeurs prises en charge, par ordre croissant de signification:

  • undefined
  • never
  • marginal
  • fully
  • ultimate

Avec Git 2.26 (Q1 2020) , " git show" et d'autres ont donné un nom d'objet au format brut dans sa sortie d'erreur, qui a été corrigé pour le donner en hexadécimal.

show_one_mergetag: affiche les non-parents sous forme hexadécimale.

Lorsqu'un mergetag nomme un non-parent, ce qui peut se produire après un clone superficiel, son hachage était précédemment imprimé en tant que données brutes.
Imprimez-le plutôt sous forme hexadécimale.

Testé avec git -C shallow log --graph --show-signature -n1 plain-shallowaprès ungit clone --depth 1 --no-local . shallow


Avec Git 2.27 (Q2 2020), le code pour s'interfacer avec GnuPG a été refactorisé.

Voir commit 6794898 , commit f1e3df3 (04 mars 2020) par Hans Jerry Illikainen ( illikainen) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit fa82be9 , 27 mars 2020)

gpg-interface: préférez la check_signature()vérification GPG

Signé par: Hans Jerry Illikainen

Ce commit refactorise l'utilisation de l' verify_signed_buffer()extérieur de gpg-interface.cpour utiliser à la check_signature()place.

Elle se transforme également verify_signed_buffer()en une fonction locale de fichier puisqu'elle n'est désormais invoquée qu'en interne par check_signature().

Il y avait auparavant deux fonctions globales utilisées dans différentes parties de Git pour effectuer la vérification de signature GPG: verify_signed_buffer()et check_signature().

Maintenant, seul check_signature()est utilisé.

La verify_signed_buffer()fonction ne protège pas contre les signatures en double comme décrit par Michał Górny .

Au lieu de cela, il garantit uniquement un code de sortie non erroné de GPG et la présence d'au moins un GOODSIGchamp d'état.

Cela contraste avec check_signature()cela renvoie une erreur si plusieurs signatures sont rencontrées.

Le degré de vérification inférieur rend l'utilisation de verify_signed_buffer()problématique si les appelants n'analysent pas et ne valident pas eux-mêmes les différentes parties du message d'état GPG.

Et le traitement de ces messages semble être une tâche qui devrait être réservée à gpg-interface.cla fonction check_signature().

De plus, l'utilisation de verify_signed_buffer()rend difficile l'introduction de nouvelles fonctionnalités reposant sur le contenu des lignes d'état GPG.

Désormais, toutes les opérations qui effectuent une vérification de signature partagent un point d'entrée unique vers gpg-interface.c.

Cela facilite la propagation des fonctionnalités modifiées ou supplémentaires de la vérification de la signature GPG à toutes les parties de Git, sans avoir des cas extrêmes qui n'effectuent pas le même degré de vérification .

VonC
la source
4

Une inspection superficielle du code suggère qu'il n'existe pas de méthode directe de ce type.

Tous les tests de la source git reposent sur le grepping de la sortie de git show(voir t / t7510-signed-commit.sh pour les tests).

Vous pouvez personnaliser la sortie en utilisant quelque chose comme --pretty "%H %G?%"pour le rendre facile à analyser.

Il semble que vous puissiez demander git mergeà vérifier une signature mais là encore, ses tests reposent sur grep(voir t / t7612-merge-verify-signatures.sh ). Il semble qu'une signature invalide provoquera la git mergesortie avec une mauvaise signature, donc vous pourriez potentiellement aujourd'hui pirater cela en faisant un test de fusion quelque part et en rejetant cette fusion, mais cela semble pire que d'appeler simplement grep.

Emil Sit
la source