]> git.ipfire.org Git - thirdparty/git.git/commitdiff
commit: use expected signature header for SHA-256
authorbrian m. carlson <sandals@crustytoothpaste.net>
Sat, 22 Feb 2020 20:17:42 +0000 (20:17 +0000)
committerJunio C Hamano <gitster@pobox.com>
Mon, 24 Feb 2020 17:33:30 +0000 (09:33 -0800)
The transition plan anticipates that we will allow signatures using
multiple algorithms in a single commit. In order to do so, we need to
use a different header per algorithm so that it will be obvious over
which data to compute the signature.

The transition plan specifies that we should use "gpgsig-sha256", so
wire up the commit code such that it can write and parse the current
algorithm, and it can remove the headers for any algorithm when creating
a new commit. Add tests to ensure that we write using the right header
and that git fsck doesn't reject these commits.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/commit.c
commit.c
sequencer.c
t/t1450-fsck.sh
t/t7510-signed-commit.sh

index 7ba33a3bec48de4b8a7b6433df1205bde9e3ebfa..798d362a2e9ea0f83d509d43c4e2c4ceb201eb3d 100644 (file)
@@ -1659,7 +1659,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (amend) {
-               const char *exclude_gpgsig[2] = { "gpgsig", NULL };
+               const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
                extra = read_commit_extra_headers(current_head, exclude_gpgsig);
        } else {
                struct commit_extra_header **tail = &extra;
index a6cfa41a4e315225c08b8e51c5dd982d9f6273d2..534e14f22a5ba279b34d36ea768b464089c261c9 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -961,14 +961,22 @@ cleanup_return:
        return ret;
 }
 
-static const char gpg_sig_header[] = "gpgsig";
-static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
+/*
+ * Indexed by hash algorithm identifier.
+ */
+static const char *gpg_sig_headers[] = {
+       NULL,
+       "gpgsig",
+       "gpgsig-sha256",
+};
 
 static int do_sign_commit(struct strbuf *buf, const char *keyid)
 {
        struct strbuf sig = STRBUF_INIT;
        int inspos, copypos;
        const char *eoh;
+       const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
+       int gpg_sig_header_len = strlen(gpg_sig_header);
 
        /* find the end of the header */
        eoh = strstr(buf->buf, "\n\n");
@@ -1010,6 +1018,8 @@ int parse_signed_commit(const struct commit *commit,
        const char *buffer = get_commit_buffer(commit, &size);
        int in_signature, saw_signature = -1;
        const char *line, *tail;
+       const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
+       int gpg_sig_header_len = strlen(gpg_sig_header);
 
        line = buffer;
        tail = buffer + size;
@@ -1056,11 +1066,17 @@ int remove_signature(struct strbuf *buf)
 
                if (in_signature && line[0] == ' ')
                        sig_end = next;
-               else if (starts_with(line, gpg_sig_header) &&
-                        line[gpg_sig_header_len] == ' ') {
-                       sig_start = line;
-                       sig_end = next;
-                       in_signature = 1;
+               else if (starts_with(line, "gpgsig")) {
+                       int i;
+                       for (i = 1; i < GIT_HASH_NALGOS; i++) {
+                               const char *p;
+                               if (skip_prefix(line, gpg_sig_headers[i], &p) &&
+                                   *p == ' ') {
+                                       sig_start = line;
+                                       sig_end = next;
+                                       in_signature = 1;
+                               }
+                       }
                } else {
                        if (*line == '\n')
                                /* dump the whole remainder of the buffer */
index ba90a513b95f1ddd2b53d6eeafd28ef5d49745e6..cbd920afb2b2e283b02de2313cbc7609429dc101 100644 (file)
@@ -1321,7 +1321,7 @@ static int try_to_commit(struct repository *r,
                return -1;
 
        if (flags & AMEND_MSG) {
-               const char *exclude_gpgsig[] = { "gpgsig", NULL };
+               const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
                const char *out_enc = get_commit_output_encoding();
                const char *message = logmsg_reencode(current_head, NULL,
                                                      out_enc);
index 02478bc4ece20564a7d5ea27df91cb0695d6e5ec..70a8307154ad996ea4ebd51994bd4c2f60a97d0c 100755 (executable)
@@ -133,6 +133,30 @@ test_expect_success 'other worktree HEAD link pointing at a funny place' '
        test_i18ngrep "worktrees/other/HEAD points to something strange" out
 '
 
+test_expect_success 'commit with multiple signatures is okay' '
+       git cat-file commit HEAD >basis &&
+       cat >sigs <<-EOF &&
+       gpgsig -----BEGIN PGP SIGNATURE-----
+         VGhpcyBpcyBub3QgcmVhbGx5IGEgc2lnbmF0dXJlLg==
+         -----END PGP SIGNATURE-----
+       gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
+         VGhpcyBpcyBub3QgcmVhbGx5IGEgc2lnbmF0dXJlLg==
+         -----END PGP SIGNATURE-----
+       EOF
+       sed -e "/^committer/q" basis >okay &&
+       cat sigs >>okay &&
+       echo >>okay &&
+       sed -e "1,/^$/d" basis >>okay &&
+       cat okay &&
+       new=$(git hash-object -t commit -w --stdin <okay) &&
+       test_when_finished "remove_object $new" &&
+       git update-ref refs/heads/bogus "$new" &&
+       test_when_finished "git update-ref -d refs/heads/bogus" &&
+       git fsck 2>out &&
+       cat out &&
+       ! grep "commit $new" out
+'
+
 test_expect_success 'email without @ is okay' '
        git cat-file commit HEAD >basis &&
        sed "s/@/AT/" basis >okay &&
index 0c06d22a0079a61f04cd83dad29562dc4d017218..6baaa1ad91d4e51364afb12e62be6a1b48f2ea74 100755 (executable)
@@ -6,6 +6,11 @@ GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY/lib-gpg.sh"
 
 test_expect_success GPG 'create signed commits' '
+       test_oid_cache <<-\EOF &&
+       header sha1:gpgsig
+       header sha256:gpgsig-sha256
+       EOF
+
        test_when_finished "test_unconfig commit.gpgsign" &&
 
        echo 1 >file && git add file &&
@@ -155,6 +160,11 @@ test_expect_success GPG 'verify signatures with --raw' '
        )
 '
 
+test_expect_success GPG 'proper header is used for hash algorithm' '
+       git cat-file commit fourth-signed >output &&
+       grep "^$(test_oid header) -----BEGIN PGP SIGNATURE-----" output
+'
+
 test_expect_success GPG 'show signed commit with signature' '
        git show -s initial >commit &&
        git show -s --show-signature initial >show &&
@@ -162,7 +172,7 @@ test_expect_success GPG 'show signed commit with signature' '
        git cat-file commit initial >cat &&
        grep -v -e "gpg: " -e "Warning: " show >show.commit &&
        grep -e "gpg: " -e "Warning: " show >show.gpg &&
-       grep -v "^ " cat | grep -v "^gpgsig " >cat.commit &&
+       grep -v "^ " cat | grep -v "^$(test_oid header) " >cat.commit &&
        test_cmp show.commit commit &&
        test_cmp show.gpg verify.2 &&
        test_cmp cat.commit verify.1
@@ -299,10 +309,10 @@ test_expect_success GPG 'check config gpg.format values' '
 test_expect_success GPG 'detect fudged commit with double signature' '
        sed -e "/gpgsig/,/END PGP/d" forged1 >double-base &&
        sed -n -e "/gpgsig/,/END PGP/p" forged1 | \
-               sed -e "s/^gpgsig//;s/^ //" | gpg --dearmor >double-sig1.sig &&
+               sed -e "s/^$(test_oid header)//;s/^ //" | gpg --dearmor >double-sig1.sig &&
        gpg -o double-sig2.sig -u 29472784 --detach-sign double-base &&
        cat double-sig1.sig double-sig2.sig | gpg --enarmor >double-combined.asc &&
-       sed -e "s/^\(-.*\)ARMORED FILE/\1SIGNATURE/;1s/^/gpgsig /;2,\$s/^/ /" \
+       sed -e "s/^\(-.*\)ARMORED FILE/\1SIGNATURE/;1s/^/$(test_oid header) /;2,\$s/^/ /" \
                double-combined.asc > double-gpgsig &&
        sed -e "/committer/r double-gpgsig" double-base >double-commit &&
        git hash-object -w -t commit double-commit >double-commit.commit &&