Stai verificando i commit git firmati?


95

Con le versioni più recenti di gitè possibile firmare singoli commit (oltre ai tag) con una chiave PGP:

git commit -m "some message" -S

E puoi mostrare queste firme nell'output di git logcon l' --show-signatureopzione:

$ 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

Ma c'è un modo per verificare programmaticamente la firma su un dato commit diverso da grepping dell'output di git log? Sto cercando l'equivalente di commit di git tag -v- qualcosa che fornirà un codice di uscita che indica se c'era o meno una firma valida su un determinato commit.


1
Penso che dovrebbe essere git commit ...e git log .... Per quanto ne so, gpgnon ha aggiunto sottocomandi che vengono passati in modo gittrasparente ... Non ho alcun repository con cui testare, ma git show --show-signature <commitish>funziona?
twalberg

show_signatureaggiunge solo cose all'output (vedi github.com/git/git/blob/master/log-tree.c#L370 ).
Emil Sit

Nota: presto avrai --rawper git verify-tag/ git verify-commit. Vedi la mia risposta di seguito
VonC

1
Nota: con git 2.11 (Q4 2016), git logcodici di stato introduce ulteriori E, X, Y, Rper ERRSIG, EXPSIG, EXPKEYSIG, e REVKEYSIG, in modo che un utente di %G?ottiene ulteriori informazioni. Vedi la mia risposta modificata di seguito
VonC

1
Con Git 2.26 (Q1 2020), la nuova configurazione gpg.minTrustLevelpuò aiutare quando si utilizza git verify-tag/ verify -commit. Vedi la mia risposta modificata di seguito .
VonC

Risposte:


114

Nel caso in cui qualcuno acceda a questa pagina tramite un motore di ricerca, come ho fatto io: Nuovi strumenti sono stati resi disponibili nei due anni successivi alla pubblicazione della domanda: Ora ci sono comandi git per questa attività: git verify-commite git verify-tagpossono essere usati per verificare i commit e tag, rispettivamente.


34

Nota: fino a git 2.5 git verify-commite git verify-tagvisualizzava solo un messaggio leggibile dall'uomo.
Se vuoi automatizzare il controllo, git 2.6+ (Q3 2015) aggiunge un altro output.

Vedere commit e18443e , commit aeff29d , commit ca194d5 , commit 434060e , commit 8e98e5f , commit a4cc18f , commit d66aeff (21 giugno 2015) di brian m. carlson ( bk2204) .
(Fuso da Junio ​​C Hamano - gitster- in commit ba12cb2 , 03 agosto 2015)

verify-tag/ verify-commit: aggiungi un'opzione per stampare le informazioni sullo stato gpg grezze

verify-tag/ verify-commitper impostazione predefinita visualizza un output leggibile dall'uomo in caso di errore standard.
Tuttavia, può anche essere utile avere accesso alle informazioni sullo stato gpg grezze, che sono leggibili dalla macchina, consentendo l'implementazione automatica della politica di firma .

Aggiungi --rawun'opzione per verify-tagprodurre le informazioni sullo stato di gpg sull'errore standard invece del formato leggibile dall'uomo.

Più:

verify-tagesce correttamente se la firma è buona ma la chiave non è attendibile. verify-commitesce senza successo.
Questa divergenza di comportamento è inaspettata e indesiderata.
Poiché verify-tagesisteva in precedenza, aggiungi un test con esito negativo per avere il comportamento di verify-commitcondivisione verify-tag.


git 2.9 (giugno 2016) aggiorna il documento git merge :

Vedere il commit 05a5869 (13 maggio 2016) di Keller Fuchs (``) .
Aiutato da: Junio ​​C Hamano ( gitster) .
(Fusione di Junio ​​C Hamano - gitster- in commit be6ec17 , 17 maggio 2016)

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

Verificare che il tip commit del ramo laterale da unire sia firmato con una chiave valida, cioè una chiave che abbia un uid valido: nel modello di trust predefinito, questo significa che la chiave di firma è stata firmata da una chiave fidata.
Se il tip commit del ramo laterale non è firmato con una chiave valida, l'unione viene interrotta
.


Aggiorna Git 2.10 (Q3 2016)

Vedere commit b624a3e (16 agosto 2016) di Linus Torvalds ( torvalds) .
(Fusa da Junio ​​C Hamano - gitster- in commit 83d9eb0 , 19 agosto 2016)

gpg-interface: preferisce l'output in formato chiave "lungo" durante la verifica delle firme PGP

" git log --show-signature" e altri comandi che visualizzano lo stato di verifica della firma PGP ora mostrano l'ID chiave più lungo, come lo è stato l'ID chiave a 32 bit nel secolo scorso.

L'originale di Linus è stato ribasato per essere applicato alla traccia di manutenzione nel caso in cui i distributori binari che sono rimasti bloccati nel passato volessero portarlo alla loro base di codice precedente.


Git 2.11+ (Q4 2016) sarà ancora più preciso.

Vedere commit 661a180 (12 ottobre 2016) di Michael J Gruber ( mjg) .
(Fuso da Junio ​​C Hamano - gitster- in commit 56d268b , 26 ottobre 2016)

Lo stato di verifica GPG mostrato in " %G?" grazioso identificatore di formato non era abbastanza ricco per differenziare una firma fatta da una chiave scaduta, una firma fatta da una chiave revocata, ecc.
Sono state assegnate nuove lettere di output per esprimerle .

Secondo gpg2doc/DETAILS :

Per ogni firma uno solo dei codici GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIGo ERRSIGsarà emessa.

La git pretty-formatdocumentazione ora include:

  • ' %G?': mostra
    • " G" per una buona firma (valida),
    • " B" per una cattiva firma,
    • " U" per una buona firma con validità sconosciuta,
    • " X" per una buona firma scaduta,
    • " Y" per una buona firma fatta da una chiave scaduta,
    • " R" per una buona firma fatta da una chiave revocata,
    • " E" se la firma non può essere controllata (es. chiave mancante) e "N" per nessuna firma

Git 2.12 (Q1 2017) " git tag" e " git verify-tag" hanno imparato a mettere lo stato di verifica GPG nel loro --format=<placeholders>formato di " " output .

Vedere commit 4fea72f , commit 02c5433 , commit ff3c8c8 (17 gennaio 2017) di Santiago Torres ( SantiagoTorres) .
Vedere commit 07d347c , commit 2111aa7 , commit 94240b9 (17 gennaio 2017) di Lukas Puehringer (``) .
(Fuso da Junio ​​C Hamano - gitster- in commit 237bdd9 , 31 gennaio 2017)

L'aggiunta --formata git tag -vdisattiva l'output predefinito della verifica GPG e stampa invece l'oggetto tag formattato.
Ciò consente ai chiamanti di effettuare un controllo incrociato del nome tag da refs / tag con il nome tag dall'intestazione dell'oggetto tag al momento della verifica GPG.


Git 2.16 (Q1 2018) consentirà che la verifica della firma del commit sia ancora più automatizzata, con la merge.verifySignaturesvariabile di configurazione.

Vedere commit 7f8ca20 , commit ca779e8 (10 dicembre 2017) di Hans Jerry Illikainen (``) .
(Fuso da Junio ​​C Hamano - gitster- in commit 0433d53 , 28 dicembre 2017)

merge: aggiungi l'opzione di configurazione per verifySignatures

git merge --verify-signatures può essere usato per verificare che il tip commit del ramo che viene unito sia firmato correttamente, ma è complicato doverlo specificare ogni volta.

Aggiungi un'opzione di configurazione che abiliti questo comportamento per impostazione predefinita, che può essere sovrascritto da --no-verify-signatures.

La git mergepagina man di configurazione ora legge:

merge.verifySignatures:

Se vero, equivale --verify-signaturesall'opzione della riga di comando.


Git 2.19 (Q3 2018) è ancora più utile, poiché a " git verify-tag" e " git verify-commit" è stato insegnato a usare lo stato di uscita del sottostante " gpg --verify" per segnalare firme errate o non attendibili che hanno trovato.

Nota: con Git 2.19, gpg.formatche può essere impostato su " openpgp" o " x509", e gpg.<format>.programche viene utilizzato per specificare quale programma utilizzare per gestire il formato) per consentire l'utilizzo dei certificati x.509 con CMS tramite " gpgsm" anziché openpgptramite " gnupg".

Vedi commit 4e5dc9c (09 agosto 2018) di Junio ​​C Hamano ( gitster) .
Aiutato da: Vojtech Myslivec ( VojtechMyslivec) , brian m. carlson ( bk2204) e Jeff King ( peff) .
(Fuso da Junio ​​C Hamano - gitster- in commit 4d34122 , 20 agosto 2018)

gpg-interface: propaga lo stato di uscita dal gpgretro ai chiamanti

Quando l'API gpg-interface ha unificato il supporto per i codepath di verifica della firma per i tag firmati e per i commit firmati a metà 2015 intorno alla v2.6.0-rc0 ~ 114, abbiamo accidentalmente allentato la verifica della firma GPG.

Prima di questa modifica, i commit firmati venivano verificati cercando " G" la firma ood da GPG, ignorando lo stato di uscita del " gpg --verify" processo, mentre i tag firmati venivano verificati semplicemente passando lo stato di uscita di "gpg --verify".

Il codice unificato di cui disponiamo attualmente ignora lo stato di uscita di " gpg --verify" e restituisce la verifica con successo quando la firma corrisponde a una chiave non scaduta indipendentemente dall'affidabilità riposta sulla chiave (cioè oltre a " G" quelle ood, accettiamo " U" quelle ntrusted).

Fai in modo che questi comandi segnalino un errore con il loro stato di uscita quando sottostante " gpg --verify" (o il comando personalizzato specificato dalla gpg.programvariabile di configurazione " ") lo fa.
Questo essenzialmente cambia il loro comportamento in un modo incompatibile con le versioni precedenti per rifiutare le firme che sono state fatte con chiavi non attendibili anche se vengono verificate correttamente, poiché " gpg --verify" si comporta così.

Nota che il codice sovrascrive ancora uno stato di uscita zero ottenuto da " gpg" (o gpg.program) se l'output non dice che la firma è buona o calcola correttamente ma fatta con chiavi non attendibili, per catturare un involucro scritto male intorno a " gpg" che l'utente potrebbe darci .

Potremmo escludere il Usupporto " " ntrusted da questo codice di fallback, ma ciò significherebbe apportare due modifiche incompatibili all'indietro in un singolo commit, quindi evitiamolo per ora.
Un cambiamento successivo potrebbe farlo se lo si desidera.


la chiave è necessaria per essere attendibile / firmata prima di eseguire qualsiasi crittografia

Dal punto di vista della fiducia, ci sono progressi:
con Git 2.26 (Q1 2020), la gpg.minTrustLevelvariabile di configurazione è stata introdotta per indicare a vari codepath di verifica della firma il livello di fiducia minimo richiesto.

Vedi commit 54887b4 (27 dic 2019) di Hans Jerry Illikainen ( illikainen) .
(Fuso da Junio ​​C Hamano - gitster- in commit 11ad30b , 30 gennaio 2020)

gpg-interface: aggiungi minTrustLevel come opzione di configurazione

Firmato da: Hans Jerry Illikainen

In precedenza, la verifica della firma per le operazioni di unione e pull controllava se la chiave aveva un livello di affidabilità di TRUST_NEVERo TRUST_UNDEFINEDin verify_merge_signature().

In tal caso, il processo die()"d.

Gli altri percorsi di codice che hanno eseguito la verifica della firma si basavano interamente sul codice di ritorno da check_commit_signature().

E le firme fatte con una buona chiave, indipendentemente dal suo livello di fiducia, sono state considerate valide da check_commit_signature().

Questa differenza di comportamento potrebbe indurre gli utenti a presumere erroneamente che il livello di fiducia di una chiave nel loro portachiavi sia sempre considerato da Git, anche per le operazioni in cui non lo è (ad esempio durante un verify-commitor verify-tag) .

Il modo in cui ha funzionato è stato gpg-interface.carchiviando il risultato dello stato di chiave / firma e dei due livelli di fiducia più bassi nel resultmembro della signature_checkstruttura (l'ultima di queste righe di stato incontrate è stata scritta result).

Questi sono documentati in GPG sotto la sottosezione General status codese Key related, rispettivamente.

La documentazione GPG dice quanto segue sui TRUST_ statuscodici :


Questi sono diversi codici di stato simili:

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

Per firme buone viene emessa una di queste righe di stato per indicare la validità della chiave utilizzata per creare la firma.
I valori del token di errore sono attualmente emessi solo da gpgsm.


La mia interpretazione è che il livello di fiducia è concettualmente diverso dalla validità della chiave e / o della firma.

Questa sembra essere stata anche l'ipotesi del vecchio codice in check_signature()cui un risultato di G"(come in GOODSIG) e" U"(come in TRUST_NEVERo TRUST_UNDEFINED)erano entrambi considerati un successo.

I due casi in cui un risultato di " U" aveva un significato speciale erano in verify_merge_signature()(dove questo ha causato gita die()) e in format_commit_one()(dove ha influenzato l'output dell'identificatore di %G?formato).

Penso che abbia senso effettuare il refactoring dell'elaborazione delle TRUST_ statuslinee in modo tale che gli utenti possano configurare un livello di fiducia minimo che viene applicato a livello globale, piuttosto che avere singole parti di git(ad esempio unire) lo fanno da soli (tranne per un periodo di grazia con retrocompatibilità).

Penso anche che abbia senso non memorizzare il livello di fiducia nello stesso membro della struttura dello stato della chiave / firma.

Sebbene la presenza di un TRUST_ statuscodice implichi che la firma sia buona (vedere il primo paragrafo nello snippet incluso sopra), per quanto ne so, l'ordine delle righe di stato da GPG non è ben definito; quindi sembrerebbe plausibile che il livello di fiducia potrebbe essere sovrascritto con lo stato di chiave / firma se fossero memorizzati nello stesso membro della signature_checkstruttura.

Questa patch introduce una nuova opzione di configurazione: gpg.minTrustLevel.

Consolida la verifica del livello di fiducia gpg-interface.ce aggiunge un nuovo trust_levelmembro alla signature_checkstruttura.

Backward-compatibilità è mantenuta introducendo un caso speciale in verify_merge_signature()modo tale che se nessun utente configurabile gpg.minTrustLevelè impostato, il vecchio comportamento di rigetto TRUST_UNDEFINEDe TRUST_NEVERviene applicata.

Se, d'altra parte, gpg.minTrustLevelè impostato, quel valore sovrascrive il vecchio comportamento.

Allo stesso modo, l' %G?identificatore di formato continuerà a mostrare " U" per le firme create con una chiave che ha un livello di fiducia TRUST_UNDEFINEDo TRUST_NEVER,anche se il Ucarattere " " non esiste più nel resultmembro della signature_checkstruttura.

Viene %GTinoltre introdotto un nuovo identificatore di formato,, per gli utenti che desiderano mostrare tutti i possibili livelli di affidabilità per una firma.

Un altro approccio sarebbe stato quello di eliminare semplicemente il requisito del livello di fiducia verify_merge_signature().

Ciò avrebbe anche reso il comportamento coerente con altre parti di git che eseguono la verifica della firma.

Tuttavia, la richiesta di un livello di affidabilità minimo per la firma delle chiavi sembra avere un caso d'uso reale.

Ad esempio, il sistema di compilazione utilizzato dal progetto Qubes OS attualmente analizza l'output non elaborato dal tag-di verifica al fine di affermare un livello di affidabilità minimo per le chiavi utilizzate per firmare i tag git .

La git config gpgpagina man ora include:

gpg.minTrustLevel:

Specifica un livello di affidabilità minimo per la verifica della firma.
Se questa opzione non è impostata, la verifica della firma per le operazioni di unione richiede una chiave con almeno marginalattendibilità.
Altre operazioni che eseguono la verifica della firma richiedono una chiave con almeno undefinedattendibilità.
L'impostazione di questa opzione sovrascrive il livello di attendibilità richiesto per tutte le operazioni. Valori supportati, in ordine crescente di significatività:

  • undefined
  • never
  • marginal
  • fully
  • ultimate

Con Git 2.26 (Q1 2020) , " git show" e altri hanno fornito un nome oggetto in formato grezzo nel suo output di errore, che è stato corretto per fornirlo in esadecimale.

show_one_mergetag: stampa non genitore in formato esadecimale.

Quando un mergetag nomina un non padre, cosa che può verificarsi dopo un clone superficiale, il relativo hash veniva precedentemente stampato come dati non elaborati.
Stampalo invece in formato esadecimale.

Testato con git -C shallow log --graph --show-signature -n1 plain-shallowdopo agit clone --depth 1 --no-local . shallow


Con Git 2.27 (Q2 2020), il codice per interfacciarsi con GnuPG è stato refactoring.

Vedere commit 6794898 , commit f1e3df3 (04 marzo 2020) di Hans Jerry Illikainen ( illikainen) .
(Fuso da Junio ​​C Hamano - gitster- in commit fa82be9 , 27 marzo 2020)

gpg-interface: preferisci check_signature()per la verifica GPG

Firmato da: Hans Jerry Illikainen

Questo commit refactora invece l'uso di verify_signed_buffer()outside of gpg-interface.cto use check_signature().

Si trasforma anche verify_signed_buffer()in una funzione locale di file poiché ora viene richiamata solo internamente da check_signature().

In precedenza c'erano due funzioni con ambito globale utilizzate in diverse parti di Git per eseguire la verifica della firma GPG: verify_signed_buffer()e check_signature().

Ora check_signature()viene utilizzato solo .

La verify_signed_buffer()funzione non protegge dalle firme duplicate come descritto da Michał Górny .

Invece garantisce solo un codice di uscita non errato da GPG e la presenza di almeno un GOODSIGcampo di stato.

Ciò è in contrasto con il fatto check_signature()che restituisce un errore se viene rilevata più di una firma.

Il grado inferiore di verifica rende verify_signed_buffer()problematico l'uso di se i chiamanti non analizzano e convalidano da soli le varie parti del messaggio di stato GPG.

E l'elaborazione di questi messaggi sembra un'attività che dovrebbe essere riservata alla gpg-interface.cfunzione check_signature().

Inoltre, l'uso di verify_signed_buffer()rende difficile introdurre nuove funzionalità che si basano sul contenuto delle righe di stato GPG.

Ora tutte le operazioni che eseguono la verifica della firma condividono un unico punto di ingresso per gpg-interface.c.

Ciò semplifica la propagazione di funzionalità modificate o aggiuntive nella verifica della firma GPG a tutte le parti di Git, senza avere casi limite strani che non eseguono lo stesso grado di verifica .


4

Un'ispezione superficiale del codice suggerisce che non esiste un metodo così diretto.

Tutti i test nel sorgente git si basano sul grepping dell'output di git show(vedere t / t7510-signed-commit.sh per i test).

Puoi personalizzare l'output usando qualcosa di simile --pretty "%H %G?%"per renderlo facile da analizzare.

Sembra che tu possa chiedere git mergedi verificare una firma ma, ancora una volta, i suoi test si basano su grep(vedi t / t7612-merge-verify-signatures.sh ). Sembra che una firma non valida provochi git mergel'uscita con una cattiva firma, quindi oggi potresti potenzialmente aggirare questo problema facendo una fusione di prova da qualche parte e buttando fuori quella fusione, ma sembra peggio che chiamare grep.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.