1#!/usr/bin/env bash 2 3# TODO: 4# - decryption/verification with signer key not available 5# - verification of signatures from expired/revoked keys 6 7test_description='PGP/MIME signature verification and decryption' 8. $(dirname "$0")/test-lib.sh || exit 1 9. $NOTMUCH_SRCDIR/test/test-lib-emacs.sh || exit 1 10 11################################################## 12 13test_require_emacs 14add_gnupg_home 15 16test_begin_subtest "emacs delivery of signed message" 17test_expect_success \ 18'emacs_fcc_message \ 19 "test signed message 001" \ 20 "This is a test signed message." \ 21 "(mml-secure-message-sign)"' 22 23test_begin_subtest "signed part content-type indexing" 24output=$(notmuch search mimetype:multipart/signed and mimetype:application/pgp-signature | notmuch_search_sanitize) 25test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test signed message 001 (inbox signed)" 26 27test_begin_subtest "signature verification" 28output=$(notmuch show --format=json --verify subject:"test signed message 001" \ 29 | notmuch_json_show_sanitize \ 30 | sed -e 's|"created": [1234567890]*|"created": 946728000|g') 31expected='[[[{"id": "XXXXX", 32 "match": true, 33 "excluded": false, 34 "filename": ["YYYYY"], 35 "timestamp": 946728000, 36 "date_relative": "2000-01-01", 37 "tags": ["inbox","signed"], 38 "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "email": "'"$SELF_EMAIL"'", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'"}]}}, 39 "headers": {"Subject": "test signed message 001", 40 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 41 "To": "test_suite@notmuchmail.org", 42 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 43 "body": [{"id": 1, 44 "sigstatus": [{"status": "good", 45 "fingerprint": "'$FINGERPRINT'", 46 "created": 946728000, 47 "email": "'"$SELF_EMAIL"'", 48 "userid": "'"$SELF_USERID"'"}], 49 "content-type": "multipart/signed", 50 "content": [{"id": 2, 51 "content-type": "text/plain", 52 "content": "This is a test signed message.\n"}, 53 {"id": 3, 54 "content-type": "application/pgp-signature", 55 "content-length": "NONZERO"}]}]}, 56 []]]]' 57test_expect_equal_json \ 58 "$output" \ 59 "$expected" 60 61test_begin_subtest "detection of modified signed contents" 62emacs_fcc_message \ 63 "bad signed message 001" \ 64 "Incriminating stuff. This is a test signed message." \ 65 "(mml-secure-message-sign)" 66 67file=$(notmuch search --output=files subject:"bad signed message 001") 68 69sed -i 's/Incriminating stuff. //' ${file} 70 71output=$(notmuch show --format=json --verify subject:"bad signed message 001" \ 72 | notmuch_json_show_sanitize \ 73 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 74expected='[[[{"id": "XXXXX", 75 "match": true, 76 "excluded": false, 77 "filename": ["YYYYY"], 78 "timestamp": 946728000, 79 "date_relative": "2000-01-01", 80 "tags": ["inbox","signed"], 81 "crypto": {"signed": {"status": [{ "status": "bad", "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'"}]}}, 82 "headers": {"Subject": "bad signed message 001", 83 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 84 "To": "test_suite@notmuchmail.org", 85 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 86 "body": [{"id": 1, 87 "sigstatus": [{"status": "bad", 88 "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'"}], 89 "content-type": "multipart/signed", 90 "content": [{"id": 2, 91 "content-type": "text/plain", 92 "content": "This is a test signed message.\n"}, 93 {"id": 3, 94 "content-type": "application/pgp-signature", 95 "content-length": "NONZERO"}]}]}, 96 []]]]' 97test_expect_equal_json \ 98 "$output" \ 99 "$expected" 100 101test_begin_subtest "corrupted pgp/mime signature" 102emacs_fcc_message \ 103 "bad signed message 002" \ 104 "Incriminating stuff. This is a test signed message." \ 105 "(mml-secure-message-sign)" 106 107file=$(notmuch search --output=files subject:"bad signed message 002") 108 109awk '/-----BEGIN PGP SIGNATURE-----/{flag=1;print;next} \ 110 /-----END PGP SIGNATURE-----/{flag=0;print;next} \ 111 flag{gsub(/[A-Za-z]/,"0");print}!flag{print}' $file > $file.new 112 113rm $file 114mv $file.new $file 115 116output=$(notmuch show --format=json --verify subject:"bad signed message 002" \ 117 | notmuch_json_show_sanitize \ 118 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 119expected='[[[{"id": "XXXXX", 120 "crypto": {}, 121 "match": true, 122 "excluded": false, 123 "filename": ["YYYYY"], 124 "timestamp": 946728000, 125 "date_relative": "2000-01-01", 126 "tags": ["inbox","signed"], 127 "headers": {"Subject": "bad signed message 002", 128 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 129 "To": "test_suite@notmuchmail.org", 130 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 131 "body": [{"id": 1, 132 "sigstatus": [], 133 "content-type": "multipart/signed", 134 "content": [{"id": 2, 135 "content-type": "text/plain", 136 "content": "Incriminating stuff. This is a test signed message.\n"}, 137 {"id": 3, 138 "content-type": "application/pgp-signature", 139 "content-length": "NONZERO"}]}]}, 140 []]]]' 141test_expect_equal_json \ 142 "$output" \ 143 "$expected" 144 145test_begin_subtest "signature verification without full user ID validity" 146# give the key no owner trust, removes validity on all user IDs of the 147# certificate in the absence of other trusted certifiers: 148gpg --quiet --batch --no-tty --export-ownertrust > "$GNUPGHOME/ownertrust.bak" 149echo "${FINGERPRINT}:3:" | gpg --quiet --batch --no-tty --import-ownertrust 150output=$(notmuch show --format=json --verify subject:"test signed message 001" \ 151 | notmuch_json_show_sanitize \ 152 | sed -e 's|"created": [1234567890]*|"created": 946728000|g') 153expected='[[[{"id": "XXXXX", 154 "match": true, 155 "excluded": false, 156 "filename": ["YYYYY"], 157 "timestamp": 946728000, 158 "date_relative": "2000-01-01", 159 "tags": ["inbox","signed"], 160 "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'"}]}}, 161 "headers": {"Subject": "test signed message 001", 162 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 163 "To": "test_suite@notmuchmail.org", 164 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 165 "body": [{"id": 1, 166 "sigstatus": [{"status": "good", 167 "fingerprint": "'$FINGERPRINT'", 168 "created": 946728000}], 169 "content-type": "multipart/signed", 170 "content": [{"id": 2, 171 "content-type": "text/plain", 172 "content": "This is a test signed message.\n"}, 173 {"id": 3, 174 "content-type": "application/pgp-signature", 175 "content-length": "NONZERO"}]}]}, 176 []]]]' 177test_expect_equal_json \ 178 "$output" \ 179 "$expected" 180gpg --quiet --batch --no-tty --import-ownertrust < "$GNUPGHOME/ownertrust.bak" 181 182test_begin_subtest "signature verification with signer key unavailable" 183# move the gnupghome temporarily out of the way 184mv "${GNUPGHOME}"{,.bak} 185output=$(notmuch show --format=json --verify subject:"test signed message 001" \ 186 | notmuch_json_show_sanitize \ 187 | sed -e 's|"created": [1234567890]*|"created": 946728000|g') 188expected='[[[{"id": "XXXXX", 189 "match": true, 190 "excluded": false, 191 "filename": ["YYYYY"], 192 "timestamp": 946728000, 193 "date_relative": "2000-01-01", 194 "tags": ["inbox","signed"], 195 "crypto": {"signed": {"status": [{"errors": {"key-missing": true}, "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'", "status": "error"}]}}, 196 "headers": {"Subject": "test signed message 001", 197 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 198 "To": "test_suite@notmuchmail.org", 199 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 200 "body": [{"id": 1, 201 "sigstatus": [{"status": "error", 202 "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'", 203 "errors": {"key-missing": true}}], 204 "content-type": "multipart/signed", 205 "content": [{"id": 2, 206 "content-type": "text/plain", 207 "content": "This is a test signed message.\n"}, 208 {"id": 3, 209 "content-type": "application/pgp-signature", 210 "content-length": "NONZERO"}]}]}, 211 []]]]' 212test_expect_equal_json \ 213 "$output" \ 214 "$expected" 215mv "${GNUPGHOME}"{.bak,} 216 217test_begin_subtest "emacs delivery of encrypted message with attachment" 218# create a test encrypted message with attachment 219cat <<EOF >TESTATTACHMENT 220This is a test file. 221EOF 222test_expect_success \ 223'emacs_fcc_message \ 224 "test encrypted message 001" \ 225 "This is a test encrypted message.\n" \ 226 "(mml-attach-file \"TESTATTACHMENT\") (mml-secure-message-encrypt)"' 227 228test_begin_subtest "encrypted part content-type indexing" 229output=$(notmuch search mimetype:multipart/encrypted and mimetype:application/pgp-encrypted and mimetype:application/octet-stream | notmuch_search_sanitize) 230test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; test encrypted message 001 (encrypted inbox)" 231 232test_begin_subtest "decryption, --format=text" 233output=$(notmuch show --format=text --decrypt=true subject:"test encrypted message 001" \ 234 | notmuch_show_sanitize_all \ 235 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 236expected='message{ id:XXXXX depth:0 match:1 excluded:0 filename:XXXXX 237header{ 238Notmuch Test Suite <test_suite@notmuchmail.org> (2000-01-01) (encrypted inbox) 239Subject: test encrypted message 001 240From: Notmuch Test Suite <test_suite@notmuchmail.org> 241To: test_suite@notmuchmail.org 242Date: Sat, 01 Jan 2000 12:00:00 +0000 243header} 244body{ 245part{ ID: 1, Content-type: multipart/encrypted 246part{ ID: 2, Content-type: application/pgp-encrypted 247Non-text part: application/pgp-encrypted 248part} 249part{ ID: 3, Content-type: multipart/mixed 250part{ ID: 4, Content-type: text/plain 251This is a test encrypted message. 252part} 253attachment{ ID: 5, Filename: TESTATTACHMENT, Content-type: application/octet-stream 254Non-text part: application/octet-stream 255attachment} 256part} 257part} 258body} 259message}' 260test_expect_equal \ 261 "$output" \ 262 "$expected" 263 264test_begin_subtest "decryption, --format=json" 265output=$(notmuch show --format=json --decrypt=true subject:"test encrypted message 001" \ 266 | notmuch_json_show_sanitize \ 267 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 268expected='[[[{"id": "XXXXX", 269 "match": true, 270 "excluded": false, 271 "filename": ["YYYYY"], 272 "timestamp": 946728000, 273 "date_relative": "2000-01-01", 274 "tags": ["encrypted","inbox"], 275 "crypto": {"decrypted": {"status": "full"}}, 276 "headers": {"Subject": "test encrypted message 001", 277 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 278 "To": "test_suite@notmuchmail.org", 279 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 280 "body": [{"id": 1, 281 "encstatus": [{"status": "good"}], 282 "content-type": "multipart/encrypted", 283 "content": [{"id": 2, 284 "content-type": "application/pgp-encrypted", 285 "content-length": "NONZERO"}, 286 {"id": 3, 287 "content-type": "multipart/mixed", 288 "content": [{"id": 4, 289 "content-type": "text/plain", 290 "content": "This is a test encrypted message.\n"}, 291 {"id": 5, 292 "content-type": "application/octet-stream", 293 "content-disposition": "attachment", 294 "content-length": "NONZERO", 295 "content-transfer-encoding": "base64", 296 "filename": "TESTATTACHMENT"}]}]}]}, 297 []]]]' 298test_expect_equal_json \ 299 "$output" \ 300 "$expected" 301 302test_begin_subtest "decryption, --format=json, --part=4" 303output=$(notmuch show --format=json --part=4 --decrypt=true subject:"test encrypted message 001" \ 304 | notmuch_json_show_sanitize \ 305 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 306expected='{"id": 4, 307 "content-type": "text/plain", 308 "content": "This is a test encrypted message.\n"}' 309test_expect_equal_json \ 310 "$output" \ 311 "$expected" 312 313test_begin_subtest "decrypt attachment (--part=5 --format=raw)" 314notmuch show \ 315 --format=raw \ 316 --part=5 \ 317 --decrypt=true \ 318 subject:"test encrypted message 001" >OUTPUT 319test_expect_equal_file TESTATTACHMENT OUTPUT 320 321test_begin_subtest "decryption failure with missing key" 322mv "${GNUPGHOME}"{,.bak} 323output=$(notmuch show --format=json --decrypt=true subject:"test encrypted message 001" \ 324 | notmuch_json_show_sanitize \ 325 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 326expected='[[[{"id": "XXXXX", 327 "crypto": {}, 328 "match": true, 329 "excluded": false, 330 "filename": ["YYYYY"], 331 "timestamp": 946728000, 332 "date_relative": "2000-01-01", 333 "tags": ["encrypted","inbox"], 334 "headers": {"Subject": "test encrypted message 001", 335 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 336 "To": "test_suite@notmuchmail.org", 337 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 338 "body": [{"id": 1, 339 "encstatus": [{"status": "bad"}], 340 "content-type": "multipart/encrypted", 341 "content": [{"id": 2, 342 "content-type": "application/pgp-encrypted", 343 "content-length": "NONZERO"}, 344 {"id": 3, 345 "content-type": "application/octet-stream", 346 "content-length": "NONZERO"}]}]}, 347 []]]]' 348test_expect_equal_json \ 349 "$output" \ 350 "$expected" 351mv "${GNUPGHOME}"{.bak,} 352 353test_begin_subtest "emacs delivery of encrypted + signed message" 354test_expect_success \ 355'emacs_fcc_message \ 356 "test encrypted message 002" \ 357 "This is another test encrypted message.\n" \ 358 "(mml-secure-message-sign-encrypt)"' 359 360test_begin_subtest "decryption + signature verification" 361output=$(notmuch show --format=json --decrypt=true subject:"test encrypted message 002" \ 362 | notmuch_json_show_sanitize \ 363 | sed -e 's|"created": [1234567890]*|"created": 946728000|g') 364expected='[[[{"id": "XXXXX", 365 "match": true, 366 "excluded": false, 367 "filename": ["YYYYY"], 368 "timestamp": 946728000, 369 "date_relative": "2000-01-01", 370 "tags": ["encrypted","inbox"], 371 "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'"}], 372 "encrypted": true }, 373 "decrypted": {"status": "full"}}, 374 "headers": {"Subject": "test encrypted message 002", 375 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 376 "To": "test_suite@notmuchmail.org", 377 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 378 "body": [{"id": 1, 379 "encstatus": [{"status": "good"}], 380 "sigstatus": [{"status": "good", 381 "fingerprint": "'$FINGERPRINT'", 382 "created": 946728000, 383 "email": "'"$SELF_EMAIL"'", 384 "userid": "'"$SELF_USERID"'"}], 385 "content-type": "multipart/encrypted", 386 "content": [{"id": 2, 387 "content-type": "application/pgp-encrypted", 388 "content-length": "NONZERO"}, 389 {"id": 3, 390 "content-type": "text/plain", 391 "content": "This is another test encrypted message.\n"}]}]}, 392 []]]]' 393test_expect_equal_json \ 394 "$output" \ 395 "$expected" 396 397test_begin_subtest "reply to encrypted message" 398output=$(notmuch reply --decrypt=true subject:"test encrypted message 002" \ 399 | notmuch_drop_mail_headers In-Reply-To References) 400expected='From: Notmuch Test Suite <test_suite@notmuchmail.org> 401Subject: Re: test encrypted message 002 402To: test_suite@notmuchmail.org 403 404On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote: 405> This is another test encrypted message.' 406test_expect_equal \ 407 "$output" \ 408 "$expected" 409 410test_begin_subtest "Reply within emacs to an encrypted message" 411test_emacs "(let ((message-hidden-headers '()) 412 (notmuch-crypto-process-mime 't)) 413 (notmuch-show \"subject:test.encrypted.message.002\") 414 (notmuch-show-reply) 415 (test-output))" 416grep -v -e '^In-Reply-To:' -e '^References:' -e '^Fcc:' < OUTPUT > OUTPUT.clean 417cat <<EOF >EXPECTED 418From: Notmuch Test Suite <test_suite@notmuchmail.org> 419To: test_suite@notmuchmail.org 420Subject: Re: test encrypted message 002 421--text follows this line-- 422<#secure method=pgpmime mode=signencrypt> 423Notmuch Test Suite <test_suite@notmuchmail.org> writes: 424 425> This is another test encrypted message. 426EOF 427test_expect_equal_file EXPECTED OUTPUT.clean 428 429test_begin_subtest "signature verification with revoked key" 430# generate revocation certificate and load it to revoke key 431echo "y 4321 433Notmuch Test Suite key revocation (automated) $(date '+%F_%T%z') 434 435y 436 437" \ 438 | gpg --no-tty --quiet --command-fd 0 --armor --gen-revoke "0x${FINGERPRINT}!" 2>/dev/null \ 439 | gpg --no-tty --quiet --import 440output=$(notmuch show --format=json --verify subject:"test signed message 001" \ 441 | notmuch_json_show_sanitize \ 442 | sed -e 's|"created": [1234567890]*|"created": 946728000|') 443expected='[[[{"id": "XXXXX", 444 "match": true, 445 "excluded": false, 446 "filename": ["YYYYY"], 447 "timestamp": 946728000, 448 "date_relative": "2000-01-01", 449 "tags": ["inbox","signed"], 450 "crypto": {"signed": {"status": [{"errors": {"key-revoked": true}, "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'", "status": "error"}]}}, 451 "headers": {"Subject": "test signed message 001", 452 "From": "Notmuch Test Suite <test_suite@notmuchmail.org>", 453 "To": "test_suite@notmuchmail.org", 454 "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, 455 "body": [{"id": 1, 456 "sigstatus": [{"status": "error", 457 "keyid": "6D92612D94E46381", 458 "errors": {"key-revoked": true}}], 459 "content-type": "multipart/signed", 460 "content": [{"id": 2, 461 "content-type": "text/plain", 462 "content": "This is a test signed message.\n"}, 463 {"id": 3, 464 "content-type": "application/pgp-signature", 465 "content-length": "NONZERO"}]}]}, 466 []]]]' 467test_expect_equal_json \ 468 "$output" \ 469 "$expected" 470 471test_done 472