ssh signing: tests for logs, tags & push certs
Signed-off-by: Fabian Stelzer <fs@gigacodes.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Fabian Stelzer committed
Sep 10, 2021 at 20:07 UTC
f265f2d630c498fd256d5da9d8b742efaf0cba8c
3 files changed
+285
t/t4202-log.sh
+23
@@ -1616,6 +1616,16 @@ test_expect_success GPGSM 'setup signed branch x509' '
1616
git commit -S -m signed_commit
1617
'
1618
1619
+test_expect_success GPGSSH 'setup sshkey signed branch' '
1620
+ test_config gpg.format ssh &&
1621
+ test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
1622
+ test_when_finished "git reset --hard && git checkout main" &&
1623
+ git checkout -b signed-ssh main &&
1624
+ echo foo >foo &&
1625
+ git add foo &&
1626
+ git commit -S -m signed_commit
1627
+'
1628
+
1629
test_expect_success GPGSM 'log x509 fingerprint' '
1630
echo "F8BF62E0693D0694816377099909C779FA23FD65 | " >expect &&
1631
git log -n1 --format="%GF | %GP" signed-x509 >actual &&
@@ -1628,6 +1638,13 @@ test_expect_success GPGSM 'log OpenPGP fingerprint' '
1638
test_cmp expect actual
1639
'
1640
1641
+test_expect_success GPGSSH 'log ssh key fingerprint' '
1642
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
1643
+ ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2\" | \"}" >expect &&
1644
+ git log -n1 --format="%GF | %GP" signed-ssh >actual &&
1645
+ test_cmp expect actual
1646
+'
1647
+
1648
test_expect_success GPG 'log --graph --show-signature' '
1649
git log --graph --show-signature -n1 signed >actual &&
1650
grep "^| gpg: Signature made" actual &&
@@ -1640,6 +1657,12 @@ test_expect_success GPGSM 'log --graph --show-signature x509' '
1657
grep "^| gpgsm: Good signature" actual
1658
'
1659
1660
+test_expect_success GPGSSH 'log --graph --show-signature ssh' '
1661
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
1662
+ git log --graph --show-signature -n1 signed-ssh >actual &&
1663
+ grep "${GOOD_SIGNATURE_TRUSTED}" actual
1664
+'
1665
+
1666
test_expect_success GPG 'log --graph --show-signature for merged tag' '
1667
test_when_finished "git reset --hard && git checkout main" &&
1668
git checkout -b plain main &&
t/t5534-push-signed.sh
+101
@@ -137,6 +137,53 @@ test_expect_success GPG 'signed push sends push certificate' '
137
test_cmp expect dst/push-cert-status
138
'
139
140
+test_expect_success GPGSSH 'ssh signed push sends push certificate' '
141
+ prepare_dst &&
142
+ mkdir -p dst/.git/hooks &&
143
+ git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
144
+ git -C dst config receive.certnonceseed sekrit &&
145
+ write_script dst/.git/hooks/post-receive <<-\EOF &&
146
+ # discard the update list
147
+ cat >/dev/null
148
+ # record the push certificate
149
+ if test -n "${GIT_PUSH_CERT-}"
150
+ then
151
+ git cat-file blob $GIT_PUSH_CERT >../push-cert
152
+ fi &&
153
+
154
+ cat >../push-cert-status <<E_O_F
155
+ SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
156
+ KEY=${GIT_PUSH_CERT_KEY-nokey}
157
+ STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
158
+ NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
159
+ NONCE=${GIT_PUSH_CERT_NONCE-nononce}
160
+ E_O_F
161
+
162
+ EOF
163
+
164
+ test_config gpg.format ssh &&
165
+ test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
166
+ FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
167
+ git push --signed dst noop ff +noff &&
168
+
169
+ (
170
+ cat <<-\EOF &&
171
+ SIGNER=principal with number 1
172
+ KEY=FINGERPRINT
173
+ STATUS=G
174
+ NONCE_STATUS=OK
175
+ EOF
176
+ sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
177
+ ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect &&
178
+
179
+ noop=$(git rev-parse noop) &&
180
+ ff=$(git rev-parse ff) &&
181
+ noff=$(git rev-parse noff) &&
182
+ grep "$noop $ff refs/heads/ff" dst/push-cert &&
183
+ grep "$noop $noff refs/heads/noff" dst/push-cert &&
184
+ test_cmp expect dst/push-cert-status
185
+'
186
+
187
test_expect_success GPG 'inconsistent push options in signed push not allowed' '
188
# First, invoke receive-pack with dummy input to obtain its preamble.
189
prepare_dst &&
@@ -276,6 +323,60 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
323
test_cmp expect dst/push-cert-status
324
'
325
326
+test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '
327
+ test_config gpg.format ssh &&
328
+ prepare_dst &&
329
+ mkdir -p dst/.git/hooks &&
330
+ git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
331
+ git -C dst config receive.certnonceseed sekrit &&
332
+ write_script dst/.git/hooks/post-receive <<-\EOF &&
333
+ # discard the update list
334
+ cat >/dev/null
335
+ # record the push certificate
336
+ if test -n "${GIT_PUSH_CERT-}"
337
+ then
338
+ git cat-file blob $GIT_PUSH_CERT >../push-cert
339
+ fi &&
340
+
341
+ cat >../push-cert-status <<E_O_F
342
+ SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
343
+ KEY=${GIT_PUSH_CERT_KEY-nokey}
344
+ STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
345
+ NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
346
+ NONCE=${GIT_PUSH_CERT_NONCE-nononce}
347
+ E_O_F
348
+
349
+ EOF
350
+
351
+ test_config user.email hasnokey@nowhere.com &&
352
+ test_config gpg.format ssh &&
353
+ test_config user.signingkey "" &&
354
+ (
355
+ sane_unset GIT_COMMITTER_EMAIL &&
356
+ test_must_fail git push --signed dst noop ff +noff
357
+ ) &&
358
+ test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
359
+ FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
360
+ git push --signed dst noop ff +noff &&
361
+
362
+ (
363
+ cat <<-\EOF &&
364
+ SIGNER=principal with number 1
365
+ KEY=FINGERPRINT
366
+ STATUS=G
367
+ NONCE_STATUS=OK
368
+ EOF
369
+ sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
370
+ ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect &&
371
+
372
+ noop=$(git rev-parse noop) &&
373
+ ff=$(git rev-parse ff) &&
374
+ noff=$(git rev-parse noff) &&
375
+ grep "$noop $ff refs/heads/ff" dst/push-cert &&
376
+ grep "$noop $noff refs/heads/noff" dst/push-cert &&
377
+ test_cmp expect dst/push-cert-status
378
+'
379
+
380
test_expect_success GPG 'failed atomic push does not execute GPG' '
381
prepare_dst &&
382
git -C dst config receive.certnonceseed sekrit &&
t/t7031-verify-tag-signed-ssh.sh
new
+161
@@ -0,0 +1,161 @@
1
+#!/bin/sh
2
+
3
+test_description='signed tag tests'
4
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
+
7
+. ./test-lib.sh
8
+. "$TEST_DIRECTORY/lib-gpg.sh"
9
+
10
+test_expect_success GPGSSH 'create signed tags ssh' '
11
+ test_when_finished "test_unconfig commit.gpgsign" &&
12
+ test_config gpg.format ssh &&
13
+ test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
14
+
15
+ echo 1 >file && git add file &&
16
+ test_tick && git commit -m initial &&
17
+ git tag -s -m initial initial &&
18
+ git branch side &&
19
+
20
+ echo 2 >file && test_tick && git commit -a -m second &&
21
+ git tag -s -m second second &&
22
+
23
+ git checkout side &&
24
+ echo 3 >elif && git add elif &&
25
+ test_tick && git commit -m "third on side" &&
26
+
27
+ git checkout main &&
28
+ test_tick && git merge -S side &&
29
+ git tag -s -m merge merge &&
30
+
31
+ echo 4 >file && test_tick && git commit -a -S -m "fourth unsigned" &&
32
+ git tag -a -m fourth-unsigned fourth-unsigned &&
33
+
34
+ test_tick && git commit --amend -S -m "fourth signed" &&
35
+ git tag -s -m fourth fourth-signed &&
36
+
37
+ echo 5 >file && test_tick && git commit -a -m "fifth" &&
38
+ git tag fifth-unsigned &&
39
+
40
+ git config commit.gpgsign true &&
41
+ echo 6 >file && test_tick && git commit -a -m "sixth" &&
42
+ git tag -a -m sixth sixth-unsigned &&
43
+
44
+ test_tick && git rebase -f HEAD^^ && git tag -s -m 6th sixth-signed HEAD^ &&
45
+ git tag -m seventh -s seventh-signed &&
46
+
47
+ echo 8 >file && test_tick && git commit -a -m eighth &&
48
+ git tag -u"${GPGSSH_KEY_UNTRUSTED}" -m eighth eighth-signed-alt
49
+'
50
+
51
+test_expect_success GPGSSH 'verify and show ssh signatures' '
52
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
53
+ (
54
+ for tag in initial second merge fourth-signed sixth-signed seventh-signed
55
+ do
56
+ git verify-tag $tag 2>actual &&
57
+ grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
58
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
59
+ echo $tag OK || exit 1
60
+ done
61
+ ) &&
62
+ (
63
+ for tag in fourth-unsigned fifth-unsigned sixth-unsigned
64
+ do
65
+ test_must_fail git verify-tag $tag 2>actual &&
66
+ ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
67
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
68
+ echo $tag OK || exit 1
69
+ done
70
+ ) &&
71
+ (
72
+ for tag in eighth-signed-alt
73
+ do
74
+ test_must_fail git verify-tag $tag 2>actual &&
75
+ grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
76
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
77
+ grep "${GPGSSH_KEY_NOT_TRUSTED}" actual &&
78
+ echo $tag OK || exit 1
79
+ done
80
+ )
81
+'
82
+
83
+test_expect_success GPGSSH 'detect fudged ssh signature' '
84
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
85
+ git cat-file tag seventh-signed >raw &&
86
+ sed -e "/^tag / s/seventh/7th forged/" raw >forged1 &&
87
+ git hash-object -w -t tag forged1 >forged1.tag &&
88
+ test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 &&
89
+ grep "${GPGSSH_BAD_SIGNATURE}" actual1 &&
90
+ ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual1 &&
91
+ ! grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual1
92
+'
93
+
94
+test_expect_success GPGSSH 'verify ssh signatures with --raw' '
95
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
96
+ (
97
+ for tag in initial second merge fourth-signed sixth-signed seventh-signed
98
+ do
99
+ git verify-tag --raw $tag 2>actual &&
100
+ grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
101
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
102
+ echo $tag OK || exit 1
103
+ done
104
+ ) &&
105
+ (
106
+ for tag in fourth-unsigned fifth-unsigned sixth-unsigned
107
+ do
108
+ test_must_fail git verify-tag --raw $tag 2>actual &&
109
+ ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
110
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
111
+ echo $tag OK || exit 1
112
+ done
113
+ ) &&
114
+ (
115
+ for tag in eighth-signed-alt
116
+ do
117
+ test_must_fail git verify-tag --raw $tag 2>actual &&
118
+ grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
119
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
120
+ echo $tag OK || exit 1
121
+ done
122
+ )
123
+'
124
+
125
+test_expect_success GPGSSH 'verify signatures with --raw ssh' '
126
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
127
+ git verify-tag --raw sixth-signed 2>actual &&
128
+ grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
129
+ ! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
130
+ echo sixth-signed OK
131
+'
132
+
133
+test_expect_success GPGSSH 'verify multiple tags ssh' '
134
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
135
+ tags="seventh-signed sixth-signed" &&
136
+ for i in $tags
137
+ do
138
+ git verify-tag -v --raw $i || return 1
139
+ done >expect.stdout 2>expect.stderr.1 &&
140
+ grep "^${GPGSSH_GOOD_SIGNATURE_TRUSTED}" <expect.stderr.1 >expect.stderr &&
141
+ git verify-tag -v --raw $tags >actual.stdout 2>actual.stderr.1 &&
142
+ grep "^${GPGSSH_GOOD_SIGNATURE_TRUSTED}" <actual.stderr.1 >actual.stderr &&
143
+ test_cmp expect.stdout actual.stdout &&
144
+ test_cmp expect.stderr actual.stderr
145
+'
146
+
147
+test_expect_success GPGSSH 'verifying tag with --format - ssh' '
148
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
149
+ cat >expect <<-\EOF &&
150
+ tagname : fourth-signed
151
+ EOF
152
+ git verify-tag --format="tagname : %(tag)" "fourth-signed" >actual &&
153
+ test_cmp expect actual
154
+'
155
+
156
+test_expect_success GPGSSH 'verifying a forged tag with --format should fail silently - ssh' '
157
+ test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged &&
158
+ test_must_be_empty actual-forged
159
+'
160
+
161
+test_done