From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id CD92E6DE135E for ; Wed, 24 Apr 2019 11:31:24 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.151 X-Spam-Level: X-Spam-Status: No, score=-0.151 tagged_above=-999 required=5 tests=[AWL=0.050, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YymPHFDhUk1t for ; Wed, 24 Apr 2019 11:31:24 -0700 (PDT) Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118]) by arlo.cworth.org (Postfix) with ESMTPS id 7B89C6DE0F4A for ; Wed, 24 Apr 2019 11:31:23 -0700 (PDT) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019; t=1556130682; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=6M6QfkKE0wH8nhtX2gS+OdbXFmjR97uOrUgI1PAyK3g=; b=6AR+hBKqrcv6CVO4hoXF2alb3T+kgDKiGINrWeCyMJAgjlK9crn6ot9p ZKFQWuiuKBtF9ue3wEAhsX+GaBkNAg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019rsa; t=1556130682; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=6M6QfkKE0wH8nhtX2gS+OdbXFmjR97uOrUgI1PAyK3g=; b=PhuxFV9WmgAutP0HS5OYgdRJe5zAaISoRFjMXnLJLdqinmkaoQ93ERkA nVpam6H4jojGsPdC7m+pj2Y1UzDBnJ7js2z4yWUTZt3K15PTX3dsGr7R6f kCSP5VLAQCYuwjIWtRggfHhkofE2Qz6UBNyrlcS8h1gJga3NbViGgW7W8E lPZhvWpNhq95NtaNCK8mA6iK2o15Bj4Ih8tQUVYZcAebDI5Yx2xveW5YC2 IBpLGnAp1/jpqTkhJ87TAL9sGz0VhBkig/fw4LmMxre89QXRJmX9qZHaI3 yANJK5NoO4xOXFVvtoZ8DdTrLnJDvD+XXgPEbGTjrUCFS+QnL3CJFQ== Received: from fifthhorseman.net (unknown [38.109.115.130]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by che.mayfirst.org (Postfix) with ESMTPSA id 2B068F99E for ; Wed, 24 Apr 2019 14:31:22 -0400 (EDT) Received: by fifthhorseman.net (Postfix, from userid 1000) id 62D7B20A2F; Wed, 24 Apr 2019 14:31:18 -0400 (EDT) From: Daniel Kahn Gillmor To: Notmuch Mail Subject: [PATCH 4/4] cli/show: emit new whole-message crypto status output Date: Wed, 24 Apr 2019 14:31:13 -0400 Message-Id: <20190424183113.29242-5-dkg@fifthhorseman.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190424183113.29242-1-dkg@fifthhorseman.net> References: <20190424183113.29242-1-dkg@fifthhorseman.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2019 18:31:24 -0000 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 | 18 ++++++++++++++++++ notmuch-show.c | 29 +++++++++++++++++++++++++++++ test/T350-crypto.sh | 19 +++++++++++++++---- test/T355-smime.sh | 5 +++-- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/devel/schemata b/devel/schemata index 42b1bcf3..33633ab3 100644 --- a/devel/schemata +++ b/devel/schemata @@ -33,6 +33,8 @@ v3 v4 - replace signature error integer bitmask with a set of flags for individual errors. +- (notmuch 0.29) added message.crypto to identify overall message + cryptographic state Common non-terminals -------------------- @@ -73,9 +75,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 88699e90..575b1654 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -648,6 +648,35 @@ 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); } + + if (notmuch_format_version >= 4) { + 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 2f793e96..a6d8bebd 100755 --- a/test/T350-crypto.sh +++ b/test/T350-crypto.sh @@ -25,7 +25,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, @@ -33,6 +33,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 ", "To": "test_suite@notmuchmail.org", @@ -73,6 +74,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 ", "To": "test_suite@notmuchmail.org", @@ -142,7 +144,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, @@ -150,6 +152,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 (INSECURE!)"}]}}, "headers": {"Subject": "test signed message 001", "From": "Notmuch Test Suite ", "To": "test_suite@notmuchmail.org", @@ -176,7 +180,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, @@ -184,6 +188,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 ", "To": "test_suite@notmuchmail.org", @@ -263,6 +268,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 ", "To": "test_suite@notmuchmail.org", @@ -350,7 +356,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, @@ -358,6 +364,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 (INSECURE!)"}], + "encrypted": true }, + "decrypted": {"status": "full"}}, "headers": {"Subject": "test encrypted message 002", "From": "Notmuch Test Suite ", "To": "test_suite@notmuchmail.org", @@ -433,6 +443,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 ", "To": "test_suite@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 ", "To": "test_suite@notmuchmail.org", -- 2.20.1