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