git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 17/24] commit: use expected signature header for SHA-256

From
brian m. carlson <sandals@crustytoothpaste.net>
Date
Feb 22, 2020, 20:17 UTC
Message-ID
<20200222201749.937983-18-sandals@crustytoothpaste.net>
In-Reply-To
<20200222201749.937983-1-sandals@crustytoothpaste.net>

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>
---
 builtin/commit.c         |  2 +-
 commit.c                 | 30 +++++++++++++++++++++++-------
 sequencer.c              |  2 +-
 t/t1450-fsck.sh          | 24 ++++++++++++++++++++++++
 t/t7510-signed-commit.sh | 16 +++++++++++++---
 5 files changed, 62 insertions(+), 12 deletions(-)
diff --git a/builtin/commit.c b/builtin/commit.c
index 7ba33a3bec..798d362a2e 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -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;
diff --git a/commit.c b/commit.c
index a6cfa41a4e..534e14f22a 100644
--- a/commit.c
+++ b/commit.c
@@ -961,14 +961,22 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
 	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 */
diff --git a/sequencer.c b/sequencer.c
index ba90a513b9..cbd920afb2 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -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);
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 02478bc4ec..70a8307154 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -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 &&
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 0c06d22a00..6baaa1ad91 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -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 &&
Previous: brian m. carlsonNext: Junio C Hamano
Message 26 of 51 in “SHA-256 stage 4 implementation, part 1/3”
  1. 00/24 SHA-256 stage 4 implementation, part 1/3brian m. carlson, Feb 22, 2020
  2. 01/24 builtin/pack-objects: make hash agnosticbrian m. carlson, Feb 22, 2020
  3. Jeff KingFeb 23, 2020
  4. Jeff KingFeb 24, 2020
  5. brian m. carlsonFeb 24, 2020
  6. Jeff KingFeb 24, 2020
  7. 03/24 hex: introduce parsing variants taking hash algorithmsbrian m. carlson, Feb 22, 2020
  8. 07/24 t6300: abstract away SHA-1-specific constantsbrian m. carlson, Feb 22, 2020
  9. Junio C HamanoFeb 24, 2020
  10. Jeff KingFeb 24, 2020
  11. Junio C HamanoFeb 24, 2020
  12. 12/24 setup: allow check_repository_format to read repository formatbrian m. carlson, Feb 22, 2020
  13. 11/24 t/helper: make repository tests hash independentbrian m. carlson, Feb 22, 2020
  14. 14/24 builtin/init-db: add environment variable for new repo hashbrian m. carlson, Feb 22, 2020
  15. 06/24 t: use hash-specific lookup tables to define test constantsbrian m. carlson, Feb 22, 2020
  16. 10/24 t/helper: initialize repository if necessarybrian m. carlson, Feb 22, 2020
  17. Junio C HamanoFeb 24, 2020
  18. brian m. carlsonFeb 25, 2020
  19. 22/24 fast-import: make find_marks work on any mark setbrian m. carlson, Feb 22, 2020
  20. 19/24 tag: store SHA-256 signatures in a headerbrian m. carlson, Feb 22, 2020
  21. Junio C HamanoFeb 24, 2020
  22. 23/24 fast-import: add a generic function to iterate over marksbrian m. carlson, Feb 22, 2020
  23. 13/24 builtin/init-db: allow specifying hash algorithm on command linebrian m. carlson, Feb 22, 2020
  24. Junio C HamanoFeb 24, 2020
  25. brian m. carlsonFeb 25, 2020
  26. 17/24 commit: use expected signature header for SHA-256brian m. carlson, Feb 22, 2020
  27. Junio C HamanoFeb 24, 2020
  28. 18/24 gpg-interface: improve interface for parsing tagsbrian m. carlson, Feb 22, 2020
  29. Junio C HamanoFeb 24, 2020
  30. Johannes SchindelinFeb 25, 2020
  31. Junio C HamanoFeb 25, 2020
  32. brian m. carlsonFeb 26, 2020
  33. Junio C HamanoFeb 26, 2020
  34. brian m. carlsonFeb 26, 2020
  35. Johannes SchindelinFeb 27, 2020
  36. Junio C HamanoFeb 27, 2020
  37. 20/24 fast-import: permit reading multiple marks filesbrian m. carlson, Feb 22, 2020
  38. Junio C HamanoJun 5, 2020
  39. Junio C HamanoJun 5, 2020
  40. brian m. carlsonJun 5, 2020
  41. Junio C HamanoJun 5, 2020
  42. 24/24 fast-import: add options for rewriting submodulesbrian m. carlson, Feb 22, 2020
  43. 21/24 fast-import: add helper function for inserting mark object entriesbrian m. carlson, Feb 22, 2020
  44. 04/24 hex: add functions to parse hex object IDs in any algorithmbrian m. carlson, Feb 22, 2020
  45. 16/24 worktree: allow repository version 1brian m. carlson, Feb 22, 2020
  46. 05/24 repository: require a build flag to use SHA-256brian m. carlson, Feb 22, 2020
  47. 02/24 hash: implement and use a context cloning functionbrian m. carlson, Feb 22, 2020
  48. 15/24 init-db: move writing repo version into a functionbrian m. carlson, Feb 22, 2020
  49. 08/24 t6300: make hash algorithm independentbrian m. carlson, Feb 22, 2020
  50. 09/24 t/helper/test-dump-split-index: initialize git repositorybrian m. carlson, Feb 22, 2020
  51. Junio C HamanoFeb 24, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.