Skip to content

Commit

Permalink
signed push: remove duplicated protocol info
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Junio C Hamano committed Sep 15, 2014
1 parent 20a7558 commit 4adf569
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
33 changes: 32 additions & 1 deletion Documentation/technical/pack-protocol.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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,
Expand All @@ -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
-------------

Expand Down
12 changes: 10 additions & 2 deletions Documentation/technical/protocol-capabilities.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
26 changes: 26 additions & 0 deletions builtin/receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion send-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit 4adf569

Please sign in to comment.