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