Skip to content

Commit 6f5f705

Browse files
committed
Merge branch 'hi/gpg-prefer-check-signature' into pu
The code to interface with GnuPG has been refactored. * hi/gpg-prefer-check-signature: gpg-interface: prefer check_signature() for GPG verification t: increase test coverage of signature verification output
2 parents 1eced8b + a041c0d commit 6f5f705

File tree

6 files changed

+201
-78
lines changed

6 files changed

+201
-78
lines changed

builtin/fmt-merge-msg.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
494494
enum object_type type;
495495
unsigned long size, len;
496496
char *buf = read_object_file(oid, &type, &size);
497+
struct signature_check sigc = { 0 };
497498
struct strbuf sig = STRBUF_INIT;
498499

499500
if (!buf || type != OBJ_TAG)
@@ -502,10 +503,12 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
502503

503504
if (size == len)
504505
; /* merely annotated */
505-
else if (verify_signed_buffer(buf, len, buf + len, size - len, &sig, NULL)) {
506-
if (!sig.len)
507-
strbuf_addstr(&sig, "gpg verification failed.\n");
508-
}
506+
else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
507+
!sigc.gpg_output)
508+
strbuf_addstr(&sig, "gpg verification failed.\n");
509+
else
510+
strbuf_addstr(&sig, sigc.gpg_output);
511+
signature_check_clear(&sigc);
509512

510513
if (!tag_number++) {
511514
fmt_tag_signature(&tagbuf, &sig, buf, len);

gpg-interface.c

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,55 @@ static void parse_gpg_output(struct signature_check *sigc)
256256
FREE_AND_NULL(sigc->key);
257257
}
258258

259+
static int verify_signed_buffer(const char *payload, size_t payload_size,
260+
const char *signature, size_t signature_size,
261+
struct strbuf *gpg_output,
262+
struct strbuf *gpg_status)
263+
{
264+
struct child_process gpg = CHILD_PROCESS_INIT;
265+
struct gpg_format *fmt;
266+
struct tempfile *temp;
267+
int ret;
268+
struct strbuf buf = STRBUF_INIT;
269+
270+
temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
271+
if (!temp)
272+
return error_errno(_("could not create temporary file"));
273+
if (write_in_full(temp->fd, signature, signature_size) < 0 ||
274+
close_tempfile_gently(temp) < 0) {
275+
error_errno(_("failed writing detached signature to '%s'"),
276+
temp->filename.buf);
277+
delete_tempfile(&temp);
278+
return -1;
279+
}
280+
281+
fmt = get_format_by_sig(signature);
282+
if (!fmt)
283+
BUG("bad signature '%s'", signature);
284+
285+
argv_array_push(&gpg.args, fmt->program);
286+
argv_array_pushv(&gpg.args, fmt->verify_args);
287+
argv_array_pushl(&gpg.args,
288+
"--status-fd=1",
289+
"--verify", temp->filename.buf, "-",
290+
NULL);
291+
292+
if (!gpg_status)
293+
gpg_status = &buf;
294+
295+
sigchain_push(SIGPIPE, SIG_IGN);
296+
ret = pipe_command(&gpg, payload, payload_size,
297+
gpg_status, 0, gpg_output, 0);
298+
sigchain_pop(SIGPIPE);
299+
300+
delete_tempfile(&temp);
301+
302+
ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
303+
strbuf_release(&buf); /* no matter it was used or not */
304+
305+
return ret;
306+
}
307+
259308
int check_signature(const char *payload, size_t plen, const char *signature,
260309
size_t slen, struct signature_check *sigc)
261310
{
@@ -418,51 +467,3 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig
418467

419468
return 0;
420469
}
421-
422-
int verify_signed_buffer(const char *payload, size_t payload_size,
423-
const char *signature, size_t signature_size,
424-
struct strbuf *gpg_output, struct strbuf *gpg_status)
425-
{
426-
struct child_process gpg = CHILD_PROCESS_INIT;
427-
struct gpg_format *fmt;
428-
struct tempfile *temp;
429-
int ret;
430-
struct strbuf buf = STRBUF_INIT;
431-
432-
temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
433-
if (!temp)
434-
return error_errno(_("could not create temporary file"));
435-
if (write_in_full(temp->fd, signature, signature_size) < 0 ||
436-
close_tempfile_gently(temp) < 0) {
437-
error_errno(_("failed writing detached signature to '%s'"),
438-
temp->filename.buf);
439-
delete_tempfile(&temp);
440-
return -1;
441-
}
442-
443-
fmt = get_format_by_sig(signature);
444-
if (!fmt)
445-
BUG("bad signature '%s'", signature);
446-
447-
argv_array_push(&gpg.args, fmt->program);
448-
argv_array_pushv(&gpg.args, fmt->verify_args);
449-
argv_array_pushl(&gpg.args,
450-
"--status-fd=1",
451-
"--verify", temp->filename.buf, "-",
452-
NULL);
453-
454-
if (!gpg_status)
455-
gpg_status = &buf;
456-
457-
sigchain_push(SIGPIPE, SIG_IGN);
458-
ret = pipe_command(&gpg, payload, payload_size,
459-
gpg_status, 0, gpg_output, 0);
460-
sigchain_pop(SIGPIPE);
461-
462-
delete_tempfile(&temp);
463-
464-
ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
465-
strbuf_release(&buf); /* no matter it was used or not */
466-
467-
return ret;
468-
}

gpg-interface.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,6 @@ size_t parse_signature(const char *buf, size_t size);
5454
int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
5555
const char *signing_key);
5656

57-
/*
58-
* Run "gpg" to see if the payload matches the detached signature.
59-
* gpg_output, when set, receives the diagnostic output from GPG.
60-
* gpg_status, when set, receives the status output from GPG.
61-
*/
62-
int verify_signed_buffer(const char *payload, size_t payload_size,
63-
const char *signature, size_t signature_size,
64-
struct strbuf *gpg_output, struct strbuf *gpg_status);
65-
6657
int git_gpg_config(const char *, const char *, void *);
6758
void set_signing_key(const char *);
6859
const char *get_signing_key(void);

log-tree.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -449,22 +449,21 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
449449
{
450450
struct strbuf payload = STRBUF_INIT;
451451
struct strbuf signature = STRBUF_INIT;
452-
struct strbuf gpg_output = STRBUF_INIT;
452+
struct signature_check sigc = { 0 };
453453
int status;
454454

455455
if (parse_signed_commit(commit, &payload, &signature) <= 0)
456456
goto out;
457457

458-
status = verify_signed_buffer(payload.buf, payload.len,
459-
signature.buf, signature.len,
460-
&gpg_output, NULL);
461-
if (status && !gpg_output.len)
462-
strbuf_addstr(&gpg_output, "No signature\n");
463-
464-
show_sig_lines(opt, status, gpg_output.buf);
458+
status = check_signature(payload.buf, payload.len, signature.buf,
459+
signature.len, &sigc);
460+
if (status && !sigc.gpg_output)
461+
show_sig_lines(opt, status, "No signature\n");
462+
else
463+
show_sig_lines(opt, status, sigc.gpg_output);
464+
signature_check_clear(&sigc);
465465

466466
out:
467-
strbuf_release(&gpg_output);
468467
strbuf_release(&payload);
469468
strbuf_release(&signature);
470469
}
@@ -497,8 +496,9 @@ static int show_one_mergetag(struct commit *commit,
497496
struct object_id oid;
498497
struct tag *tag;
499498
struct strbuf verify_message;
499+
struct signature_check sigc = { 0 };
500500
int status, nth;
501-
size_t payload_size, gpg_message_offset;
501+
size_t payload_size;
502502

503503
hash_object_file(the_hash_algo, extra->value, extra->len,
504504
type_name(OBJ_TAG), &oid);
@@ -520,19 +520,19 @@ static int show_one_mergetag(struct commit *commit,
520520
else
521521
strbuf_addf(&verify_message,
522522
"parent #%d, tagged '%s'\n", nth + 1, tag->tag);
523-
gpg_message_offset = verify_message.len;
524523

525524
payload_size = parse_signature(extra->value, extra->len);
526525
status = -1;
527526
if (extra->len > payload_size) {
528527
/* could have a good signature */
529-
if (!verify_signed_buffer(extra->value, payload_size,
530-
extra->value + payload_size,
531-
extra->len - payload_size,
532-
&verify_message, NULL))
533-
status = 0; /* good */
534-
else if (verify_message.len <= gpg_message_offset)
528+
status = check_signature(extra->value, payload_size,
529+
extra->value + payload_size,
530+
extra->len - payload_size, &sigc);
531+
if (sigc.gpg_output)
532+
strbuf_addstr(&verify_message, sigc.gpg_output);
533+
else
535534
strbuf_addstr(&verify_message, "No signature\n");
535+
signature_check_clear(&sigc);
536536
/* otherwise we couldn't verify, which is shown as bad */
537537
}
538538

t/t4202-log.sh

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,66 @@ test_expect_success GPG 'log --graph --show-signature for merged tag in shallow
16271627
grep "tag signed_tag_shallow names a non-parent $hash" actual
16281628
'
16291629

1630+
test_expect_success GPG 'log --graph --show-signature for merged tag with missing key' '
1631+
test_when_finished "git reset --hard && git checkout master" &&
1632+
git checkout -b plain-nokey master &&
1633+
echo aaa >bar &&
1634+
git add bar &&
1635+
git commit -m bar_commit &&
1636+
git checkout -b tagged-nokey master &&
1637+
echo bbb >baz &&
1638+
git add baz &&
1639+
git commit -m baz_commit &&
1640+
git tag -s -m signed_tag_msg signed_tag_nokey &&
1641+
git checkout plain-nokey &&
1642+
git merge --no-ff -m msg signed_tag_nokey &&
1643+
GNUPGHOME=. git log --graph --show-signature -n1 plain-nokey >actual &&
1644+
grep "^|\\\ merged tag" actual &&
1645+
grep "^| | gpg: Signature made" actual &&
1646+
grep "^| | gpg: Can'"'"'t check signature: \(public key not found\|No public key\)" actual
1647+
'
1648+
1649+
test_expect_success GPG 'log --graph --show-signature for merged tag with bad signature' '
1650+
test_when_finished "git reset --hard && git checkout master" &&
1651+
git checkout -b plain-bad master &&
1652+
echo aaa >bar &&
1653+
git add bar &&
1654+
git commit -m bar_commit &&
1655+
git checkout -b tagged-bad master &&
1656+
echo bbb >baz &&
1657+
git add baz &&
1658+
git commit -m baz_commit &&
1659+
git tag -s -m signed_tag_msg signed_tag_bad &&
1660+
git cat-file tag signed_tag_bad >raw &&
1661+
sed -e "s/signed_tag_msg/forged/" raw >forged &&
1662+
git hash-object -w -t tag forged >forged.tag &&
1663+
git checkout plain-bad &&
1664+
git merge --no-ff -m msg "$(cat forged.tag)" &&
1665+
git log --graph --show-signature -n1 plain-bad >actual &&
1666+
grep "^|\\\ merged tag" actual &&
1667+
grep "^| | gpg: Signature made" actual &&
1668+
grep "^| | gpg: BAD signature from" actual
1669+
'
1670+
1671+
test_expect_success GPG 'log --show-signature for merged tag with GPG failure' '
1672+
test_when_finished "git reset --hard && git checkout master" &&
1673+
git checkout -b plain-fail master &&
1674+
echo aaa >bar &&
1675+
git add bar &&
1676+
git commit -m bar_commit &&
1677+
git checkout -b tagged-fail master &&
1678+
echo bbb >baz &&
1679+
git add baz &&
1680+
git commit -m baz_commit &&
1681+
git tag -s -m signed_tag_msg signed_tag_fail &&
1682+
git checkout plain-fail &&
1683+
git merge --no-ff -m msg signed_tag_fail &&
1684+
TMPDIR="$(pwd)/bogus" git log --show-signature -n1 plain-fail >actual &&
1685+
grep "^merged tag" actual &&
1686+
grep "^No signature" actual &&
1687+
! grep "^gpg: Signature made" actual
1688+
'
1689+
16301690
test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' '
16311691
test_when_finished "git reset --hard && git checkout master" &&
16321692
test_config gpg.format x509 &&
@@ -1648,6 +1708,51 @@ test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' '
16481708
grep "^| | gpgsm: Good signature" actual
16491709
'
16501710

1711+
test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 missing key' '
1712+
test_when_finished "git reset --hard && git checkout master" &&
1713+
test_config gpg.format x509 &&
1714+
test_config user.signingkey $GIT_COMMITTER_EMAIL &&
1715+
git checkout -b plain-x509-nokey master &&
1716+
echo aaa >bar &&
1717+
git add bar &&
1718+
git commit -m bar_commit &&
1719+
git checkout -b tagged-x509-nokey master &&
1720+
echo bbb >baz &&
1721+
git add baz &&
1722+
git commit -m baz_commit &&
1723+
git tag -s -m signed_tag_msg signed_tag_x509_nokey &&
1724+
git checkout plain-x509-nokey &&
1725+
git merge --no-ff -m msg signed_tag_x509_nokey &&
1726+
GNUPGHOME=. git log --graph --show-signature -n1 plain-x509-nokey >actual &&
1727+
grep "^|\\\ merged tag" actual &&
1728+
grep "^| | gpgsm: certificate not found" actual
1729+
'
1730+
1731+
test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 bad signature' '
1732+
test_when_finished "git reset --hard && git checkout master" &&
1733+
test_config gpg.format x509 &&
1734+
test_config user.signingkey $GIT_COMMITTER_EMAIL &&
1735+
git checkout -b plain-x509-bad master &&
1736+
echo aaa >bar &&
1737+
git add bar &&
1738+
git commit -m bar_commit &&
1739+
git checkout -b tagged-x509-bad master &&
1740+
echo bbb >baz &&
1741+
git add baz &&
1742+
git commit -m baz_commit &&
1743+
git tag -s -m signed_tag_msg signed_tag_x509_bad &&
1744+
git cat-file tag signed_tag_x509_bad >raw &&
1745+
sed -e "s/signed_tag_msg/forged/" raw >forged &&
1746+
git hash-object -w -t tag forged >forged.tag &&
1747+
git checkout plain-x509-bad &&
1748+
git merge --no-ff -m msg "$(cat forged.tag)" &&
1749+
git log --graph --show-signature -n1 plain-x509-bad >actual &&
1750+
grep "^|\\\ merged tag" actual &&
1751+
grep "^| | gpgsm: Signature made" actual &&
1752+
grep "^| | gpgsm: invalid signature" actual
1753+
'
1754+
1755+
16511756
test_expect_success GPG '--no-show-signature overrides --show-signature' '
16521757
git log -1 --show-signature --no-show-signature signed >actual &&
16531758
! grep "^gpg:" actual

t/t6200-fmt-merge-msg.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
test_description='fmt-merge-msg test'
77

88
. ./test-lib.sh
9+
. "$TEST_DIRECTORY/lib-gpg.sh"
910

1011
test_expect_success setup '
1112
echo one >one &&
@@ -73,6 +74,10 @@ test_expect_success setup '
7374
apos="'\''"
7475
'
7576

77+
test_expect_success GPG '
78+
git tag -s -m signed-tag-msg signed-good-tag left
79+
'
80+
7681
test_expect_success 'message for merging local branch' '
7782
echo "Merge branch ${apos}left${apos}" >expected &&
7883
@@ -83,6 +88,24 @@ test_expect_success 'message for merging local branch' '
8388
test_cmp expected actual
8489
'
8590

91+
test_expect_success GPG 'message for merging local tag signed by good key' '
92+
git checkout master &&
93+
git fetch . signed-good-tag &&
94+
git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
95+
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
96+
grep "^# gpg: Signature made" actual &&
97+
grep "^# gpg: Good signature from" actual
98+
'
99+
100+
test_expect_success GPG 'message for merging local tag signed by unknown key' '
101+
git checkout master &&
102+
git fetch . signed-good-tag &&
103+
GNUPGHOME=. git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
104+
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
105+
grep "^# gpg: Signature made" actual &&
106+
grep "^# gpg: Can${apos}t check signature: \(public key not found\|No public key\)" actual
107+
'
108+
86109
test_expect_success 'message for merging external branch' '
87110
echo "Merge branch ${apos}left${apos} of $(pwd)" >expected &&
88111

0 commit comments

Comments
 (0)