diff options
author | Junio C Hamano <gitster@pobox.com> | 2014-08-14 15:59:21 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-08-15 13:14:34 -0700 |
commit | a3ac15ca7d1457c9ec947c45f2942afe2d8f4a04 (patch) | |
tree | dc2e383d424fcabc72db10f43f5814f85db81894 | |
parent | 399b4cfd7c9ab5792dade8b0ba549c067a766a15 (diff) | |
download | git-jc/push-cert-2.tar.gz |
receive-pack: GPG-validate push certificatesjc/push-cert-2
Reusing the GPG signature check helpers we already have, verify
the signature in receive-pack and give the results to the hooks
via GIT_PUSH_CERT_{SIGNER,KEY,STATUS} environment variables.
Policy decisions, such as accepting or rejecting a good signature by
a key that is not fully trusted, is left to the hook and kept
outside of the core.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | builtin/receive-pack.c | 29 | ||||
-rwxr-xr-x | t/t5534-push-signed.sh | 18 |
2 files changed, 45 insertions, 2 deletions
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 469e344ea0..1577aacfbc 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -15,6 +15,8 @@ #include "connected.h" #include "argv-array.h" #include "version.h" +#include "tag.h" +#include "gpg-interface.h" static const char receive_pack_usage[] = "git receive-pack <git-dir>"; @@ -48,6 +50,7 @@ static int shallow_update; static const char *alt_shallow_file; static struct strbuf push_cert = STRBUF_INIT; static unsigned char push_cert_sha1[20]; +static struct signature_check sigcheck; static enum deny_action parse_deny_action(const char *var, const char *value) { @@ -260,12 +263,38 @@ static void prepare_push_cert_sha1(struct child_process *proc) struct argv_array env = ARGV_ARRAY_INIT; if (!already_done) { + struct strbuf gpg_output = STRBUF_INIT; + struct strbuf gpg_status = STRBUF_INIT; + int bogs /* beginning_of_gpg_sig */; + already_done = 1; if (write_sha1_file(push_cert.buf, push_cert.len, "blob", push_cert_sha1)) hashclr(push_cert_sha1); + + memset(&sigcheck, '\0', sizeof(sigcheck)); + sigcheck.result = 'N'; + + bogs = parse_signature(push_cert.buf, push_cert.len); + if (verify_signed_buffer(push_cert.buf, bogs, + push_cert.buf + bogs, push_cert.len - bogs, + &gpg_output, &gpg_status) < 0) { + ; /* error running gpg */ + } else { + sigcheck.payload = push_cert.buf; + sigcheck.gpg_output = gpg_output.buf; + sigcheck.gpg_status = gpg_status.buf; + parse_gpg_output(&sigcheck); + } + + strbuf_release(&gpg_output); + strbuf_release(&gpg_status); } if (!is_null_sha1(push_cert_sha1)) { argv_array_pushf(&env, "GIT_PUSH_CERT=%s", sha1_to_hex(push_cert_sha1)); + argv_array_pushf(&env, "GIT_PUSH_CERT_SIGNER=%s", sigcheck.signer); + argv_array_pushf(&env, "GIT_PUSH_CERT_KEY=%s", sigcheck.key); + argv_array_pushf(&env, "GIT_PUSH_CERT_STATUS=%c", sigcheck.result); + proc->env = env.argv; } } diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh index 9ee5c29cc8..3acc8648f1 100755 --- a/t/t5534-push-signed.sh +++ b/t/t5534-push-signed.sh @@ -52,13 +52,27 @@ test_expect_success 'signed push sends push certificate' ' if test -n "${GIT_PUSH_CERT-}" then git cat-file blob $GIT_PUSH_CERT >../push-cert - fi + fi && + + cat >../push-cert-status <<E_O_F + SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} + KEY=${GIT_PUSH_CERT_KEY-nokey} + STATUS=${GIT_PUSH_CERT_STATUS-nostatus} + E_O_F + + EOF + + cat >expect <<-\EOF && + SIGNER=C O Mitter <committer@example.com> + KEY=13B6F51ECDDE430D + STATUS=G EOF git push --signed dst noop ff +noff && grep "update $(git rev-parse noop ff) refs/heads/ff" dst/push-cert && - grep "update $(git rev-parse noop noff) refs/heads/noff" dst/push-cert + grep "update $(git rev-parse noop noff) refs/heads/noff" dst/push-cert && + test_cmp expect dst/push-cert-status ' test_done |