Re: [PATCH 18/18] signed push: final protocol update

2014-09-04 Thread Junio C Hamano
Shawn Pearce spea...@spearce.org writes:

 As you know, the stateless HTTP thing doesn't allow the nonce on the
 server to be carried from the initial ref advertisement into the final
 receive-pack. We would either need to write the nonce to disk and load
 it back up later (ick), or use some sort of stateless nonce.

 A stateless nonce could look like:

   nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

 where site_key is a private key known to the server. It doesn't have
 to be per-repo.

Doing the above naively will force you to check 600 HMAC if your
slack is for 10 minutes.  You could just instead use

nonce = now '-' HMAC_SHA1(path + '.' + now, site_key)

and the validation side can make sure the same site_key was used,
and also now readable from the plaintext part is fresh enough,
with a single HMAC.

I may be missing something, but with this, we can always validate
that nonce is what the repository issued (whether stateless is
used or not).  The hook script can decide if now is recent enough
or not without bothering receive-pack at all.



--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-09-04 Thread Shawn Pearce
On Thu, Sep 4, 2014 at 4:57 PM, Junio C Hamano gits...@pobox.com wrote:
 Shawn Pearce spea...@spearce.org writes:

 As you know, the stateless HTTP thing doesn't allow the nonce on the
 server to be carried from the initial ref advertisement into the final
 receive-pack. We would either need to write the nonce to disk and load
 it back up later (ick), or use some sort of stateless nonce.

 A stateless nonce could look like:

   nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

 where site_key is a private key known to the server. It doesn't have
 to be per-repo.

 Doing the above naively will force you to check 600 HMAC if your
 slack is for 10 minutes.  You could just instead use

 nonce = now '-' HMAC_SHA1(path + '.' + now, site_key)

 and the validation side can make sure the same site_key was used,
 and also now readable from the plaintext part is fresh enough,
 with a single HMAC.

Argh. Yes, thank you. This is what I meant but did not write. :(

 I may be missing something, but with this, we can always validate
 that nonce is what the repository issued (whether stateless is
 used or not).  The hook script can decide if now is recent enough
 or not without bothering receive-pack at all.

Correct.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-26 Thread Shawn Pearce
On Mon, Aug 25, 2014 at 10:59 AM, Junio C Hamano gits...@pobox.com wrote:
 Shawn Pearce spea...@spearce.org writes:

 A stateless nonce could look like:

   nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

 where site_key is a private key known to the server. It doesn't have
 to be per-repo.

 receive-pack would then be willing to accept any nonce whose timestamp
 is within a window, e.g. 10 minutes of the current time, and whose
 signature verifies in the HMAC. The 10 minute window is important to
 allow clients time to generate the object list, perform delta
 compression, and begin transmitting to the server.

 Hmph, don't you send the finally tell the other end the sequence
 of update this ref from old to new and the packdata separately?

No. The command list (triples of old, new, ref) is sent in the same
HTTP request as the pack data, ahead of the pack data. So its one
request.

Push on smart HTTP is 3 HTTP requests:

  1)  get advertisement
  2)  POST empty flush packet to tickle auth (literally just ).
  3)  POST command list + pack

The nonce can be sent server-client in 1, and client-server in 3.

  I
 think we have a FLUSH in between, and the push certificate is given
 before the FLUSH, which you do not have to wait for 10 minutes.

Nope I think you need to wait for the pack to generate enough to start
sending the pack data stream. Nothing forces the smart HTTP client to
push its pending buffer out. We wait for the pack data to either
finish, or overflow the in-memory buffer, and then start transmitting.
If your client needs a lot of time for counting and delta compression,
we aren't likely to overflow and transmit for a while.

If you send a _lot_ of refs you can overflow, which will cause us to
transmit early. But we are talking about megabytes worth of (old, new,
ref) triplets to reach that overflow point.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-26 Thread Junio C Hamano
Shawn Pearce spea...@spearce.org writes:

 On Mon, Aug 25, 2014 at 10:59 AM, Junio C Hamano gits...@pobox.com wrote:
 Shawn Pearce spea...@spearce.org writes:

 A stateless nonce could look like:

   nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

 where site_key is a private key known to the server. It doesn't have
 to be per-repo.

 receive-pack would then be willing to accept any nonce whose timestamp
 is within a window, e.g. 10 minutes of the current time, and whose
 signature verifies in the HMAC. The 10 minute window is important to
 allow clients time to generate the object list, perform delta
 compression, and begin transmitting to the server.

 Hmph, don't you send the finally tell the other end the sequence
 of update this ref from old to new and the packdata separately?

 No. The command list (triples of old, new, ref) is sent in the same
 HTTP request as the pack data, ahead of the pack data. So its one
 request.

That is unfortunate.  Would it be a major surgery to update the
protocol not to do that, perhaps by moving the command list from 3
to 2 (the latter of which is not currently doing anything useful
payload-wise, other than flushing a HTTP request early)?

 Push on smart HTTP is 3 HTTP requests:

   1)  get advertisement
   2)  POST empty flush packet to tickle auth (literally just ).
   3)  POST command list + pack

 The nonce can be sent server-client in 1, and client-server in 3.

  I
 think we have a FLUSH in between, and the push certificate is given
 before the FLUSH, which you do not have to wait for 10 minutes.

 Nope I think you need to wait for the pack to generate enough to start
 sending the pack data stream. Nothing forces the smart HTTP client to
 push its pending buffer out. We wait for the pack data to either
 finish, or overflow the in-memory buffer, and then start transmitting.
 If your client needs a lot of time for counting and delta compression,
 we aren't likely to overflow and transmit for a while.

 If you send a _lot_ of refs you can overflow, which will cause us to
 transmit early. But we are talking about megabytes worth of (old, new,
 ref) triplets to reach that overflow point.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-26 Thread Junio C Hamano
Junio C Hamano gits...@pobox.com writes:

 That is unfortunate.  Would it be a major surgery to update the
 protocol not to do that, perhaps by moving the command list from 3
 to 2 (the latter of which is not currently doing anything useful
 payload-wise, other than flushing a HTTP request early)?

Nah, that was one of the most stupid thing I ever said here X.
There is nothing that ties #2 and #3 unless the server side keeps
some state, so that would not work very well X-.


 Push on smart HTTP is 3 HTTP requests:

   1)  get advertisement
   2)  POST empty flush packet to tickle auth (literally just ).
   3)  POST command list + pack
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-25 Thread Junio C Hamano
Shawn Pearce spea...@spearce.org writes:

 A stateless nonce could look like:

   nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

 where site_key is a private key known to the server. It doesn't have
 to be per-repo.

 receive-pack would then be willing to accept any nonce whose timestamp
 is within a window, e.g. 10 minutes of the current time, and whose
 signature verifies in the HMAC. The 10 minute window is important to
 allow clients time to generate the object list, perform delta
 compression, and begin transmitting to the server.

Hmph, don't you send the finally tell the other end the sequence
of update this ref from old to new and the packdata separately?  I
think we have a FLUSH in between, and the push certificate is given
before the FLUSH, which you do not have to wait for 10 minutes.

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-22 Thread Junio C Hamano
Junio C Hamano gits...@pobox.com writes:

 There are a few gotchas I can certainly use help on, especially from
 a smart-http expert ;-).

  * pushed-to URL will identify the site and the repository, so
you cannot MITM my push to an experimental server and replay it
against the authoritative server.

However, the receiving end may not even know what name its users
call the repository being pushed into.  Obviously gethostname()
may not be what the pusher called us, and getcwd() may not match
the repository name without leading /var/repos/shard3/ path
components stripped, for example.

I am not sure if we even have the necessary information at
send-pack.c::send_pack() level, where it already has an
established connection to the server (hence it does not need to
know to whom it is talking to).


  * The receiving end will issue push-cert=nonce in its initial
capability advertisement, and this nonce will be given on the
PUSH_CERT_NONCE environment to the pre/post-receive hooks, to
allow the nonce nonce header in the signed certificate to be
checked against it.  You cannot capture my an earlier push to the
authoritative server and replay it later.

That would all work well within a single receive-pack process,
but with stateless RPC, it is unclear to me how we should
arrange the nonce the initial instance of receive-pack placed
on its capability advertisement to be securely passed to the
instance of receive-pack that actually receives the push
certificate.

A good nonce may be something like taking the SHA-1 hash of the
concatenation of the sitename, repo-path and the timestamp when the
receive-pack generated the nonce.  Replaying a push certificate
for a push to a repository at a site that gives such a nonce can
succeed at the same chance of finding a SHA-1 collision [*1*].  As
long as you exercise good hygiene and only push to repositories that
give such nonce, we can do without checking pushed-to that says
where the push went.

So nonce nonce is the only thing that is necessary to make them
impossible to replay.  For auditing purposes, pushed-to URL that
records the repository the pusher intended to push to may help but
probably not necessary [*2*].


[Footnote]

*1* And the old-sha1s recorded in the certificate has to match what
the repository being attacked currently has; otherwise the push
will fail with the ref moved while you were trying to push.

*2* When auditing the history for a repository at a site, the
certificate the auditors examine would be the ones accumulated
at that site for the repository, so we would implicitly know the
value for URL already.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-22 Thread Shawn Pearce
On Fri, Aug 22, 2014 at 10:59 AM, Junio C Hamano gits...@pobox.com wrote:
 Junio C Hamano gits...@pobox.com writes:

 There are a few gotchas I can certainly use help on, especially from
 a smart-http expert ;-).

  * pushed-to URL will identify the site and the repository, so
you cannot MITM my push to an experimental server and replay it
against the authoritative server.

However, the receiving end may not even know what name its users
call the repository being pushed into.  Obviously gethostname()
may not be what the pusher called us, and getcwd() may not match
the repository name without leading /var/repos/shard3/ path
components stripped, for example.

I am not sure if we even have the necessary information at
send-pack.c::send_pack() level, where it already has an
established connection to the server (hence it does not need to
know to whom it is talking to).


  * The receiving end will issue push-cert=nonce in its initial
capability advertisement, and this nonce will be given on the
PUSH_CERT_NONCE environment to the pre/post-receive hooks, to
allow the nonce nonce header in the signed certificate to be
checked against it.  You cannot capture my an earlier push to the
authoritative server and replay it later.

That would all work well within a single receive-pack process,
but with stateless RPC, it is unclear to me how we should
arrange the nonce the initial instance of receive-pack placed
on its capability advertisement to be securely passed to the
instance of receive-pack that actually receives the push
certificate.

 A good nonce may be something like taking the SHA-1 hash of the
 concatenation of the sitename, repo-path and the timestamp when the
 receive-pack generated the nonce.  Replaying a push certificate
 for a push to a repository at a site that gives such a nonce can
 succeed at the same chance of finding a SHA-1 collision [*1*].  As
 long as you exercise good hygiene and only push to repositories that
 give such nonce, we can do without checking pushed-to that says
 where the push went.

Yes, this is an interesting solution.

As you know, the stateless HTTP thing doesn't allow the nonce on the
server to be carried from the initial ref advertisement into the final
receive-pack. We would either need to write the nonce to disk and load
it back up later (ick), or use some sort of stateless nonce.

A stateless nonce could look like:

  nonce = HMAC_SHA1( SHA1(site+path) + '.' + now, site_key )

where site_key is a private key known to the server. It doesn't have
to be per-repo.

receive-pack would then be willing to accept any nonce whose timestamp
is within a window, e.g. 10 minutes of the current time, and whose
signature verifies in the HMAC. The 10 minute window is important to
allow clients time to generate the object list, perform delta
compression, and begin transmitting to the server.

 So nonce nonce is the only thing that is necessary to make them
 impossible to replay.  For auditing purposes, pushed-to URL that
 records the repository the pusher intended to push to may help but
 probably not necessary [*2*].

So pushed-to is still useful as a documentation/historical artifact,
but isn't important for verifying the certificate. That fixes a lot of
problems with repositories having different paths under e.g. git://
vs. ssh:// vs. https:// on the same host.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-21 Thread Shawn Pearce
On Tue, Aug 19, 2014 at 3:06 PM, Junio C Hamano gits...@pobox.com wrote:

 +  push-cert = PKT-LINE(push-cert NUL capability-list LF)

Haha. NUL.  I love our wire protocol.

 + PKT-LINE(certificate version 0.1 LF)
 + PKT-LINE(pusher ident LF)
 + PKT-LINE(LF)
 + *PKT-LINE(command LF)
 + *PKT-LINE(GPG signature lines LF)

Should we include the URL as part of this certificate?

Perhaps the pusher means to sign the master branch of experimental
tree, but not their trunk tree?
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-21 Thread Junio C Hamano
Shawn Pearce spea...@spearce.org writes:

 On Tue, Aug 19, 2014 at 3:06 PM, Junio C Hamano gits...@pobox.com wrote:

 +  push-cert = PKT-LINE(push-cert NUL capability-list LF)

 Haha. NUL.  I love our wire protocol.

 + PKT-LINE(certificate version 0.1 LF)
 + PKT-LINE(pusher ident LF)
 + PKT-LINE(LF)
 + *PKT-LINE(command LF)
 + *PKT-LINE(GPG signature lines LF)

 Should we include the URL as part of this certificate?

 Perhaps the pusher means to sign the master branch of experimental
 tree, but not their trunk tree?

Yes, in $gmane/255582 I cover this and also mention that we would
need some nonce from the receiving end to make it harder to
replay.

Currently I am leaning toward to add both pushed-to URL and also
nonce nonce, the latter of which the receiver can ask with
push-cert=nonce in its initial capability advertisement.

There are a few gotchas I can certainly use help on, especially from
a smart-http expert ;-).

 * pushed-to URL will identify the site and the repository, so
   you cannot MITM my push to an experimental server and replay it
   against the authoritative server.

   However, the receiving end may not even know what name its users
   call the repository being pushed into.  Obviously gethostname()
   may not be what the pusher called us, and getcwd() may not match
   the repository name without leading /var/repos/shard3/ path
   components stripped, for example.

   I am not sure if we even have the necessary information at
   send-pack.c::send_pack() level, where it already has an
   established connection to the server (hence it does not need to
   know to whom it is talking to).


 * The receiving end will issue push-cert=nonce in its initial
   capability advertisement, and this nonce will be given on the
   PUSH_CERT_NONCE environment to the pre/post-receive hooks, to
   allow the nonce nonce header in the signed certificate to be
   checked against it.  You cannot capture my an earlier push to the
   authoritative server and replay it later.

   That would all work well within a single receive-pack process,
   but with stateless RPC, it is unclear to me how we should
   arrange the nonce the initial instance of receive-pack placed
   on its capability advertisement to be securely passed to the
   instance of receive-pack that actually receives the push
   certificate.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-21 Thread David Turner
On Tue, 2014-08-19 at 15:06 -0700, Junio C Hamano wrote:
  
 +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 GPG
 +signature lines are detached signature for the contents recorded in

are a detached signature

 +the push certificate before the signature block begins and is used

which is used (or and are used)

 +to certify that the commands were given by the pusher which must be

, who must be

 +the signer.
 +
 +
 +The receive-pack server that advertises this capability is willing
 +to accept a signed push certificate.  A send-pack client MUST NOT
 +send push-cert packet unless the receive-pack server advertises this

packets (or a push-cert packet)

  
 +static void queue_commands_from_cert(struct command **p,

Uninformative parameter name p.

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-21 Thread Kyle J. McKay

On Aug 21, 2014, at 16:40, Junio C Hamano wrote:


* The receiving end will issue push-cert=nonce in its initial
  capability advertisement, and this nonce will be given on the
  PUSH_CERT_NONCE environment to the pre/post-receive hooks, to
  allow the nonce nonce header in the signed certificate to be
  checked against it.  You cannot capture my an earlier push to the
  authoritative server and replay it later.

  That would all work well within a single receive-pack process,
  but with stateless RPC, it is unclear to me how we should
  arrange the nonce the initial instance of receive-pack placed
  on its capability advertisement to be securely passed to the
  instance of receive-pack that actually receives the push
  certificate.


Have you considered having the advertised nonce only be updated after  
receipt of a successful signed push?


It would eliminate the stateless issue.  And since the next nonce to  
be advertised would be updated at the successful completion of a  
receive of a signed push no replay would be possible.  (I'm assuming  
that receive hook activity is already pipelined in the case of  
simultaneous pushes via some lock file or something or this scheme  
falls apart.)


The obvious downside is that only one of two or more simultaneous  
signed pushers could succeed.  But the sender could be modified to  
automatically retry (a limited number of times) on a nonce mismatch  
error.


A receive hook could also be responsible for generating the next nonce  
value using this technique.

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 18/18] signed push: final protocol update

2014-08-21 Thread Junio C Hamano
On Thu, Aug 21, 2014 at 12:28 PM, Shawn Pearce spea...@spearce.org wrote:
 On Tue, Aug 19, 2014 at 3:06 PM, Junio C Hamano gits...@pobox.com wrote:

 +  push-cert = PKT-LINE(push-cert NUL capability-list LF)

 Haha. NUL.  I love our wire protocol.

It is a direct and natural consequence of [PATCH 02/18].

We could use SP here, if we really wanted to, but that would make the
push-cert packet a special kind that is different from others, which we
would want to avoid. shallow is already special in that it cannot even
carry the feature request, and it is not worth introducing and advertising
a new capability to fix it, but at least we can avoid making the same
mistake here.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 18/18] signed push: final protocol update

2014-08-19 Thread Junio C Hamano
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.

Signed-off-by: Junio C Hamano gits...@pobox.com
---
 Documentation/technical/pack-protocol.txt | 20 -
 Documentation/technical/protocol-capabilities.txt | 12 +--
 builtin/receive-pack.c| 26 +++
 send-pack.c   |  2 +-
 4 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/Documentation/technical/pack-protocol.txt 
b/Documentation/technical/pack-protocol.txt
index a845d51..f6c3073 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,30 @@ 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 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 GPG
+signature lines are detached signature for the contents recorded in
+the push certificate before the signature block begins and is used
+to certify that the commands were given by the pusher which must be
+the signer.
+
 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,
diff --git a/Documentation/technical/protocol-capabilities.txt 
b/Documentation/technical/protocol-capabilities.txt
index e174343..5b398e9 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 push-cert packet unless the receive-pack server advertises this
+capability.
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index abdc296..96e4c99 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -907,6 +907,28 @@ static struct command **queue_command(struct command **p,
return cmd-next;
 }
 
+static void queue_commands_from_cert(struct command **p,
+struct strbuf *push_cert)
+{
+   const char *boc, *eoc;
+
+   if (*p)
+   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);
+   p = queue_command(p, boc, eol ? eol - boc : eoc - eol);
+   boc =