Merge branch 'jc/gpg-status'
authorJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:50 +0000 (11:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:50 +0000 (11:33 -0700)
"git verify-tag" and "git verify-commit" have been taught to use
the exit status of underlying "gpg --verify" to signal bad or
untrusted signature they found.

* jc/gpg-status:
  gpg-interface: propagate exit status from gpg back to the callers

1  2 
gpg-interface.c

diff --combined gpg-interface.c
@@@ -7,64 -7,10 +7,64 @@@
  #include "tempfile.h"
  
  static char *configured_signing_key;
 -static const char *gpg_program = "gpg";
 +struct gpg_format {
 +      const char *name;
 +      const char *program;
 +      const char **verify_args;
 +      const char **sigs;
 +};
 +
 +static const char *openpgp_verify_args[] = {
 +      "--keyid-format=long",
 +      NULL
 +};
 +static const char *openpgp_sigs[] = {
 +      "-----BEGIN PGP SIGNATURE-----",
 +      "-----BEGIN PGP MESSAGE-----",
 +      NULL
 +};
 +
 +static const char *x509_verify_args[] = {
 +      NULL
 +};
 +static const char *x509_sigs[] = {
 +      "-----BEGIN SIGNED MESSAGE-----",
 +      NULL
 +};
  
 -#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
 -#define PGP_MESSAGE "-----BEGIN PGP MESSAGE-----"
 +static struct gpg_format gpg_format[] = {
 +      { .name = "openpgp", .program = "gpg",
 +        .verify_args = openpgp_verify_args,
 +        .sigs = openpgp_sigs
 +      },
 +      { .name = "x509", .program = "gpgsm",
 +        .verify_args = x509_verify_args,
 +        .sigs = x509_sigs
 +      },
 +};
 +
 +static struct gpg_format *use_format = &gpg_format[0];
 +
 +static struct gpg_format *get_format_by_name(const char *str)
 +{
 +      int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
 +              if (!strcmp(gpg_format[i].name, str))
 +                      return gpg_format + i;
 +      return NULL;
 +}
 +
 +static struct gpg_format *get_format_by_sig(const char *sig)
 +{
 +      int i, j;
 +
 +      for (i = 0; i < ARRAY_SIZE(gpg_format); i++)
 +              for (j = 0; gpg_format[i].sigs[j]; j++)
 +                      if (starts_with(sig, gpg_format[i].sigs[j]))
 +                              return gpg_format + i;
 +      return NULL;
 +}
  
  void signature_check_clear(struct signature_check *sigc)
  {
@@@ -89,7 -35,7 +89,7 @@@ static struct 
        { 'R', "\n[GNUPG:] REVKEYSIG "},
  };
  
 -void parse_gpg_output(struct signature_check *sigc)
 +static void parse_gpg_output(struct signature_check *sigc)
  {
        const char *buf = sigc->gpg_status;
        int i;
                sigc->result = sigcheck_gpg_status[i].result;
                /* The trust messages are not followed by key/signer information */
                if (sigc->result != 'U') {
 -                      sigc->key = xmemdupz(found, 16);
 +                      next = strchrnul(found, ' ');
 +                      sigc->key = xmemdupz(found, next - found);
                        /* The ERRSIG message is not followed by signer information */
 -                      if (sigc-> result != 'E') {
 -                              found += 17;
 +                      if (*next && sigc-> result != 'E') {
 +                              found = next + 1;
                                next = strchrnul(found, '\n');
                                sigc->signer = xmemdupz(found, next - found);
                        }
@@@ -136,12 -81,13 +136,13 @@@ int check_signature(const char *payload
        sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
        sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
        parse_gpg_output(sigc);
+       status |= sigc->result != 'G' && sigc->result != 'U';
  
   out:
        strbuf_release(&gpg_status);
        strbuf_release(&gpg_output);
  
-       return sigc->result != 'G' && sigc->result != 'U';
+       return !!status;
  }
  
  void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
                fputs(output, stderr);
  }
  
 -static int is_gpg_start(const char *line)
 -{
 -      return starts_with(line, PGP_SIGNATURE) ||
 -              starts_with(line, PGP_MESSAGE);
 -}
 -
  size_t parse_signature(const char *buf, size_t size)
  {
        size_t len = 0;
        while (len < size) {
                const char *eol;
  
 -              if (is_gpg_start(buf + len))
 +              if (get_format_by_sig(buf + len))
                        match = len;
  
                eol = memchr(buf + len, '\n', size - len);
@@@ -180,9 -132,6 +181,9 @@@ void set_signing_key(const char *key
  
  int git_gpg_config(const char *var, const char *value, void *cb)
  {
 +      struct gpg_format *fmt = NULL;
 +      char *fmtname = NULL;
 +
        if (!strcmp(var, "user.signingkey")) {
                if (!value)
                        return config_error_nonbool(var);
                return 0;
        }
  
 -      if (!strcmp(var, "gpg.program")) {
 +      if (!strcmp(var, "gpg.format")) {
                if (!value)
                        return config_error_nonbool(var);
 -              gpg_program = xstrdup(value);
 +              fmt = get_format_by_name(value);
 +              if (!fmt)
 +                      return error("unsupported value for %s: %s",
 +                                   var, value);
 +              use_format = fmt;
                return 0;
        }
  
 +      if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
 +              fmtname = "openpgp";
 +
 +      if (!strcmp(var, "gpg.x509.program"))
 +              fmtname = "x509";
 +
 +      if (fmtname) {
 +              fmt = get_format_by_name(fmtname);
 +              return git_config_string(&fmt->program, var, value);
 +      }
 +
        return 0;
  }
  
@@@ -230,7 -164,7 +231,7 @@@ int sign_buffer(struct strbuf *buffer, 
        struct strbuf gpg_status = STRBUF_INIT;
  
        argv_array_pushl(&gpg.args,
 -                       gpg_program,
 +                       use_format->program,
                         "--status-fd=2",
                         "-bsau", signing_key,
                         NULL);
@@@ -268,7 -202,6 +269,7 @@@ int verify_signed_buffer(const char *pa
                         struct strbuf *gpg_output, struct strbuf *gpg_status)
  {
        struct child_process gpg = CHILD_PROCESS_INIT;
 +      struct gpg_format *fmt;
        struct tempfile *temp;
        int ret;
        struct strbuf buf = STRBUF_INIT;
                return -1;
        }
  
 +      fmt = get_format_by_sig(signature);
 +      if (!fmt)
 +              BUG("bad signature '%s'", signature);
 +
 +      argv_array_push(&gpg.args, fmt->program);
 +      argv_array_pushv(&gpg.args, fmt->verify_args);
        argv_array_pushl(&gpg.args,
 -                       gpg_program,
                         "--status-fd=1",
 -                       "--keyid-format=long",
                         "--verify", temp->filename.buf, "-",
                         NULL);