gpg: centralize signature check

verify-commit and verify-tag both share a central codepath for verifying
commits: check_signature.  However, verify-tag exited successfully for
untrusted signature, while verify-commit exited unsuccessfully.
Centralize this signature check and make verify-commit adopt the older
verify-tag behavior.  This behavior is more logical anyway, as the
signature is in fact valid, whether or not there's a path of trust to
the author.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
brian m. carlson 2015-06-21 23:14:40 +00:00 committed by Junio C Hamano
parent 8e98e5f27a
commit 434060ec6d
7 changed files with 18 additions and 10 deletions

View File

@ -21,10 +21,11 @@ static const char * const verify_commit_usage[] = {
static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose) static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose)
{ {
struct signature_check signature_check; struct signature_check signature_check;
int ret;
memset(&signature_check, 0, sizeof(signature_check)); memset(&signature_check, 0, sizeof(signature_check));
check_commit_signature(lookup_commit(sha1), &signature_check); ret = check_commit_signature(lookup_commit(sha1), &signature_check);
if (verbose && signature_check.payload) if (verbose && signature_check.payload)
fputs(signature_check.payload, stdout); fputs(signature_check.payload, stdout);
@ -33,7 +34,7 @@ static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned l
fputs(signature_check.gpg_output, stderr); fputs(signature_check.gpg_output, stderr);
signature_check_clear(&signature_check); signature_check_clear(&signature_check);
return signature_check.result != 'G'; return ret;
} }
static int verify_commit(const char *name, int verbose) static int verify_commit(const char *name, int verbose)

View File

@ -22,6 +22,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
{ {
struct signature_check sigc; struct signature_check sigc;
int len; int len;
int ret;
memset(&sigc, 0, sizeof(sigc)); memset(&sigc, 0, sizeof(sigc));
@ -32,11 +33,11 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
if (size == len) if (size == len)
return error("no signature found"); return error("no signature found");
check_signature(buf, len, buf + len, size - len, &sigc); ret = check_signature(buf, len, buf + len, size - len, &sigc);
fputs(sigc.gpg_output, stderr); fputs(sigc.gpg_output, stderr);
signature_check_clear(&sigc); signature_check_clear(&sigc);
return sigc.result != 'G' && sigc.result != 'U'; return ret;
} }
static int verify_tag(const char *name, int verbose) static int verify_tag(const char *name, int verbose)

View File

@ -1227,20 +1227,24 @@ free_return:
free(buf); free(buf);
} }
void check_commit_signature(const struct commit *commit, struct signature_check *sigc) int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
{ {
struct strbuf payload = STRBUF_INIT; struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT; struct strbuf signature = STRBUF_INIT;
int ret = 1;
sigc->result = 'N'; sigc->result = 'N';
if (parse_signed_commit(commit, &payload, &signature) <= 0) if (parse_signed_commit(commit, &payload, &signature) <= 0)
goto out; goto out;
check_signature(payload.buf, payload.len, signature.buf, signature.len, sigc); ret = check_signature(payload.buf, payload.len, signature.buf,
signature.len, sigc);
out: out:
strbuf_release(&payload); strbuf_release(&payload);
strbuf_release(&signature); strbuf_release(&signature);
return ret;
} }

View File

@ -375,7 +375,7 @@ extern void print_commit_list(struct commit_list *list,
* at all. This may allocate memory for sig->gpg_output, sig->gpg_status, * at all. This may allocate memory for sig->gpg_output, sig->gpg_status,
* sig->signer and sig->key. * sig->signer and sig->key.
*/ */
extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc); extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc);
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused); int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);

View File

@ -60,7 +60,7 @@ void parse_gpg_output(struct signature_check *sigc)
} }
} }
void check_signature(const char *payload, size_t plen, const char *signature, int check_signature(const char *payload, size_t plen, const char *signature,
size_t slen, struct signature_check *sigc) size_t slen, struct signature_check *sigc)
{ {
struct strbuf gpg_output = STRBUF_INIT; struct strbuf gpg_output = STRBUF_INIT;
@ -81,6 +81,8 @@ void check_signature(const char *payload, size_t plen, const char *signature,
out: out:
strbuf_release(&gpg_status); strbuf_release(&gpg_status);
strbuf_release(&gpg_output); strbuf_release(&gpg_output);
return sigc->result != 'G' && sigc->result != 'U';
} }
/* /*

View File

@ -27,7 +27,7 @@ extern int verify_signed_buffer(const char *payload, size_t payload_size, const
extern int git_gpg_config(const char *, const char *, void *); extern int git_gpg_config(const char *, const char *, void *);
extern void set_signing_key(const char *); extern void set_signing_key(const char *);
extern const char *get_signing_key(void); extern const char *get_signing_key(void);
extern void check_signature(const char *payload, size_t plen, extern int check_signature(const char *payload, size_t plen,
const char *signature, size_t slen, struct signature_check *sigc); const char *signature, size_t slen, struct signature_check *sigc);
#endif #endif

View File

@ -81,7 +81,7 @@ test_expect_success GPG 'verify and show signatures' '
) )
' '
test_expect_failure GPG 'verify-commit exits success on untrusted signature' ' test_expect_success GPG 'verify-commit exits success on untrusted signature' '
git verify-commit eighth-signed-alt 2>actual && git verify-commit eighth-signed-alt 2>actual &&
grep "Good signature from" actual && grep "Good signature from" actual &&
! grep "BAD signature from" actual && ! grep "BAD signature from" actual &&