Skip to content

Commit 4adf569

Browse files
committed
signed push: remove duplicated protocol info
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 <[email protected]>
1 parent 20a7558 commit 4adf569

File tree

4 files changed

+69
-4
lines changed

4 files changed

+69
-4
lines changed

Documentation/technical/pack-protocol.txt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ contain all the objects that the server will need to complete the new
465465
references.
466466

467467
----
468-
update-request = *shallow command-list [pack-file]
468+
update-request = *shallow ( command-list | push-cert ) [pack-file]
469469

470470
shallow = PKT-LINE("shallow" SP obj-id)
471471

@@ -481,12 +481,25 @@ references.
481481
old-id = obj-id
482482
new-id = obj-id
483483

484+
push-cert = PKT-LINE("push-cert" NUL capability-list LF)
485+
PKT-LINE("certificate version 0.1" LF)
486+
PKT-LINE("pusher" SP ident LF)
487+
PKT-LINE(LF)
488+
*PKT-LINE(command LF)
489+
*PKT-LINE(gpg-signature-lines LF)
490+
PKT-LINE("push-cert-end" LF)
491+
484492
pack-file = "PACK" 28*(OCTET)
485493
----
486494

487495
If the receiving end does not support delete-refs, the sending end MUST
488496
NOT ask for delete command.
489497

498+
If the receiving end does not support push-cert, the sending end
499+
MUST NOT send a push-cert command. When a push-cert command is
500+
sent, command-list MUST NOT be sent; the commands recorded in the
501+
push certificate is used instead.
502+
490503
The pack-file MUST NOT be sent if the only command used is 'delete'.
491504

492505
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
501514
it will run any update hooks to make sure that the update is acceptable.
502515
If all of that is fine, the server will then update the references.
503516

517+
Push Certificate
518+
----------------
519+
520+
A push certificate begins with a set of header lines. After the
521+
header and an empty line, the protocol commands follow, one per
522+
line.
523+
524+
Currently, the following header fields are defined:
525+
526+
`pusher` ident::
527+
Identify the GPG key in "Human Readable Name <email@address>"
528+
format.
529+
530+
The GPG signature lines are a detached signature for the contents
531+
recorded in the push certificate before the signature block begins.
532+
The detached signature is used to certify that the commands were
533+
given by the pusher, who must be the signer.
534+
504535
Report Status
505536
-------------
506537

Documentation/technical/protocol-capabilities.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ was sent. Server MUST NOT ignore capabilities that client requested
1818
and server advertised. As a consequence of these rules, server MUST
1919
NOT advertise capabilities it does not understand.
2020

21-
The 'report-status', 'delete-refs', and 'quiet' capabilities are sent and
22-
recognized by the receive-pack (push to server) process.
21+
The 'report-status', 'delete-refs', 'quiet', and 'push-cert' capabilities
22+
are sent and recognized by the receive-pack (push to server) process.
2323

2424
The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
2525
by both upload-pack and receive-pack protocols. The 'agent' capability
@@ -250,3 +250,11 @@ allow-tip-sha1-in-want
250250
If the upload-pack server advertises this capability, fetch-pack may
251251
send "want" lines with SHA-1s that exist at the server but are not
252252
advertised by upload-pack.
253+
254+
push-cert
255+
---------
256+
257+
The receive-pack server that advertises this capability is willing
258+
to accept a signed push certificate. A send-pack client MUST NOT
259+
send a push-cert packet unless the receive-pack server advertises
260+
this capability.

builtin/receive-pack.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,28 @@ static struct command **queue_command(struct command **tail,
926926
return &cmd->next;
927927
}
928928

929+
static void queue_commands_from_cert(struct command **tail,
930+
struct strbuf *push_cert)
931+
{
932+
const char *boc, *eoc;
933+
934+
if (*tail)
935+
die("protocol error: got both push certificate and unsigned commands");
936+
937+
boc = strstr(push_cert->buf, "\n\n");
938+
if (!boc)
939+
die("malformed push certificate %.*s", 100, push_cert->buf);
940+
else
941+
boc += 2;
942+
eoc = push_cert->buf + parse_signature(push_cert->buf, push_cert->len);
943+
944+
while (boc < eoc) {
945+
const char *eol = memchr(boc, '\n', eoc - boc);
946+
tail = queue_command(tail, boc, eol ? eol - boc : eoc - eol);
947+
boc = eol ? eol + 1 : eoc;
948+
}
949+
}
950+
929951
static struct command *read_head_info(struct sha1_array *shallow)
930952
{
931953
struct command *commands = NULL;
@@ -981,6 +1003,10 @@ static struct command *read_head_info(struct sha1_array *shallow)
9811003

9821004
p = queue_command(p, line, linelen);
9831005
}
1006+
1007+
if (push_cert.len)
1008+
queue_commands_from_cert(p, &push_cert);
1009+
9841010
return commands;
9851011
}
9861012

send-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ int send_pack(struct send_pack_args *args,
363363
for (ref = remote_refs; ref; ref = ref->next) {
364364
char *old_hex, *new_hex;
365365

366-
if (args->dry_run)
366+
if (args->dry_run || args->push_cert)
367367
continue;
368368

369369
if (!ref_update_to_be_sent(ref, args))

0 commit comments

Comments
 (0)