summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-08-14 15:59:21 -0700
committerJunio C Hamano <gitster@pobox.com>2014-08-15 13:14:34 -0700
commita3ac15ca7d1457c9ec947c45f2942afe2d8f4a04 (patch)
treedc2e383d424fcabc72db10f43f5814f85db81894
parent399b4cfd7c9ab5792dade8b0ba549c067a766a15 (diff)
downloadgit-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.c29
-rwxr-xr-xt/t5534-push-signed.sh18
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