receive-pack: GPG-validate push certificates
[gitweb.git] / builtin / receive-pack.c
index 610b085e3d88a4ca07132b1e991222179eaae276..c0a31899431d39f37051b91ebc42bf418c49df0e 100644 (file)
@@ -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>";
 
@@ -49,6 +51,7 @@ static const char *alt_shallow_file;
 static int accept_push_cert = 1;
 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)
 {
@@ -277,12 +280,40 @@ static void prepare_push_cert_sha1(struct child_process *proc)
                return;
 
        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 ? sigcheck.signer : "");
+               argv_array_pushf(&env, "GIT_PUSH_CERT_KEY=%s",
+                                sigcheck.key ? sigcheck.key : "");
+               argv_array_pushf(&env, "GIT_PUSH_CERT_STATUS=%c", sigcheck.result);
+
                proc->env = env.argv;
        }
 }