Signed-off-by: Sebastian Götte <jaseg@xxxxxxxxxxxxxxxxxxxxxxxx> --- commit.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ commit.h | 9 ++++++++ gpg-interface.h | 6 ++++++ pretty.c | 67 +++++---------------------------------------------------- 4 files changed, 74 insertions(+), 62 deletions(-) diff --git a/commit.c b/commit.c index e8eb0ae..d0d9135 100644 --- a/commit.c +++ b/commit.c @@ -1023,6 +1023,60 @@ free_return: free(buf); } +static struct { + char result; + const char *check; +} signature_check[] = { + { 'G', ": Good signature from " }, + { 'B', ": BAD signature from " }, +}; + +static void parse_signature_lines(struct signature *sig) +{ + const char *buf = sig->gpg_output; + int i; + + for (i = 0; i < ARRAY_SIZE(signature_check); i++) { + const char *found = strstr(buf, signature_check[i].check); + const char *next; + if (!found) + continue; + sig->check_result = signature_check[i].result; + found += strlen(signature_check[i].check); + next = strchrnul(found, '\n'); + sig->signer = xmemdupz(found, next - found); + break; + } +} + +void check_commit_signature(const struct commit* commit, struct signature *sig) +{ + struct strbuf payload = STRBUF_INIT; + struct strbuf signature = STRBUF_INIT; + struct strbuf gpg_output = STRBUF_INIT; + int status; + + sig->check_result = 'N'; + + if (parse_signed_commit(commit->object.sha1, + &payload, &signature) <= 0) + goto out; + status = verify_signed_buffer(payload.buf, payload.len, + signature.buf, signature.len, + &gpg_output); + if (status && !gpg_output.len) + goto out; + sig->gpg_output = strbuf_detach(&gpg_output, NULL); + parse_signature_lines(sig); + + out: + strbuf_release(&gpg_output); + strbuf_release(&payload); + strbuf_release(&signature); +} + + + void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail) { diff --git a/commit.h b/commit.h index 4138bb4..eada616 100644 --- a/commit.h +++ b/commit.h @@ -5,6 +5,7 @@ #include "tree.h" #include "strbuf.h" #include "decorate.h" +#include "gpg-interface.h" struct commit_list { struct commit *item; @@ -230,4 +231,12 @@ extern void print_commit_list(struct commit_list *list, const char *format_cur, const char *format_last); +/* + * Check the signature of the given commit. The result of the check is stored in + * sig->check_result, 'G' for a good signature, 'B' for a bad signature and 'N' + * for no signature at all. + * This may allocate memory for sig->gpg_output and sig->signer. + */ +extern void check_commit_signature(const struct commit* commit, struct signature *sig); + #endif /* COMMIT_H */ diff --git a/gpg-interface.h b/gpg-interface.h index b9c3608..c69130f 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -1,6 +1,12 @@ #ifndef GPG_INTERFACE_H #define GPG_INTERFACE_H +struct signature { + char *gpg_output; + char check_result; /* 0 (not checked), N (checked but no further result), G (good) or B (bad) */ + char *signer; +}; + extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key); extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output); extern int git_gpg_config(const char *, const char *, void *); diff --git a/pretty.c b/pretty.c index eae57ad..0547df1 100644 --- a/pretty.c +++ b/pretty.c @@ -756,12 +756,7 @@ struct format_commit_context { const struct pretty_print_context *pretty_ctx; unsigned commit_header_parsed:1; unsigned commit_message_parsed:1; - unsigned commit_signature_parsed:1; - struct { - char *gpg_output; - char good_bad; - char *signer; - } signature; + struct signature signature; char *message; size_t width, indent1, indent2; @@ -944,58 +939,6 @@ static void rewrap_message_tail(struct strbuf *sb, c->indent2 = new_indent2; } -static struct { - char result; - const char *check; -} signature_check[] = { - { 'G', ": Good signature from " }, - { 'B', ": BAD signature from " }, -}; - -static void parse_signature_lines(struct format_commit_context *ctx) -{ - const char *buf = ctx->signature.gpg_output; - int i; - - for (i = 0; i < ARRAY_SIZE(signature_check); i++) { - const char *found = strstr(buf, signature_check[i].check); - const char *next; - if (!found) - continue; - ctx->signature.good_bad = signature_check[i].result; - found += strlen(signature_check[i].check); - next = strchrnul(found, '\n'); - ctx->signature.signer = xmemdupz(found, next - found); - break; - } -} - -static void parse_commit_signature(struct format_commit_context *ctx) -{ - struct strbuf payload = STRBUF_INIT; - struct strbuf signature = STRBUF_INIT; - struct strbuf gpg_output = STRBUF_INIT; - int status; - - ctx->commit_signature_parsed = 1; - - if (parse_signed_commit(ctx->commit->object.sha1, - &payload, &signature) <= 0) - goto out; - status = verify_signed_buffer(payload.buf, payload.len, - signature.buf, signature.len, - &gpg_output); - if (status && !gpg_output.len) - goto out; - ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL); - parse_signature_lines(ctx); - - out: - strbuf_release(&gpg_output); - strbuf_release(&payload); - strbuf_release(&signature); -} - static int format_reflog_person(struct strbuf *sb, char part, @@ -1182,18 +1125,18 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, } if (placeholder[0] == 'G') { - if (!c->commit_signature_parsed) - parse_commit_signature(c); + if (!c->signature.check_result) + check_commit_signature(c->commit, &(c->signature)); switch (placeholder[1]) { case 'G': if (c->signature.gpg_output) strbuf_addstr(sb, c->signature.gpg_output); break; case '?': - switch (c->signature.good_bad) { + switch (c->signature.check_result) { case 'G': case 'B': - strbuf_addch(sb, c->signature.good_bad); + strbuf_addch(sb, c->signature.check_result); } break; case 'S': -- 1.8.1.5 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html