log: --show-signature

This teaches the "log" family of commands to pass the GPG signature in the commit objects to "gpg --verify" via the verify_signed_buffer() interface used to verify signed tag objects. E.g. $ git show --show-signature -s HEAD shows GPG output in the header part of the output. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Oct 18, 2011 at 15:53 UTC 0c37f1fce6cb7997dbb2703d35eef0dfd86c5070
5 files changed +88
commit.c
+44
@@ -877,6 +877,50 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
877 return 0;
878 }
879
880 +int parse_signed_commit(const unsigned char *sha1,
881 + struct strbuf *payload, struct strbuf *signature)
882 +{
883 + unsigned long size;
884 + enum object_type type;
885 + char *buffer = read_sha1_file(sha1, &type, &size);
886 + int in_signature, saw_signature = -1;
887 + char *line, *tail;
888 +
889 + if (!buffer || type != OBJ_COMMIT)
890 + goto cleanup;
891 +
892 + line = buffer;
893 + tail = buffer + size;
894 + in_signature = 0;
895 + saw_signature = 0;
896 + while (line < tail) {
897 + const char *sig = NULL;
898 + char *next = memchr(line, '\n', tail - line);
899 +
900 + next = next ? next + 1 : tail;
901 + if (in_signature && line[0] == ' ')
902 + sig = line + 1;
903 + else if (!prefixcmp(line, gpg_sig_header) &&
904 + line[gpg_sig_header_len] == ' ')
905 + sig = line + gpg_sig_header_len + 1;
906 + if (sig) {
907 + strbuf_add(signature, sig, next - sig);
908 + saw_signature = 1;
909 + in_signature = 1;
910 + } else {
911 + if (*line == '\n')
912 + /* dump the whole remainder of the buffer */
913 + next = tail;
914 + strbuf_add(payload, line, next - line);
915 + in_signature = 0;
916 + }
917 + line = next;
918 + }
919 + cleanup:
920 + free(buffer);
921 + return saw_signature;
922 +}
923 +
924 static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
925 {
926 struct merge_remote_desc *desc;
commit.h
+2
@@ -218,4 +218,6 @@ struct merge_remote_desc {
218 */
219 struct commit *get_merge_parent(const char *name);
220
221 +extern int parse_signed_commit(const unsigned char *sha1,
222 + struct strbuf *message, struct strbuf *signature);
223 #endif /* COMMIT_H */
log-tree.c
+39
@@ -8,6 +8,7 @@
8 #include "refs.h"
9 #include "string-list.h"
10 #include "color.h"
11 +#include "gpg-interface.h"
12
13 struct decoration name_decoration = { "object names" };
14
@@ -403,6 +404,41 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
404 *extra_headers_p = extra_headers;
405 }
406
407 +static void show_signature(struct rev_info *opt, struct commit *commit)
408 +{
409 + struct strbuf payload = STRBUF_INIT;
410 + struct strbuf signature = STRBUF_INIT;
411 + struct strbuf gpg_output = STRBUF_INIT;
412 + int status;
413 + const char *color, *reset, *bol, *eol;
414 +
415 + if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
416 + goto out;
417 +
418 + status = verify_signed_buffer(payload.buf, payload.len,
419 + signature.buf, signature.len,
420 + &gpg_output);
421 + if (status && !gpg_output.len)
422 + strbuf_addstr(&gpg_output, "No signature\n");
423 +
424 + color = diff_get_color_opt(&opt->diffopt,
425 + status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
426 + reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
427 +
428 + bol = gpg_output.buf;
429 + while (*bol) {
430 + eol = strchrnul(bol, '\n');
431 + printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
432 + *eol ? "\n" : "");
433 + bol = (*eol) ? (eol + 1) : eol;
434 + }
435 +
436 + out:
437 + strbuf_release(&gpg_output);
438 + strbuf_release(&payload);
439 + strbuf_release(&signature);
440 +}
441 +
442 void show_log(struct rev_info *opt)
443 {
444 struct strbuf msgbuf = STRBUF_INIT;
@@ -514,6 +550,9 @@ void show_log(struct rev_info *opt)
550 }
551 }
552
553 + if (opt->show_signature)
554 + show_signature(opt, commit);
555 +
556 if (!commit->buffer)
557 return;
558
revision.c
+2
@@ -1469,6 +1469,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
1469 revs->show_notes = 1;
1470 revs->show_notes_given = 1;
1471 revs->notes_opt.use_default_notes = 1;
1472 + } else if (!strcmp(arg, "--show-signature")) {
1473 + revs->show_signature = 1;
1474 } else if (!prefixcmp(arg, "--show-notes=") ||
1475 !prefixcmp(arg, "--notes=")) {
1476 struct strbuf buf = STRBUF_INIT;
revision.h
+1
@@ -110,6 +110,7 @@ struct rev_info {
110 show_merge:1,
111 show_notes:1,
112 show_notes_given:1,
113 + show_signature:1,
114 pretty_given:1,
115 abbrev_commit:1,
116 abbrev_commit_given:1,