Git fork
at reftables-rust 470 lines 16 kB view raw
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 echo 13>file && test_tick && git commit -a -m thirteenth -S"${GPGSSH_KEY_ECDSA}" && 79 git tag thirteenth-signed-ecdsa 80' 81 82test_expect_success GPGSSH 'sign commits using literal public keys with ssh-agent' ' 83 test_when_finished "test_unconfig commit.gpgsign" && 84 test_config gpg.format ssh && 85 eval $(ssh-agent -T || ssh-agent) && 86 test_when_finished "kill ${SSH_AGENT_PID}" && 87 test_when_finished "test_unconfig user.signingkey" && 88 mkdir tmpdir && 89 TMPDIR="$(pwd)/tmpdir" && 90 ( 91 export TMPDIR && 92 ssh-add "${GPGSSH_KEY_PRIMARY}" && 93 echo 1 >file && git add file && 94 git commit -a -m rsa-inline -S"$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && 95 echo 2 >file && 96 git config user.signingkey "$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && 97 git commit -a -m rsa-config -S && 98 ssh-add "${GPGSSH_KEY_ECDSA}" && 99 echo 3 >file && 100 git commit -a -m ecdsa-inline -S"key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && 101 echo 4 >file && 102 git config user.signingkey "key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && 103 git commit -a -m ecdsa-config -S 104 ) && 105 find tmpdir -type f >tmpfiles && 106 test_must_be_empty tmpfiles 107' 108 109test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed commits with keys having defined lifetimes' ' 110 test_when_finished "test_unconfig commit.gpgsign" && 111 test_config gpg.format ssh && 112 113 echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" && 114 git tag expired-signed && 115 116 echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" && 117 git tag notyetvalid-signed && 118 119 echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" && 120 git tag timeboxedvalid-signed && 121 122 echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" && 123 git tag timeboxedinvalid-signed 124' 125 126test_expect_success GPGSSH 'verify and show signatures' ' 127 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 128 test_config gpg.mintrustlevel UNDEFINED && 129 ( 130 for commit in initial second merge fourth-signed \ 131 fifth-signed sixth-signed seventh-signed tenth-signed \ 132 eleventh-signed 133 do 134 git verify-commit $commit && 135 git show --pretty=short --show-signature $commit >actual && 136 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 137 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 138 echo $commit OK || exit 1 139 done 140 ) && 141 ( 142 for commit in merge^2 fourth-unsigned sixth-unsigned \ 143 seventh-unsigned ninth-unsigned 144 do 145 test_must_fail git verify-commit $commit && 146 git show --pretty=short --show-signature $commit >actual && 147 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 148 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 149 echo $commit OK || exit 1 150 done 151 ) && 152 ( 153 for commit in eighth-signed-alt twelfth-signed-alt 154 do 155 git show --pretty=short --show-signature $commit >actual && 156 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 157 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 158 grep "${GPGSSH_KEY_NOT_TRUSTED}" actual && 159 echo $commit OK || exit 1 160 done 161 ) 162' 163 164test_expect_success GPGSSH 'verify-commit exits failure on untrusted signature' ' 165 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 166 test_must_fail git verify-commit eighth-signed-alt 2>actual && 167 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 168 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 169 grep "${GPGSSH_KEY_NOT_TRUSTED}" actual 170' 171 172test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure on expired signature key' ' 173 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 174 test_must_fail git verify-commit expired-signed 2>actual && 175 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual 176' 177 178test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure on not yet valid signature key' ' 179 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 180 test_must_fail git verify-commit notyetvalid-signed 2>actual && 181 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual 182' 183 184test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit succeeds with commit date and key validity matching' ' 185 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 186 git verify-commit timeboxedvalid-signed 2>actual && 187 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 188 ! grep "${GPGSSH_BAD_SIGNATURE}" actual 189' 190 191test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure with commit date outside of key validity' ' 192 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 193 test_must_fail git verify-commit timeboxedinvalid-signed 2>actual && 194 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual 195' 196 197test_expect_success GPGSSH 'verify-commit exits success with matching minTrustLevel' ' 198 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 199 test_config gpg.minTrustLevel fully && 200 git verify-commit sixth-signed 201' 202 203test_expect_success GPGSSH 'verify-commit exits success with low minTrustLevel' ' 204 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 205 test_config gpg.minTrustLevel marginal && 206 git verify-commit sixth-signed 207' 208 209test_expect_success GPGSSH 'verify-commit exits failure with high minTrustLevel' ' 210 test_config gpg.minTrustLevel ultimate && 211 test_must_fail git verify-commit eighth-signed-alt 212' 213 214test_expect_success GPGSSH 'verify signatures with --raw' ' 215 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 216 ( 217 for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed 218 do 219 git verify-commit --raw $commit 2>actual && 220 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 221 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 222 echo $commit OK || exit 1 223 done 224 ) && 225 ( 226 for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned 227 do 228 test_must_fail git verify-commit --raw $commit 2>actual && 229 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 230 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 231 echo $commit OK || exit 1 232 done 233 ) && 234 ( 235 for commit in eighth-signed-alt 236 do 237 test_must_fail git verify-commit --raw $commit 2>actual && 238 grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual && 239 ! grep "${GPGSSH_BAD_SIGNATURE}" actual && 240 echo $commit OK || exit 1 241 done 242 ) 243' 244 245test_expect_success GPGSSH 'proper header is used for hash algorithm' ' 246 git cat-file commit fourth-signed >output && 247 grep "^$(test_oid header) -----BEGIN SSH SIGNATURE-----" output 248' 249 250test_expect_success GPGSSH 'show signed commit with signature' ' 251 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 252 git show -s initial >commit && 253 git show -s --show-signature initial >show && 254 git verify-commit -v initial >verify.1 2>verify.2 && 255 git cat-file commit initial >cat && 256 grep -v -e "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" -e "Warning: " show >show.commit && 257 grep -e "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" -e "Warning: " show >show.gpg && 258 grep -v "^ " cat | grep -v "^gpgsig.* " >cat.commit && 259 test_cmp show.commit commit && 260 test_cmp show.gpg verify.2 && 261 test_cmp cat.commit verify.1 262' 263 264test_expect_success GPGSSH 'detect fudged signature' ' 265 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 266 git cat-file commit seventh-signed >raw && 267 sed -e "s/^seventh/7th forged/" raw >forged1 && 268 git hash-object -w -t commit forged1 >forged1.commit && 269 test_must_fail git verify-commit $(cat forged1.commit) && 270 git show --pretty=short --show-signature $(cat forged1.commit) >actual1 && 271 grep "${GPGSSH_BAD_SIGNATURE}" actual1 && 272 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual1 && 273 ! grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual1 274' 275 276test_expect_success GPGSSH 'detect fudged signature with NUL' ' 277 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 278 git cat-file commit seventh-signed >raw && 279 cat raw >forged2 && 280 echo Qwik | tr "Q" "\000" >>forged2 && 281 git hash-object --literally -w -t commit forged2 >forged2.commit && 282 test_must_fail git verify-commit $(cat forged2.commit) && 283 git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && 284 grep "${GPGSSH_BAD_SIGNATURE}" actual2 && 285 ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual2 286' 287 288test_expect_success GPGSSH 'amending already signed commit' ' 289 test_config gpg.format ssh && 290 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && 291 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 292 git checkout -f fourth-signed^0 && 293 git commit --amend -S --no-edit && 294 git verify-commit HEAD && 295 git show -s --show-signature HEAD >actual && 296 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && 297 ! grep "${GPGSSH_BAD_SIGNATURE}" actual 298' 299 300test_expect_success GPGSSH 'show good signature with custom format' ' 301 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 302 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && 303 cat >expect.tmpl <<-\EOF && 304 G 305 FINGERPRINT 306 principal with number 1 307 FINGERPRINT 308 309 EOF 310 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 311 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && 312 test_cmp expect actual 313' 314 315test_expect_success GPGSSH 'show bad signature with custom format' ' 316 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 317 cat >expect <<-\EOF && 318 B 319 320 321 322 323 EOF 324 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && 325 test_cmp expect actual 326' 327 328test_expect_success GPGSSH 'show untrusted signature with custom format' ' 329 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 330 cat >expect.tmpl <<-\EOF && 331 U 332 FINGERPRINT 333 334 FINGERPRINT 335 336 EOF 337 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && 338 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_UNTRUSTED}" | awk "{print \$2;}") && 339 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 340 test_cmp expect actual 341' 342 343test_expect_success GPGSSH 'show untrusted signature with undefined trust level' ' 344 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 345 cat >expect.tmpl <<-\EOF && 346 undefined 347 FINGERPRINT 348 349 FINGERPRINT 350 351 EOF 352 git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && 353 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_UNTRUSTED}" | awk "{print \$2;}") && 354 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 355 test_cmp expect actual 356' 357 358test_expect_success GPGSSH 'show untrusted signature with ultimate trust level' ' 359 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 360 cat >expect.tmpl <<-\EOF && 361 fully 362 FINGERPRINT 363 principal with number 1 364 FINGERPRINT 365 366 EOF 367 git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && 368 FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && 369 sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && 370 test_cmp expect actual 371' 372 373test_expect_success GPGSSH 'show lack of signature with custom format' ' 374 cat >expect <<-\EOF && 375 N 376 377 378 379 380 EOF 381 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && 382 test_cmp expect actual 383' 384 385test_expect_success GPGSSH 'log.showsignature behaves like --show-signature' ' 386 test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && 387 test_config log.showsignature true && 388 git show initial >actual && 389 grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual 390' 391 392test_expect_success GPGSSH 'check config gpg.format values' ' 393 test_config gpg.format ssh && 394 test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && 395 test_config gpg.format ssh && 396 git commit -S --amend -m "success" && 397 test_config gpg.format OpEnPgP && 398 test_must_fail git commit -S --amend -m "fail" 399' 400 401test_expect_failure GPGSSH 'detect fudged commit with double signature (TODO)' ' 402 sed -e "/gpgsig/,/END PGP/d" forged1 >double-base && 403 sed -n -e "/gpgsig/,/END PGP/p" forged1 | \ 404 sed -e "s/^$(test_oid header)//;s/^ //" | gpg --dearmor >double-sig1.sig && 405 gpg -o double-sig2.sig -u 29472784 --detach-sign double-base && 406 cat double-sig1.sig double-sig2.sig | gpg --enarmor >double-combined.asc && 407 sed -e "s/^\(-.*\)ARMORED FILE/\1SIGNATURE/;1s/^/$(test_oid header) /;2,\$s/^/ /" \ 408 double-combined.asc > double-gpgsig && 409 sed -e "/committer/r double-gpgsig" double-base >double-commit && 410 git hash-object -w -t commit double-commit >double-commit.commit && 411 test_must_fail git verify-commit $(cat double-commit.commit) && 412 git show --pretty=short --show-signature $(cat double-commit.commit) >double-actual && 413 grep "BAD signature from" double-actual && 414 grep "Good signature from" double-actual 415' 416 417test_expect_failure GPGSSH 'show double signature with custom format (TODO)' ' 418 cat >expect <<-\EOF && 419 E 420 421 422 423 424 EOF 425 git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat double-commit.commit) >actual && 426 test_cmp expect actual 427' 428 429 430test_expect_failure GPGSSH 'verify-commit verifies multiply signed commits (TODO)' ' 431 git init multiply-signed && 432 cd multiply-signed && 433 test_commit first && 434 echo 1 >second && 435 git add second && 436 tree=$(git write-tree) && 437 parent=$(git rev-parse HEAD^{commit}) && 438 git commit --gpg-sign -m second && 439 git cat-file commit HEAD && 440 # Avoid trailing whitespace. 441 sed -e "s/^Q//" -e "s/^Z/ /" >commit <<-EOF && 442 Qtree $tree 443 Qparent $parent 444 Qauthor A U Thor <author@example.com> 1112912653 -0700 445 Qcommitter C O Mitter <committer@example.com> 1112912653 -0700 446 Qgpgsig -----BEGIN PGP SIGNATURE----- 447 QZ 448 Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBDRYcY29tbWl0dGVy 449 Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMNd+8AoK1I8mhLHviPH+q2I5fIVgPsEtYC 450 Q AKCTqBh+VabJceXcGIZuF0Ry+udbBQ== 451 Q =tQ0N 452 Q -----END PGP SIGNATURE----- 453 Qgpgsig-sha256 -----BEGIN PGP SIGNATURE----- 454 QZ 455 Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBIBYcY29tbWl0dGVy 456 Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN/NEAn0XO9RYSBj2dFyozi0JKSbssYMtO 457 Q AJwKCQ1BQOtuwz//IjU8TiS+6S4iUw== 458 Q =pIwP 459 Q -----END PGP SIGNATURE----- 460 Q 461 Qsecond 462 EOF 463 head=$(git hash-object -t commit -w commit) && 464 git reset --hard $head && 465 git verify-commit $head 2>actual && 466 grep "Good signature from" actual && 467 ! grep "BAD signature from" actual 468' 469 470test_done