[PATCH 07/20] cli/show: emit new whole-message crypto status output
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Thu May 10 22:55:31 PDT 2018
This allows MUAs that don't want to think about per-mime-part
cryptographic status to have a simple high-level overview of the
message's cryptographic state.
Sensibly structured encrypted and/or signed messages will work fine
with this. The only requirement for the simplest encryption + signing
is that the message have all of its encryption and signing protection
(the "cryptographic envelope") in a contiguous set of MIME layers at
the very outside of the message itself.
This is because messages with some subparts signed or encrypted, but
with other subparts with no cryptographic protection is very difficult
to reason about, and even harder for the user to make sense of or work
with.
For further characterization of the Cryptographic Envelope and some of
the usability tradeoffs, see here:
https://dkg.fifthhorseman.net/blog/e-mail-cryptography.html#cryptographic-envelope
---
devel/schemata | 21 ++++++++++++++++++++-
notmuch-show.c | 27 +++++++++++++++++++++++++++
test/T350-crypto.sh | 19 +++++++++++++++----
test/T355-smime.sh | 5 +++--
4 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/devel/schemata b/devel/schemata
index 42b1bcf3..6370eeac 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -14,7 +14,7 @@ are interleaved. Keys are printed as keywords (symbols preceded by a
colon), e.g. (:id "123" :time 54321 :from "foobar"). Null is printed as
nil, true as t and false as nil.
-This is version 4 of the structured output format.
+This is version 5 of the structured output format.
Version history
---------------
@@ -34,6 +34,9 @@ v4
- replace signature error integer bitmask with a set of flags for
individual errors.
+v5
+- added message.crypto to identify overall message cryptographic state
+
Common non-terminals
--------------------
@@ -73,9 +76,25 @@ message = {
tags: [string*],
headers: headers,
+ crypto?: crypto, # omitted if crypto disabled, or if no part was signed or encrypted.
body?: [part] # omitted if --body=false
}
+# when showing the message, was any or all of it decrypted?
+msgdecstatus: "full"|"partial"
+
+# The overall cryptographic state of the message as a whole:
+crypto = {
+ signed?: {
+ status: sigstatus,
+ # was the set of signatures described under encrypted cover?
+ encrypted: bool,
+ },
+ decrypted?: {
+ status: msgdecstatus,
+ }
+}
+
# A MIME part (format_part_sprinter)
part = {
id: int|string, # part id (currently DFS part number)
diff --git a/notmuch-show.c b/notmuch-show.c
index f0be8060..fea99bff 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -616,6 +616,33 @@ format_part_sprinter (const void *ctx, sprinter_t *sp, mime_node_t *node,
format_part_sprinter (ctx, sp, mime_node_child (node, 0), true, include_html);
sp->end (sp);
}
+
+ const _notmuch_message_crypto_t *msg_crypto = mime_node_get_message_crypto_status (node);
+ if (msg_crypto->sig_list ||
+ msg_crypto->decryption_status != NOTMUCH_MESSAGE_DECRYPTED_NONE) {
+ sp->map_key (sp, "crypto");
+ sp->begin_map (sp);
+ if (msg_crypto->sig_list) {
+ sp->map_key (sp, "signed");
+ sp->begin_map (sp);
+ sp->map_key (sp, "status");
+ format_part_sigstatus_sprinter (sp, msg_crypto->sig_list);
+ if (msg_crypto->signature_encrypted) {
+ sp->map_key (sp, "encrypted");
+ sp->boolean (sp, msg_crypto->signature_encrypted);
+ }
+ sp->end (sp);
+ }
+ if (msg_crypto->decryption_status != NOTMUCH_MESSAGE_DECRYPTED_NONE) {
+ sp->map_key (sp, "decrypted");
+ sp->begin_map (sp);
+ sp->map_key (sp, "status");
+ sp->string (sp, msg_crypto->decryption_status == NOTMUCH_MESSAGE_DECRYPTED_FULL ? "full" : "partial");
+ sp->end (sp);
+ }
+ sp->end (sp);
+ }
+
sp->end (sp);
return;
}
diff --git a/test/T350-crypto.sh b/test/T350-crypto.sh
index b5067346..4c0f6f46 100755
--- a/test/T350-crypto.sh
+++ b/test/T350-crypto.sh
@@ -27,7 +27,7 @@ test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; t
test_begin_subtest "signature verification"
output=$(notmuch show --format=json --verify subject:"test signed message 001" \
| notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|g')
expected='[[[{"id": "XXXXX",
"match": true,
"excluded": false,
@@ -35,6 +35,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'"}]}},
"headers": {"Subject": "test signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -75,6 +76,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{ "status": "bad", "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'"}]}},
"headers": {"Subject": "bad signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -144,7 +146,7 @@ echo "${FINGERPRINT}:6:" | gpg --no-tty --import-ownertrust >>"$GNUPGHOME"/trust
gpg --no-tty --check-trustdb >>"$GNUPGHOME"/trust.log 2>&1
output=$(notmuch show --format=json --verify subject:"test signed message 001" \
| notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|g')
expected='[[[{"id": "XXXXX",
"match": true,
"excluded": false,
@@ -152,6 +154,8 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'",
+ "userid": "Notmuch Test Suite <test_suite at notmuchmail.org> (INSECURE!)"}]}},
"headers": {"Subject": "test signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -178,7 +182,7 @@ test_begin_subtest "signature verification with signer key unavailable"
mv "${GNUPGHOME}"{,.bak}
output=$(notmuch show --format=json --verify subject:"test signed message 001" \
| notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|g')
expected='[[[{"id": "XXXXX",
"match": true,
"excluded": false,
@@ -186,6 +190,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{"errors": {"key-missing": true}, "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'", "status": "error"}]}},
"headers": {"Subject": "test signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -265,6 +270,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["encrypted","inbox"],
+ "crypto": {"decrypted": {"status": "full"}},
"headers": {"Subject": "test encrypted message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -352,7 +358,7 @@ test_begin_subtest "decryption + signature verification"
test_subtest_broken_gmime_2
output=$(notmuch show --format=json --decrypt=true subject:"test encrypted message 002" \
| notmuch_json_show_sanitize \
- | sed -e 's|"created": [1234567890]*|"created": 946728000|')
+ | sed -e 's|"created": [1234567890]*|"created": 946728000|g')
expected='[[[{"id": "XXXXX",
"match": true,
"excluded": false,
@@ -360,6 +366,10 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["encrypted","inbox"],
+ "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'",
+ "userid": "Notmuch Test Suite <test_suite at notmuchmail.org> (INSECURE!)"}],
+ "encrypted": true },
+ "decrypted": {"status": "full"}},
"headers": {"Subject": "test encrypted message 002",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
@@ -434,6 +444,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{"errors": {"key-revoked": true}, "keyid": "'$(echo $FINGERPRINT | cut -c 25-)'", "status": "error"}]}},
"headers": {"Subject": "test signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
diff --git a/test/T355-smime.sh b/test/T355-smime.sh
index be45e3b1..d947e866 100755
--- a/test/T355-smime.sh
+++ b/test/T355-smime.sh
@@ -56,8 +56,8 @@ else
fi
output=$(notmuch show --format=json --verify subject:"test signed message 001" \
| notmuch_json_show_sanitize \
- | sed -e 's|"created": [-1234567890]*|"created": 946728000|' \
- -e 's|"expires": [-1234567890]*|"expires": 424242424|' )
+ | sed -e 's|"created": [-1234567890]*|"created": 946728000|g' \
+ -e 's|"expires": [-1234567890]*|"expires": 424242424|g' )
expected='[[[{"id": "XXXXX",
"match": true,
"excluded": false,
@@ -65,6 +65,7 @@ expected='[[[{"id": "XXXXX",
"timestamp": 946728000,
"date_relative": "2000-01-01",
"tags": ["inbox","signed"],
+ "crypto": {"signed": {"status": [{"fingerprint": "'$FINGERPRINT'", "status": "good",'$USERID' "expires": 424242424, "created": 946728000}]}},
"headers": {"Subject": "test signed message 001",
"From": "Notmuch Test Suite <test_suite at notmuchmail.org>",
"To": "test_suite at notmuchmail.org",
--
2.17.0
More information about the notmuch
mailing list