¿Verificando las confirmaciones de git firmadas?

95

Con versiones más recientes de git , es posible firmar confirmaciones individuales (además de etiquetas) con una clave PGP:

git commit -m "some message" -S

Y puede mostrar estas firmas en la salida de git logcon la --show-signatureopción:

$ 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

Pero, ¿hay alguna manera de verificar programáticamente la firma en una confirmación determinada que no sea grepping la salida de git log? Estoy buscando el equivalente de confirmación de git tag -v: algo que proporcione un código de salida que indique si hubo o no una firma válida en una determinada confirmación.

larsks
fuente
1
Creo que debería ser git commit ...y git log .... Hasta donde yo sé, gpgno se han agregado subcomandos que se pasen de forma gittransparente ... No tengo ningún repositorio para probar, pero ¿ git show --show-signature <commitish>funciona?
twalberg
show_signaturesolo agrega cosas a la salida (consulte github.com/git/git/blob/master/log-tree.c#L370 ).
Emil Sit
Nota: pronto tendrá --rawfor git verify-tag/ git verify-commit. Vea mi respuesta a continuación
VonC
1
Nota: Con GIT 2,11 (Q4 2016), git loglos códigos de estado introduce adicionales E, X, Y, Rde ERRSIG, EXPSIG, EXPKEYSIG, y REVKEYSIG, de manera que un usuario del %G?obtiene más información. Vea mi respuesta editada a continuación
VonC
1
Con Git 2.26 (Q1 2020), la nueva configuración gpg.minTrustLevelpuede ayudar cuando se usa git verify-tag/ verify -commit. Vea mi respuesta editada a continuación .
VonC

Respuestas:

114

En caso de que alguien llegue a esta página a través de un motor de búsqueda, como lo hice yo: se han puesto a disposición nuevas herramientas en los dos años desde que se publicó la pregunta: ahora hay comandos git para esta tarea: git verify-commity git verify-tagse pueden usar para verificar confirmaciones y etiquetas, respectivamente.

tarleb
fuente
34

Nota: hasta git 2.5 git verify-commity git verify-tagsolo muestra un mensaje legible por humanos.
Si desea automatizar la verificación, git 2.6+ (Q3 2015) agrega otra salida.

Consulte confirmar e18443e , confirmar aeff29d , confirmar ca194d5 , confirmar 434060e , confirmar 8e98e5f , confirmar a4cc18f , confirmar d66aeff (21 de junio de 2015) por brian m. carlson ( bk2204) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso ba12cb2 , 03 de agosto de 2015)

verify-tag/ verify-commit: agrega la opción para imprimir información de estado de gpg sin procesar

verify-tag/ verify-commitmuestra por defecto una salida legible por humanos en caso de error estándar.
Sin embargo, también puede ser útil obtener acceso a la información de estado de gpg sin procesar, que es legible por máquina, lo que permite la implementación automatizada de la política de firma .

Agregue una --rawopción para hacer que se verify-taggenere la información de estado de gpg en un error estándar en lugar del formato legible por humanos.

Más:

verify-tagsale con éxito si la firma es buena pero la clave no es de confianza. verify-commitsale sin éxito.
Esta divergencia de comportamiento es inesperada y no deseada.
Dado que verify-tagexistía anteriormente, agregue una prueba fallida para tener el comportamiento de verify-commitcompartir verify-tag.


git 2.9 (junio de 2016) actualice el documento de fusión de git :

Véase el compromiso 05a5869 (13 de mayo de 2016) de Keller Fuchs (``) .
Ayudado por: Junio ​​C Hamano ( gitster) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso be6ec17 , 17 de mayo de 2016)

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

Verifique que la confirmación de punta de la rama lateral que se está fusionando esté firmada con una clave válida, es decir, una clave que tenga un uid válido: en el modelo de confianza predeterminado, esto significa que la clave de firma ha sido firmada por una clave de confianza.
Si la confirmación de punta de la rama lateral no está firmada con una clave válida, la fusión se aborta
.


Actualización de Git 2.10 (tercer trimestre de 2016)

Consulte la confirmación b624a3e (16 de agosto de 2016) de Linus Torvalds ( torvalds) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 83d9eb0 , 19 de agosto de 2016)

gpg-interface: prefiera la salida de formato de clave "larga" al verificar las firmas pgp

" git log --show-signature" y otros comandos que muestran el estado de verificación de la firma PGP ahora muestran el ID de clave más largo, como lo es el ID de clave de 32 bits del siglo pasado.

El original de Linus se modificó para aplicarlo a la pista de mantenimiento en caso de que los distribuidores binarios que están atascados en el pasado quieran llevarlo a su base de código anterior.


Git 2.11+ (Q4 2016) será aún más preciso.

Consulte la confirmación 661a180 (12 de octubre de 2016) de Michael J Gruber ( mjg) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 56d268b , 26 de octubre de 2016)

El estado de verificación GPG que se muestra en el " %G?" especificador de formato bonito no era lo suficientemente rico como para diferenciar una firma hecha por una clave caducada, una firma hecha por una clave revocada, etc.
Se han asignado nuevas letras de salida para expresarlas .

Según gpg2doc/DETAILS :

Para cada firma Sólo uno de los códigos GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIGo ERRSIGserá emitida.

La git pretty-formatdocumentación ahora incluye:

  • ' %G?': mostrar
    • " G" para una buena firma (válida),
    • " B" por una mala firma,
    • " U" para una buena firma con validez desconocida,
    • " X" para una buena firma vencida,
    • " Y" para una buena firma hecha con una clave caducada,
    • " R" para una buena firma hecha con una clave revocada,
    • " E" si no se puede comprobar la firma (por ejemplo, falta la clave) y "N" si no hay firma

Git 2.12 (Q1 2017) " git tag" y " git verify-tag" aprendieron a poner el estado de verificación de GPG en su --format=<placeholders>formato de salida " " .

Ver commit 4fea72f , commit 02c5433 , commit ff3c8c8 (17 de enero de 2017) por Santiago Torres ( SantiagoTorres) .
Consulte la confirmación 07d347c , la confirmación 2111aa7 , la confirmación 94240b9 (17 de enero de 2017) de Lukas Puehringer (``) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 237bdd9 , 31 de enero de 2017)

Agregar --formata git tag -vsilencia la salida predeterminada de la verificación GPG y en su lugar imprime el objeto de etiqueta formateado.
Esto permite a las personas que llaman verificar el nombre de etiqueta de las referencias / etiquetas con el nombre de etiqueta del encabezado del objeto de etiqueta después de la verificación GPG.


Git 2.16 (Q1 2018) permitirá que la verificación de la firma de confirmación sea aún más automatizada, con la merge.verifySignaturesvariable de configuración.

Ver commit 7f8ca20 , commit ca779e8 (10 de diciembre de 2017) de Hans Jerry Illikainen (``) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 0433d53 , 28 de diciembre de 2017)

merge: agregue la opción de configuración para verifySignatures

git merge --verify-signatures se puede usar para verificar que la confirmación de sugerencia de la rama que se fusiona esté firmada correctamente, pero es engorroso tener que especificar eso cada vez.

Agregue una opción de configuración que habilite este comportamiento de forma predeterminada, que puede ser anulada por --no-verify-signatures.

La git mergepágina del manual de configuración ahora dice:

merge.verifySignatures:

Si es verdadero, equivale a la --verify-signaturesopción de línea de comando.


Git 2.19 (tercer trimestre de 2018) es aún más útil, ya que se les ha enseñado a " git verify-tag" y " git verify-commit" a usar el estado de salida de " gpg --verify" subyacente para señalar una firma incorrecta o no confiable que encontraron.

Nota: con Git 2.19, gpg.formateso se puede configurar en " openpgp" o " x509", y gpg.<format>.programse usa para especificar qué programa usar para manejar el formato) para permitir que los certificados x.509 con CMS a través de " gpgsm" se usen en lugar de a openpgptravés de " gnupg".

Consulte la confirmación 4e5dc9c (09 de agosto de 2018) de Junio ​​C Hamano ( gitster) .
Ayudado por: Vojtech Myslivec ( VojtechMyslivec) , brian m. carlson ( bk2204) y Jeff King ( peff) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 4d34122 , 20 de agosto de 2018)

gpg-interface: propagar el estado de salida de gpgregreso a las personas que llaman

Cuando la API de interfaz gpg unificó el soporte para rutas de código de verificación de firmas para etiquetas firmadas y confirmaciones firmadas a mediados de 2015 alrededor de v2.6.0-rc0 ~ 114, accidentalmente aflojamos la verificación de firmas GPG.

Antes de ese cambio, las confirmaciones firmadas se verificaban buscando la " G" firma ood de GPG, mientras se ignoraba el estado de salida del gpg --verifyproceso " ", mientras que las etiquetas firmadas se verificaban simplemente pasando el estado de salida de "gpg --verify"a través.

El código unificado que tenemos actualmente ignora el estado de salida de " gpg --verify" y devuelve una verificación exitosa cuando la firma coincide con una clave no vencida independientemente de la confianza depositada en la clave (es decir, además de las " G" buenas, aceptamos las " U" no confiables).

Haga que estos comandos indiquen fallas con su estado de salida cuando lo haga " gpg --verify" subyacente (o el comando personalizado especificado por la gpg.programvariable de configuración " ").
Esto esencialmente cambia su comportamiento de una manera incompatible hacia atrás para rechazar firmas que se han hecho con claves que no son de confianza incluso si verifican correctamente, ya que así es como se gpg --verifycomporta " ".

Tenga en cuenta que el código aún anula un estado de salida cero obtenido de " gpg" (o gpg.program) si la salida no dice que la firma es buena o se calcula correctamente pero se hizo con claves que no son de confianza, para detectar un envoltorio mal escrito sobre " gpg" el usuario puede darnos .

Podríamos " U" excluir el soporte de confianza de este código de reserva, pero eso sería hacer dos cambios incompatibles con versiones anteriores en una única confirmación, así que evitemos eso por ahora.
Un cambio de seguimiento podría hacerlo si lo desea.


la clave debe ser confiable / firmada antes de realizar cualquier cifrado

En el lado de la confianza, hay progreso:
con Git 2.26 (Q1 2020), gpg.minTrustLevelse introdujo una variable de configuración para indicar a varias rutas de código de verificación de firmas el nivel mínimo de confianza requerido.

Consulte la confirmación 54887b4 (27 de diciembre de 2019) de Hans Jerry Illikainen ( illikainen) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 11ad30b , 30 de enero de 2020)

gpg-interface: agregue minTrustLevel como una opción de configuración

Firmado por: Hans Jerry Illikainen

Anteriormente, la verificación de firmas de operaciones de combinación y de extracción comprobado si la clave tenía un nivel de confianza de cualquiera TRUST_NEVERo TRUST_UNDEFINEDen verify_merge_signature().

Si ese fuera el caso, el proceso die()d.

Las otras rutas de código que hicieron la verificación de firma se basaron completamente en el código de retorno de check_commit_signature().

Y las firmas realizadas con una buena clave, independientemente de su nivel de confianza, fueron consideradas válidas por check_commit_signature().

Esta diferencia de comportamiento podría inducir a los usuarios a asumir erróneamente que Git siempre considera el nivel de confianza de una clave en su llavero, incluso para operaciones en las que no lo es (por ejemplo, durante un verify-commito verify-tag) .

La forma en que funcionó fue gpg-interface.calmacenando el resultado del estado de la clave / firma y los dos niveles de confianza más bajos en el resultmiembro de la signature_checkestructura (se escribió en la última de estas líneas de estado que se encontraron result).

Estos se documentan en GPG en la subsección General status codesy Key related, respectivamente.

La documentación de GPG dice lo siguiente en los TRUST_ statuscódigos :


Estos son varios códigos de estado similares:

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

En el caso de buenas firmas, se emite una de estas líneas de estado para indicar la validez de la clave utilizada para crear la firma.
Actualmente, los valores del token de error solo los emite gpgsm.


Mi interpretación es que el nivel de confianza es conceptualmente diferente de la validez de la clave y / o firma.

Esa parece haber sido también la suposición del código antiguo en el check_signature()que un resultado de G"(como en GOODSIG) y U" (como en TRUST_NEVERo TRUST_UNDEFINED)ambos se consideraron un éxito).

Los dos casos en los que un resultado de ' U' tenía un significado especial fueron en verify_merge_signature()(donde esto causó gita die()) y en format_commit_one()(donde afectó la salida del %G?especificador de formato).

Creo que tiene sentido refactorizar el procesamiento de TRUST_ statuslíneas de modo que los usuarios puedan configurar un nivel de confianza mínimo que se aplique globalmente, en lugar de que las partes individuales de git(por ejemplo, fusionar) lo hagan ellos mismos (excepto por un período de gracia con compatibilidad con versiones anteriores).

También creo que tiene sentido no almacenar el nivel de confianza en el mismo miembro de estructura que el estado de clave / firma.

Si bien la presencia de un TRUST_ statuscódigo implica que la firma es buena (vea el primer párrafo en el fragmento incluido arriba), por lo que puedo decir, el orden de las líneas de estado de GPG no está bien definido; por lo tanto, parecería plausible que el nivel de confianza se pueda sobrescribir con el estado de clave / firma si estuvieran almacenados en el mismo miembro de la signature_checkestructura.

Este parche introduce una nueva opción de configuración: gpg.minTrustLevel.

Consolida la verificación del nivel de confianza gpg-interface.cy agrega un nuevo trust_levelmiembro a la signature_checkestructura.

La compatibilidad con versiones anteriores se mantiene mediante la introducción de un caso especial en el verify_merge_signature()que si no gpg.minTrustLevelse establece ningún configurable por el usuario , se aplica el antiguo comportamiento de rechazar TRUST_UNDEFINEDy TRUST_NEVER.

Si, por otro lado, gpg.minTrustLevelse establece, ese valor anula el comportamiento anterior.

De manera similar, el %G?especificador de formato continuará mostrando ' U' para las firmas hechas con una clave que tenga un nivel de confianza de TRUST_UNDEFINEDo TRUST_NEVER,incluso aunque el carácter ' U' ya no exista en el resultmiembro de la signature_checkestructura.

%GTTambién se introduce un nuevo especificador de formato, para los usuarios que desean mostrar todos los niveles de confianza posibles para una firma.

Otro enfoque habría sido simplemente eliminar el requisito de nivel de confianza verify_merge_signature().

Esto también habría hecho que el comportamiento fuera coherente con otras partes de git que realizan la verificación de firmas.

Sin embargo, requerir un nivel de confianza mínimo para firmar claves parece tener un caso de uso del mundo real.

Por ejemplo, el sistema de compilación utilizado por el proyecto Qubes OS actualmente analiza la salida sin procesar de verify-tag para afirmar un nivel de confianza mínimo para las claves utilizadas para firmar etiquetas git .

La git config gpgpágina de manual ahora incluye:

gpg.minTrustLevel:

Especifica un nivel de confianza mínimo para la verificación de firmas.
Si esta opción no está configurada, la verificación de la firma para las operaciones de combinación requiere una clave con al menos marginalconfianza.
Otras operaciones que realizan la verificación de firmas requieren una clave con al menos undefinedconfianza.
La configuración de esta opción anula el nivel de confianza requerido para todas las operaciones. Valores admitidos, en orden creciente de importancia:

  • undefined
  • never
  • marginal
  • fully
  • ultimate

Con Git 2.26 (Q1 2020) , " git show" y otros dieron un nombre de objeto en formato sin formato en su salida de error, que se ha corregido para darlo en hexadecimal.

show_one_mergetag: imprime no padre en forma hexadecimal.

Cuando un mergetag nombra a un no padre, lo que puede ocurrir después de un clon superficial, su hash se imprimió previamente como datos sin procesar.
En su lugar, imprímalo en formato hexadecimal.

Probado con git -C shallow log --graph --show-signature -n1 plain-shallowdespués de ungit clone --depth 1 --no-local . shallow


Con Git 2.27 (Q2 2020), el código para interactuar con GnuPG se ha refactorizado.

Consulte la confirmación 6794898 , la confirmación f1e3df3 (4 de marzo de 2020) de Hans Jerry Illikainen ( illikainen) .
(Combinado por Junio ​​C Hamano - gitster- en commit fa82be9 , 27 de marzo de 2020)

gpg-interface: prefiero check_signature()para la verificación GPG

Firmado por: Hans Jerry Illikainen

Esta confirmación refactoriza el uso de verify_signed_buffer()outside of gpg-interface.cto use check_signature()en su lugar.

También se convierte verify_signed_buffer()en una función de archivo local, ya que ahora solo la invoca internamente check_signature().

Anteriormente, se usaban dos funciones de alcance global en diferentes partes de Git para realizar la verificación de firmas GPG: verify_signed_buffer()y check_signature().

Ahora solo check_signature()se usa.

La verify_signed_buffer()función no protege contra firmas duplicadas como lo describe Michał Górny .

En su lugar, solo asegura un código de salida no erróneo de GPG y la presencia de al menos un GOODSIGcampo de estado.

Esto contrasta con lo check_signature()que devuelve un error si se encuentra más de una firma.

El menor grado de verificación hace que el uso sea verify_signed_buffer()problemático si las personas que llaman no analizan y validan las distintas partes del mensaje de estado de GPG.

Y procesar estos mensajes parece una tarea que debería reservarse gpg-interface.ccon la función check_signature().

Además, el uso de verify_signed_buffer()hace que sea difícil introducir nuevas funciones que se basan en el contenido de las líneas de estado de GPG.

Ahora todas las operaciones que realizan la verificación de firmas comparten un único punto de entrada gpg-interface.c.

Esto facilita la propagación de funciones modificadas o adicionales en la verificación de firmas GPG a todas las partes de Git, sin tener casos extremos extraños que no realicen el mismo grado de verificación .

VonC
fuente
4

Una inspección superficial del código sugiere que no existe tal método directo.

Todas las pruebas en la fuente de git se basan en hacer grepping a la salida de git show(consulte t / t7510-signed-commit.sh para las pruebas).

Puede personalizar la salida con algo como --pretty "%H %G?%"para facilitar el análisis.

Parece que puede solicitar git mergeverificar una firma, pero nuevamente, sus pruebas se basan en grep(consulte t / t7612-merge-verify-signatures.sh ). Parece que una firma no válida hará git mergeque salga con una mala firma, por lo que hoy podría solucionar esto haciendo una combinación de prueba en algún lugar y descartando esa combinación, pero eso parece peor que simplemente llamar a grep.

Emil sentarse
fuente