diff options
Diffstat (limited to 'gpg-interface.c')
-rw-r--r-- | gpg-interface.c | 113 |
1 files changed, 93 insertions, 20 deletions
diff --git a/gpg-interface.c b/gpg-interface.c index 0647bd6348..db17d65f8a 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -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) { @@ -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; @@ -53,10 +107,11 @@ void parse_gpg_output(struct signature_check *sigc) 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); } @@ -81,12 +136,13 @@ int check_signature(const char *payload, size_t plen, const char *signature, 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) @@ -101,12 +157,6 @@ 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; @@ -114,7 +164,7 @@ size_t parse_signature(const char *buf, size_t size) 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); @@ -131,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); @@ -138,13 +191,28 @@ int git_gpg_config(const char *var, const char *value, void *cb) 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; } @@ -163,7 +231,7 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig struct strbuf gpg_status = STRBUF_INIT; argv_array_pushl(&gpg.args, - gpg_program, + use_format->program, "--status-fd=2", "-bsau", signing_key, NULL); @@ -201,6 +269,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size, 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; @@ -216,10 +285,14 @@ int verify_signed_buffer(const char *payload, size_t payload_size, 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); |