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

[PATCH v4 19/22] signed push: remove duplicated protocol info

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 5, 2014, 20:55 UTC
Message-ID
<1409950510-10209-20-git-send-email-gitster@pobox.com>
In-Reply-To
<1409950510-10209-1-git-send-email-gitster@pobox.com>

With the interim protocol, we used to send the update commands even though we already send a signed copy of the same information when push certificate is in use. Update the send-pack/receive-pack pair not to do so.

The notable thing on the receive-pack side is that it makes sure that there is no command sent over the traditional protocol packet outside the push certificate. Otherwise a pusher can claim to be pushing one set of ref updates in the signed certificate while issuing commands to update unrelated refs, and such an update will evade later audits.

Finally, start documenting the protocol.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/technical/pack-protocol.txt         | 33 ++++++++++++++++++++++-
 Documentation/technical/protocol-capabilities.txt | 12 +++++++--
 builtin/receive-pack.c                            | 26 ++++++++++++++++++
 send-pack.c                                       |  2 +-
 4 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index a845d51..4a5c2e8 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -465,7 +465,7 @@ contain all the objects that the server will need to complete the new
 references.
 
 ----
-  update-request    =  *shallow command-list [pack-file]
+  update-request    =  *shallow ( command-list | push-cert ) [pack-file]
 
   shallow           =  PKT-LINE("shallow" SP obj-id)
 
@@ -481,12 +481,25 @@ references.
   old-id            =  obj-id
   new-id            =  obj-id
 
+  push-cert         = PKT-LINE("push-cert" NUL capability-list LF)
+		      PKT-LINE("certificate version 0.1" LF)
+		      PKT-LINE("pusher" SP ident LF)
+		      PKT-LINE(LF)
+		      *PKT-LINE(command LF)
+		      *PKT-LINE(gpg-signature-lines LF)
+		      PKT-LINE("push-cert-end" LF)
+
   pack-file         = "PACK" 28*(OCTET)
 ----
 
 If the receiving end does not support delete-refs, the sending end MUST
 NOT ask for delete command.
 
+If the receiving end does not support push-cert, the sending end
+MUST NOT send a push-cert command.  When a push-cert command is
+sent, command-list MUST NOT be sent; the commands recorded in the
+push certificate is used instead.
+
 The pack-file MUST NOT be sent if the only command used is 'delete'.
 
 A pack-file MUST be sent if either create or update command is used,
@@ -501,6 +514,24 @@ was being processed (the obj-id is still the same as the old-id), and
 it will run any update hooks to make sure that the update is acceptable.
 If all of that is fine, the server will then update the references.
 
+Push Certificate
+----------------
+
+A push certificate begins with a set of header lines.  After the
+header and an empty line, the protocol commands follow, one per
+line.
+
+Currently, the following header fields are defined:
+
+`pusher` ident::
+	Identify the GPG key in "Human Readable Name <email@address>"
+	format.
+
+The GPG signature lines are a detached signature for the contents
+recorded in the push certificate before the signature block begins.
+The detached signature is used to certify that the commands were
+given by the pusher, who must be the signer.
+
 Report Status
 -------------
 
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index e174343..a478cc4 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -18,8 +18,8 @@ was sent.  Server MUST NOT ignore capabilities that client requested
 and server advertised.  As a consequence of these rules, server MUST
 NOT advertise capabilities it does not understand.
 
-The 'report-status', 'delete-refs', and 'quiet' capabilities are sent and
-recognized by the receive-pack (push to server) process.
+The 'report-status', 'delete-refs', 'quiet', and 'push-cert' capabilities
+are sent and recognized by the receive-pack (push to server) process.
 
 The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
 by both upload-pack and receive-pack protocols.  The 'agent' capability
@@ -250,3 +250,11 @@ allow-tip-sha1-in-want
 If the upload-pack server advertises this capability, fetch-pack may
 send "want" lines with SHA-1s that exist at the server but are not
 advertised by upload-pack.
+
+push-cert
+---------
+
+The receive-pack server that advertises this capability is willing
+to accept a signed push certificate.  A send-pack client MUST NOT
+send a push-cert packet unless the receive-pack server advertises
+this capability.
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c0a3189..431af39 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -926,6 +926,28 @@ static struct command **queue_command(struct command **tail,
 	return &cmd->next;
 }
 
+static void queue_commands_from_cert(struct command **tail,
+				     struct strbuf *push_cert)
+{
+	const char *boc, *eoc;
+
+	if (*tail)
+		die("protocol error: got both push certificate and unsigned commands");
+
+	boc = strstr(push_cert->buf, "\n\n");
+	if (!boc)
+		die("malformed push certificate %.*s", 100, push_cert->buf);
+	else
+		boc += 2;
+	eoc = push_cert->buf + parse_signature(push_cert->buf, push_cert->len);
+
+	while (boc < eoc) {
+		const char *eol = memchr(boc, '\n', eoc - boc);
+		tail = queue_command(tail, boc, eol ? eol - boc : eoc - eol);
+		boc = eol ? eol + 1 : eoc;
+	}
+}
+
 static struct command *read_head_info(struct sha1_array *shallow)
 {
 	struct command *commands = NULL;
@@ -981,6 +1003,10 @@ static struct command *read_head_info(struct sha1_array *shallow)
 
 		p = queue_command(p, line, linelen);
 	}
+
+	if (push_cert.len)
+		queue_commands_from_cert(p, &push_cert);
+
 	return commands;
 }
 
diff --git a/send-pack.c b/send-pack.c
index d392f5b..857beb3 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -363,7 +363,7 @@ int send_pack(struct send_pack_args *args,
 	for (ref = remote_refs; ref; ref = ref->next) {
 		char *old_hex, *new_hex;
 
-		if (args->dry_run)
+		if (args->dry_run || args->push_cert)
 			continue;
 
 		if (!ref_update_to_be_sent(ref, args))
-- 
2.1.0-399-g2df620b
Previous: Junio C HamanoNext: Junio C Hamano
Message 20 of 23 in “Signed push”
  1. 00/22 Signed pushJunio C Hamano, Sep 5, 2014
  2. 01/22 receive-pack: do not overallocate command structureJunio C Hamano, Sep 5, 2014
  3. 02/22 receive-pack: parse feature request a bit earlierJunio C Hamano, Sep 5, 2014
  4. 03/22 receive-pack: do not reuse old_sha1[] for other thingsJunio C Hamano, Sep 5, 2014
  5. 04/22 receive-pack: factor out queueing of commandJunio C Hamano, Sep 5, 2014
  6. 05/22 send-pack: move REF_STATUS_REJECT_NODELETE logic a bit higherJunio C Hamano, Sep 5, 2014
  7. 06/22 send-pack: refactor decision to send update per refJunio C Hamano, Sep 5, 2014
  8. 07/22 send-pack: always send capabilitiesJunio C Hamano, Sep 5, 2014
  9. 08/22 send-pack: factor out capability string generationJunio C Hamano, Sep 5, 2014
  10. 09/22 receive-pack: factor out capability string generationJunio C Hamano, Sep 5, 2014
  11. 10/22 send-pack: rename "new_refs" to "need_pack_data"Junio C Hamano, Sep 5, 2014
  12. 11/22 send-pack: refactor inspecting and resetting status and sending commandsJunio C Hamano, Sep 5, 2014
  13. 12/22 send-pack: clarify that cmds_sent is a booleanJunio C Hamano, Sep 5, 2014
  14. 13/22 gpg-interface: move parse_gpg_output() to where it should beJunio C Hamano, Sep 5, 2014
  15. 14/22 gpg-interface: move parse_signature() to where it should beJunio C Hamano, Sep 5, 2014
  16. 15/22 pack-protocol doc: typofix for PKT-LINEJunio C Hamano, Sep 5, 2014
  17. 16/22 push: the beginning of "git push --signed"Junio C Hamano, Sep 5, 2014
  18. 17/22 receive-pack: GPG-validate push certificatesJunio C Hamano, Sep 5, 2014
  19. 18/22 send-pack: send feature request on push-cert packetJunio C Hamano, Sep 5, 2014
  20. 19/22 signed push: remove duplicated protocol infoJunio C Hamano, Sep 5, 2014
  21. 20/22 signed push: add "pushee" header to push certificateJunio C Hamano, Sep 5, 2014
  22. 21/22 signed push: fortify against replay attacksJunio C Hamano, Sep 5, 2014
  23. 22/22 signed push: allow stale nonce in stateless modeJunio C Hamano, Sep 5, 2014

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.