1#!/bin/sh 2 3test_description='ssh signed commit tests' 4GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 5export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 6 7. ./test-lib.sh 8GNUPGHOME_NOT_USED=$GNUPGHOME 9. "$TEST_DIRECTORY/lib-gpg.sh" 10 11test_expect_success GPGSSH 'create signed commits' ' 12 test_oid_cache <<-\EOF && 13 header sha1:gpgsig 14 header sha256:gpgsig-sha256 15 EOF 16 17 test_when_finished "test_unconfig commit.gpgsign" && 18 test_config gpg.format ssh && 19 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && 20 21 echo 1 >file && git add file && 22 test_tick && git commit -S -m initial && 23 git tag initial && 24 git branch side && 25 26 echo 2 >file && test_tick && git commit -a -S -m second && 27 git tag second && 28 29 git checkout side && 30 echo 3 >elif && git add elif && 31 test_tick && git commit -m "third on side" && 32 33 git checkout main && 34 test_tick && git merge -S side && 35 git tag merge && 36 37 echo 4 >file && test_tick && git commit -a -m "fourth unsigned" && 38 git tag fourth-unsigned && 39 40 test_tick && git commit --amend -S -m "fourth signed" && 41 git tag fourth-signed && 42 43 git config commit.gpgsign true && 44 echo 5 >file && test_tick && git commit -a -m "fifth signed" && 45 git tag fifth-signed && 46 47 git config commit.gpgsign false && 48 echo 6 >file && test_tick && git commit -a -m "sixth" && 49 git tag sixth-unsigned && 50 51 git config commit.gpgsign true && 52 echo 7 >file && test_tick && git commit -a -m "seventh" --no-gpg-sign && 53 git tag seventh-unsigned && 54 55 test_tick && git rebase -f HEAD^^ && git tag sixth-signed HEAD^ && 56 git tag seventh-signed && 57 58 echo 8 >file && test_tick && git commit -a -m eighth -S"${GPGSSH_KEY_UNTRUSTED}" && 59 git tag eighth-signed-alt && 60 61 # commit.gpgsign is still on but this must not be signed 62 echo 9 | git commit-tree HEAD^{tree} >oid && 63 test_line_count = 1 oid && 64 git tag ninth-unsigned $(cat oid) && 65 # explicit -S of course must sign. 66 echo 10 | git commit-tree -S HEAD^{tree} >oid && 67 test_line_count = 1 oid && 68 git tag tenth-signed $(cat oid) && 69 70 # --gpg-sign[=<key-id>] must sign. 71 echo 11 | git commit-tree --gpg-sign HEAD^{tree} >oid && 72 test_line_count = 1 oid && 73 git tag eleventh-signed $(cat oid) && 74 echo 12 | git commit-tree --gpg-sign="${GPGSSH_KEY_UNTRUSTED}" HEAD^{tree} >oid && 75 test_line_count = 1 oid && 76 git tag twelfth-signed-alt $(cat oid) 77' 78 79test_expect_success GPGSSH 'verify and show signatures' ' 80 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 81 test_config gpg.mintrustlevel UNDEFINED && 82 ( 83 for commit in initial second merge fourth-signed \ 84 fifth-signed sixth-signed seventh-signed tenth-signed \ 85 eleventh-signed 86 do 87 git verify-commit $commit && 88 git show --pretty=short --show-signature $commit >actual && 89 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 90 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 91 echo $commit OK || exit 1 92 done 93 ) && 94 ( 95 for commit in merge^2 fourth-unsigned sixth-unsigned \ 96 seventh-unsigned ninth-unsigned 97 do 98 test_must_fail git verify-commit $commit && 99 git show --pretty=short --show-signature $commit >actual && 100 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 101 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 102 echo $commit OK || exit 1 103 done 104 ) && 105 ( 106 for commit in eighth-signed-alt twelfth-signed-alt 107 do 108 git show --pretty=short --show-signature $commit >actual && 109 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 110 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 111 grep "${GPGSSH_KEY_NOT_TRUSTED}" actual && 112 echo $commit OK || exit 1 113 done 114 ) 115' 116 117test_expect_success GPGSSH 'verify-commit exits failure on untrusted signature' ' 118 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 119 test_must_fail git verify-commit eighth-signed-alt 2>actual && 120 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 121 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 122 grep "${GPGSSH_KEY_NOT_TRUSTED}" actual 123' 124 125test_expect_success GPGSSH 'verify-commit exits success with matching minTrustLevel' ' 126 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 127 test_config gpg.minTrustLevel fully && 128 git verify-commit sixth-signed 129' 130 131test_expect_success GPGSSH 'verify-commit exits success with low minTrustLevel' ' 132 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 133 test_config gpg.minTrustLevel marginal && 134 git verify-commit sixth-signed 135' 136 137test_expect_success GPGSSH 'verify-commit exits failure with high minTrustLevel' ' 138 test_config gpg.minTrustLevel ultimate && 139 test_must_fail git verify-commit eighth-signed-alt 140' 141 142test_expect_success GPGSSH 'verify signatures with --raw' ' 143 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 144 ( 145 for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed 146 do 147 git verify-commit --raw $commit 2>actual && 148 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 149 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 150 echo $commit OK || exit 1 151 done 152 ) && 153 ( 154 for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned 155 do 156 test_must_fail git verify-commit --raw $commit 2>actual && 157 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 158 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 159 echo $commit OK || exit 1 160 done 161 ) && 162 ( 163 for commit in eighth-signed-alt 164 do 165 test_must_fail git verify-commit --raw $commit 2>actual && 166 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 167 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 168 echo $commit OK || exit 1 169 done 170 ) 171' 172 173test_expect_success GPGSSH 'proper header is used for hash algorithm' ' 174 git cat-file commit fourth-signed >output && 175 grep "^$(test_oid header) -----BEGIN SSH SIGNATURE-----" output 176' 177 178test_expect_success GPGSSH 'show signed commit with signature' ' 179 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 180 git show -s initial >commit && 181 git show -s --show-signature initial >show && 182 git verify-commit -v initial >verify.1 2>verify.2 && 183 git cat-file commit initial >cat && 184 grep -v -e "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" -e "Warning: " show >show.commit && 185 grep -e "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" -e "Warning: " show >show.gpg && 186 grep -v "^ " cat | grep -v "^gpgsig.* " >cat.commit && 187 test_cmp show.commit commit && 188 test_cmp show.gpg verify.2 && 189 test_cmp cat.commit verify.1 190' 191 192test_expect_success GPGSSH 'detect fudged signature' ' 193 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 194 git cat-file commit seventh-signed >raw && 195 sed -e "s/^seventh/7th forged/" raw >forged1 && 196 git hash-object -w -t commit forged1 >forged1.commit && 197 test_must_fail git verify-commit $(cat forged1.commit) && 198 git show --pretty=short --show-signature $(cat forged1.commit) >actual1 && 199 grep "${GPGSSH_BAD_SIGNATURE}" actual1 && 200 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual1 && 201 ! grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual1 202' 203 204test_expect_success GPGSSH 'detect fudged signature with NUL' ' 205 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 206 git cat-file commit seventh-signed >raw && 207 cat raw >forged2 && 208 echo Qwik | tr "Q" "\000" >>forged2 && 209 git hash-object -w -t commit forged2 >forged2.commit && 210 test_must_fail git verify-commit $(cat forged2.commit) && 211 git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && 212 grep "${GPGSSH_BAD_SIGNATURE}" actual2 && 213 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual2 214' 215 216test_expect_success GPGSSH 'amending already signed commit' ' 217 test_config gpg.format ssh && 218 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && 219 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 220 git checkout fourth-signed^0 && 221 git commit --amend -S --no-edit && 222 git verify-commit HEAD && 223 git show -s --show-signature HEAD >actual && 224 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 225 ! grep "${GPGSSH_BAD_SIGNATURE}" actual 226' 227 228test_expect_success GPGSSH 'show good signature with custom format' ' 229 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 230 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && 231 cat >expect.tmpl <<-\EOF && 232 G 233 FINGERPRINT 234 principal with number 1 235 FINGERPRINT 236 237 EOF 238 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 239 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && 240 test_cmp expect actual 241' 242 243test_expect_success GPGSSH 'show bad signature with custom format' ' 244 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 245 cat >expect <<-\EOF && 246 B 247 248 249 250 251 EOF 252 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && 253 test_cmp expect actual 254' 255 256test_expect_success GPGSSH 'show untrusted signature with custom format' ' 257 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 258 cat >expect.tmpl <<-\EOF && 259 U 260 FINGERPRINT 261 262 FINGERPRINT 263 264 EOF 265 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && 266 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_UNTRUSTED}" | awk "{print \$2;}") && 267 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 268 test_cmp expect actual 269' 270 271test_expect_success GPGSSH 'show untrusted signature with undefined trust level' ' 272 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 273 cat >expect.tmpl <<-\EOF && 274 undefined 275 FINGERPRINT 276 277 FINGERPRINT 278 279 EOF 280 git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && 281 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_UNTRUSTED}" | awk "{print \$2;}") && 282 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 283 test_cmp expect actual 284' 285 286test_expect_success GPGSSH 'show untrusted signature with ultimate trust level' ' 287 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 288 cat >expect.tmpl <<-\EOF && 289 fully 290 FINGERPRINT 291 principal with number 1 292 FINGERPRINT 293 294 EOF 295 git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && 296 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && 297 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 298 test_cmp expect actual 299' 300 301test_expect_success GPGSSH 'show lack of signature with custom format' ' 302 cat >expect <<-\EOF && 303 N 304 305 306 307 308 EOF 309 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && 310 test_cmp expect actual 311' 312 313test_expect_success GPGSSH 'log.showsignature behaves like --show-signature' ' 314 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 315 test_config log.showsignature true && 316 git show initial >actual && 317 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual 318' 319 320test_expect_success GPGSSH 'check config gpg.format values' ' 321 test_config gpg.format ssh && 322 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && 323 test_config gpg.format ssh && 324 git commit -S --amend -m "success" && 325 test_config gpg.format OpEnPgP && 326 test_must_fail git commit -S --amend -m "fail" 327' 328 329test_expect_failure GPGSSH 'detect fudged commit with double signature (TODO)' ' 330 sed -e "/gpgsig/,/END PGP/d" forged1 >double-base && 331 sed -n -e "/gpgsig/,/END PGP/p" forged1 | \ 332 sed -e "s/^$(test_oid header)//;s/^ //" | gpg --dearmor >double-sig1.sig && 333 gpg -o double-sig2.sig -u 29472784 --detach-sign double-base && 334 cat double-sig1.sig double-sig2.sig | gpg --enarmor >double-combined.asc && 335 sed -e "s/^\(-.*\)ARMORED FILE/\1SIGNATURE/;1s/^/$(test_oid header) /;2,\$s/^/ /" \ 336 double-combined.asc > double-gpgsig && 337 sed -e "/committer/r double-gpgsig" double-base >double-commit && 338 git hash-object -w -t commit double-commit >double-commit.commit && 339 test_must_fail git verify-commit $(cat double-commit.commit) && 340 git show --pretty=short --show-signature $(cat double-commit.commit) >double-actual && 341 grep "BAD signature from" double-actual && 342 grep "Good signature from" double-actual 343' 344 345test_expect_failure GPGSSH 'show double signature with custom format (TODO)' ' 346 cat >expect <<-\EOF && 347 E 348 349 350 351 352 EOF 353 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat double-commit.commit) >actual && 354 test_cmp expect actual 355' 356 357 358test_expect_failure GPGSSH 'verify-commit verifies multiply signed commits (TODO)' ' 359 git init multiply-signed && 360 cd multiply-signed && 361 test_commit first && 362 echo 1 >second && 363 git add second && 364 tree=$(git write-tree) && 365 parent=$(git rev-parse HEAD^{commit}) && 366 git commit --gpg-sign -m second && 367 git cat-file commit HEAD && 368 # Avoid trailing whitespace. 369 sed -e "s/^Q//" -e "s/^Z/ /" >commit <<-EOF && 370 Qtree $tree 371 Qparent $parent 372 Qauthor A U Thor <author@example.com> 1112912653 -0700 373 Qcommitter C O Mitter <committer@example.com> 1112912653 -0700 374 Qgpgsig -----BEGIN PGP SIGNATURE----- 375 QZ 376 Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBDRYcY29tbWl0dGVy 377 Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMNd+8AoK1I8mhLHviPH+q2I5fIVgPsEtYC 378 Q AKCTqBh+VabJceXcGIZuF0Ry+udbBQ== 379 Q =tQ0N 380 Q -----END PGP SIGNATURE----- 381 Qgpgsig-sha256 -----BEGIN PGP SIGNATURE----- 382 QZ 383 Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBIBYcY29tbWl0dGVy 384 Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN/NEAn0XO9RYSBj2dFyozi0JKSbssYMtO 385 Q AJwKCQ1BQOtuwz//IjU8TiS+6S4iUw== 386 Q =pIwP 387 Q -----END PGP SIGNATURE----- 388 Q 389 Qsecond 390 EOF 391 head=$(git hash-object -t commit -w commit) && 392 git reset --hard $head && 393 git verify-commit $head 2>actual && 394 grep "Good signature from" actual && 395 ! grep "BAD signature from" actual 396' 397 398test_done 399