Подтвердить что ты не робот

Какие данные подписываются, когда вы `git commit -gpg-sign = <key-id>`?

Я пытаюсь понять, как подписать/проверить фиксации вручную, но я не могу понять, какие данные подписываются для создания подписи. Другими словами, я не могу понять, что <data> в gpg --verify <commit-sig> <data> должно быть.

Здесь соответствующий бит git исходного кода: https://github.com/git/git/blob/master/commit.c#L1047-L1231, но я также новичок в C.


Вот некоторые примеры данных:

В новом репозитории git я создаю файл ledger.txt и фиксирую его с помощью подписанного commit:

git config --global user.signingkey 7E482429
git init
echo "EAC5-531F-38E8-9670-81AE-4E77-C7AA-5FC3-7E48-2429 1\n" > ledger.txt
git add ledger.txt
git commit -m "Initial commit" --gpg-sign=7E482429

И вот он в журнале:

git log --show-signature

    commit 876793da21833b5b8197b08462523fd6aad3e5ba
    gpg: Signature made Fri May  9 20:01:55 2014 CDT using RSA key ID 7E482429
    gpg: Good signature from "Dan Neumann <[email protected]>"
    Author: Dan Neumann <[email protected]>
    Date:   Fri May 9 20:01:55 2014 -0500

        Initial commit

Здесь довольно печатный объект фиксации (который находится в .git/objects/87/6793da21833b5b8197b08462523fd6aad3e5ba):

git cat-file -p 876793da21833b5b8197b08462523fd6aad3e5ba

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 1399683715 -0500
gpgsig -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1

 iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
 ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
 CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
 hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
 Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
 BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
 =sRee
 -----END PGP SIGNATURE-----

Initial commit

И вот фактическое содержимое файла объекта фиксации:

hexdump .git/objects/87/6793da21833b5b8197b08462523fd6aad3e5ba | \
zlib-decompress | \
bin-to-ascii

commit 671\0tree 70e7c184c3a89c749174b4987830c287fd78952d\nauthor Dan Neumann <[email protected]> 1399683715 -0500\ncommitter Dan Neumann <[email protected]> 1399683715 -0500\ngpgsig -----BEGIN PGP SIGNATURE-----\n Version: GnuPG v1\n \n iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw\n ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu\n CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h\n hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF\n Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY\n BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=\n =sRee\n -----END PGP SIGNATURE-----\n\nInitial commit\n
4b9b3361

Ответ 1

После прочтения кода в commit_tree_extended, кажется, что данные, используемые для подписи, являются частью от "дерева" до конца комментария, конечно, исключая подпись.

В вашем примере это должно быть:

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 1399683715 -0500
Initial commit

Из источника git:

Инициализация буфера:

strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));

Родитель совершает переход:

/*
* NOTE! This ordering means that the same exact tree merged with a
* different order of parents will be a _different_ changeset even
* if everything else stays the same.
*/
while (parents) {
    struct commit_list *next = parents->next;
    struct commit *parent = parents->item;

    strbuf_addf(&buffer, "parent %s\n",
    sha1_to_hex(parent->object.sha1));
    free(parents);
    parents = next;
}

Информация о человеке/дате:

if (!author)
    author = git_author_info(IDENT_STRICT);
strbuf_addf(&buffer, "author %s\n", author);
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
if (!encoding_is_utf8)
    strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);

while (extra) {
    add_extra_header(&buffer, extra);
    extra = extra->next;
}
strbuf_addch(&buffer, '\n');

Проверка комментария и кодирования:

/* And add the comment */
strbuf_addbuf(&buffer, msg);

/* And check the encoding */
if (encoding_is_utf8 && !verify_utf8(&buffer))
    fprintf(stderr, commit_utf8_warn);

То, что происходит подписание. Подпись будет добавлена ​​после заголовка.

if (sign_commit && do_sign_commit(&buffer, sign_commit))
    return -1;

Также была бы родительская информация, если в вашей фиксации было что-то.

Ответ 2

Этот ответ является незавершенным.

Фон

Во-первых, некоторые размышления о проблемах с текущим механизмом подписи Git.

В идеале Git использует один из встроенных механизмов подписи GnuPG. Если бы это было так, то было бы легко проверить, что Git совершает без необходимости ссылаться на Git или писать скрипты, просто используя GnuPG gpg --verify или gpg2 --verify.

В этом отношении жаль, что Git не принял механизм подписания GnuPG "снятой подписи", как предлагается в списке рассылки Linux Kernel в 2005 году. Совсем недавно Оуэн Джекобсон перечислил некоторые дополнительные причины, почему отдельные сигнатуры были бы желательны по сравнению с текущим подходом Git. Он указывает, что в настоящее время:

  • Подписи встроены в объекты, которые они подписывают. Подпись является частью идентификатора объекта; поскольку Git адресуется контенту, это означает, что объект не может быть ретроактивно подписан или ретроактивно лишен своей подписи без изменения идентификатора объекта. Git распределенная модель означает, что эти виды изменений идентичности сложны и легко обнаруживаются.

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

  • Только некоторые объекты могут быть подписаны. В то время как Git имеет относительно слабые правила о рабочем потоке, система подписи предполагает, что вы используете один из Git более распространенных рабочих процессов, ограничивая свои параметры не более чем одной подписью и ограничивая подписи тегами и коммитами (оставляя капли, деревья и ссылки).

Майк Гервитц указывает на одно из самых серьезных последствий текущего подхода Git. Git commits имеет поле "коммиттер" и "автор", позволяющее коммиттеру и автору фиксации быть двумя отдельными людьми. Однако в настоящее время Git фиксирует возможность включения только одной подписи. Итак, чья подпись должна быть? В идеале, как автор, так и коммиттер могли бы подписать коммит. Отдельные подписи позволят это. Так что в этом случае были бы вложенные подписи. Но поскольку Git не использует ни один из этих параметров, он заставляет нас выбирать между двумя неудовлетворительными параметрами:

  • Коммиттер разбивает подпись автора и подписывает фиксацию.

  • Коммиттер отказывается подписывать фиксацию.

Это обобщает плохие новости. Хорошей новостью является то, что оболочка Git для GnuPG, по крайней мере, включает параметр --show-signature для git log, который проверяет подписи с использованием GnuPG. Это позволяет журналу Git показать, была ли подпись создана ключом с идентификатором UID, на который вы положили доверие.

Если это так, GnuPG покажет:

Good signature from "John Doe <[email protected]>"

Если нет, GnuPG покажет:

Good signature from "John Doe <[email protected]>"
WARNING: This key is not certified with a trusted signature!
         There is no indication that the signature belongs to the owner.

Ваш вопрос

Как указано в Poko answer, ваша фиксация на первый взгляд выглядит эквивалентной следующему выпущенному документу:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 1399683715 -0500
Initial commit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
=sRee
-----END PGP SIGNATURE-----

Однако предположим, что мы сохраняем это как danneau_stackoverflow_example.asc и пытаемся его проверить, здесь вывод:

$ gpg --verify danneau_stackoverflow_example.asc 
gpg: Signature made Sat 10 May 2014 02:01:55 BST
gpg:                using RSA key C7AA5FC37E482429
gpg: Can't check signature: public key not found

Что GnuPG означает, что это потому, что у меня нет открытого ключа, он не может сказать, хороша или плохая подпись. Итак, даже если я вмешиваюсь в содержимое, я получаю тот же вывод:

$ echo "-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 1399683715 -0500

EVIL MESSAGE HERE

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
=sRee
-----END PGP SIGNATURE-----
" | gpg --verify -
gpg: Signature made Sat 10 May 2014 02:01:55 BST
gpg:                using RSA key C7AA5FC37E482429
gpg: Can't check signature: public key not found

Итак, это означает, что Poko, возможно, не правильно понял, что именно вы подписали в конце концов.

Чтобы разобраться в этом, я попытался преобразовать коммиты, подписанные закрытыми ключами, чьи соответствующие открытые ключи у меня есть, в очищенные файлы и передать их GnuPG для проверки. До сих пор я только что получал ответы "Плохая подпись". Если я выясню, где я ошибаюсь, я обновлю этот ответ.