From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id qJJIBK0ju16NegAA0tVLHw (envelope-from ) for ; Tue, 12 May 2020 22:31:09 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id EPMSIbsju16RcwAAbx9fmQ (envelope-from ) for ; Tue, 12 May 2020 22:31:23 +0000 Received: from arlo.cworth.org (unknown [50.126.95.6]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 402E0940C73 for ; Tue, 12 May 2020 22:31:17 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 9DEEF6DE14C5; Tue, 12 May 2020 15:30:29 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org 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 ZKbUEZx2iqzP; Tue, 12 May 2020 15:30:29 -0700 (PDT) Received: from arlo.cworth.org (localhost [IPv6:::1]) by arlo.cworth.org (Postfix) with ESMTP id B2CA96DE13F0; Tue, 12 May 2020 15:30:07 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 63F856DE13D2 for ; Tue, 12 May 2020 15:30:02 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org 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 y8wMpYklnjmY for ; Tue, 12 May 2020 15:30:01 -0700 (PDT) Received: from che.mayfirst.org (unknown [162.247.75.117]) by arlo.cworth.org (Postfix) with ESMTPS id 311526DE13E9 for ; Tue, 12 May 2020 15:29:57 -0700 (PDT) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019; t=1589322596; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=/mALCRg5cGO+wNV8hZxpolqgH6lTrKloIqYKcfdDgvU=; b=iO4WKhq5S0BiJY6q19/DM1+yoiCJlZxux2/0Z1kKDbaidgw2RsIrQP606BWObyh6xRdAR XGIbSWM0xNt24Q1DQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019rsa; t=1589322595; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=/mALCRg5cGO+wNV8hZxpolqgH6lTrKloIqYKcfdDgvU=; b=E+RrsRz9UUaNETFJrxYxg6FaJOkSuXDi+Qi70whZPnIj24qj1LXxHeiJdMStJlp4Y/1U3 xLhwm8dfjKRfAngWvJS1HfbdkqIB1pYDJrfOPkluh7RwgrRzCvEljujNyHHjtVZvaV7HdiK 8QLErtlpbfz5WnWjmVY6JSZXoXbtclu/vNnMZKbjRK6TGKXIa2MdwA+1lYC9fcPxecEixed g0rtK89ZTORCSbS8knlp+VtbVxsR8cf0bFv7NZ9Tc7qZOY04XuV91RM/NnWvu9JGFeGVu/5 NQVMOFp1MuIliCrLiYxmee2kwd79BvYkoZVjk3eta1HeRGgHRrSCYqOQ6mlQ== Received: from fifthhorseman.net (unknown [IPv6:2001:470:1f07:60d:f2de:f1ff:fec3:d109]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by che.mayfirst.org (Postfix) with ESMTPSA id E5DE5F9AC for ; Tue, 12 May 2020 18:29:55 -0400 (EDT) Received: by fifthhorseman.net (Postfix, from userid 1000) id D2F60201C5; Tue, 12 May 2020 18:29:51 -0400 (EDT) From: Daniel Kahn Gillmor To: Notmuch Mail Subject: [PATCH v2 1/9] lib: index PKCS7 SignedData parts Date: Tue, 12 May 2020 18:29:31 -0400 Message-Id: <20200512222939.372093-2-dkg@fifthhorseman.net> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200512222939.372093-1-dkg@fifthhorseman.net> References: <20200512222939.372093-1-dkg@fifthhorseman.net> MIME-Version: 1.0 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: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: notmuch-bounces@notmuchmail.org Sender: "notmuch" X-Scanner: scn0 X-Spam-Score: 4.59 Authentication-Results: aspmx1.migadu.com; dkim=fail (body hash did not verify) header.d=fifthhorseman.net header.s=2019 header.b=iO4WKhq5; dkim=fail (body hash did not verify) header.d=fifthhorseman.net header.s=2019rsa header.b=E+RrsRz9; dmarc=fail reason="SPF not aligned (relaxed)" header.from=fifthhorseman.net (policy=none); spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 50.126.95.6 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Scan-Result: default: False [4.59 / 13.00]; RCVD_VIA_SMTP_AUTH(0.00)[]; GENERIC_REPUTATION(0.00)[-0.44776842672803]; RDNS_NONE(1.00)[]; DWL_DNSWL_BLOCKED(0.00)[50.126.95.6:from]; R_DKIM_REJECT(1.00)[fifthhorseman.net:s=2019,fifthhorseman.net:s=2019rsa]; R_SPF_ALLOW(-0.20)[+a]; IP_REPUTATION_HAM(0.00)[asn: 27017(-0.18), country: US(-0.00), ip: 50.126.95.6(-0.45)]; FORGED_SENDER_MAILLIST(0.00)[]; TO_DN_ALL(0.00)[]; DKIM_TRACE(0.00)[fifthhorseman.net:-]; MX_GOOD(-0.50)[cached: notmuchmail.org]; MAILLIST(-0.20)[mailman]; MIME_TRACE(0.00)[0:+]; RCVD_TLS_LAST(0.00)[]; ASN(0.00)[asn:27017, ipnet:50.126.64.0/18, country:US]; FROM_NEQ_ENVFROM(0.00)[dkg@fifthhorseman.net,notmuch-bounces@notmuchmail.org]; RDNS_DNSFAIL(0.00)[]; ARC_NA(0.00)[]; URIBL_BLOCKED(0.00)[notmuchmail.org:email,fifthhorseman.net:email]; FROM_HAS_DN(0.00)[]; SPF_REPUTATION_HAM(0.00)[-0.4128827033031]; MIME_GOOD(-0.10)[text/plain]; PREVIOUSLY_DELIVERED(0.00)[notmuch@notmuchmail.org]; HAS_LIST_UNSUB(-0.01)[]; RCPT_COUNT_ONE(0.00)[1]; DNSWL_BLOCKED(0.00)[50.126.95.6:from]; MID_CONTAINS_FROM(1.00)[]; HFILTER_HOSTNAME_UNKNOWN(2.50)[]; RCVD_COUNT_SEVEN(0.00)[8]; DMARC_POLICY_SOFTFAIL(0.10)[fifthhorseman.net : SPF not aligned (relaxed),none] X-TUID: 90mlyI13FtE1 When we are indexing, we should treat SignedData parts the same way that we treat a multipart object, indexing the wrapped part as a distinct MIME object. Unfortunately, this means doing some sort of cryptographic verification whose results we throw away, because GMime doesn't offer us any way to unwrap without doing signature verification. I've opened https://github.com/jstedfast/gmime/issues/67 to request the capability from GMime but for now, we'll just accept the additional performance hit. As we do this indexing, we also apply the "signed" tag, by analogy with how we handle multipart/signed messages. These days, that kind of change should probably be done with a property instead, but that's a different set of changes. This one is just for consistency. Note that we are currently *only* handling signedData parts, which are basically clearsigned messages. PKCS#7 parts can also be envelopedData and authEnvelopedData (which are effectively encryption layers), and compressedData (which afaict isn't implemented anywhere, i've never encountered it). We're laying the groundwork for indexing these other S/MIME types here, but we're only dealing with signedData for now. Signed-off-by: Daniel Kahn Gillmor --- lib/index.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++ test/T355-smime.sh | 2 -- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 158ba5cf..bbf13dc5 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -372,6 +372,12 @@ _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *ind GMimeMultipartEncrypted *part, _notmuch_message_crypto_t *msg_crypto); +static void +_index_pkcs7_part (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, + GMimeObject *part, + _notmuch_message_crypto_t *msg_crypto); + /* Callback to generate terms for each mime part of a message. */ static void _index_mime_part (notmuch_message_t *message, @@ -466,6 +472,11 @@ _index_mime_part (notmuch_message_t *message, goto DONE; } + if (GMIME_IS_APPLICATION_PKCS7_MIME (part)) { + _index_pkcs7_part (message, indexopts, part, msg_crypto); + goto DONE; + } + if (! (GMIME_IS_PART (part))) { _notmuch_database_log (notmuch_message_get_database (message), "Warning: Not indexing unknown mime part: %s.\n", @@ -608,6 +619,52 @@ _index_encrypted_mime_part (notmuch_message_t *message, } +static void +_index_pkcs7_part (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, + GMimeObject *part, + _notmuch_message_crypto_t *msg_crypto) +{ + GMimeApplicationPkcs7Mime *pkcs7; + GMimeSecureMimeType p7type; + GMimeObject *mimeobj = NULL; + GMimeSignatureList *sigs = NULL; + GError *err = NULL; + notmuch_database_t *notmuch = NULL; + + pkcs7 = GMIME_APPLICATION_PKCS7_MIME (part); + p7type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7); + notmuch = notmuch_message_get_database (message); + _index_content_type (message, part); + + if (p7type == GMIME_SECURE_MIME_TYPE_SIGNED_DATA) { + sigs = g_mime_application_pkcs7_mime_verify (pkcs7, GMIME_VERIFY_NONE, &mimeobj, &err); + if (sigs == NULL) { + _notmuch_database_log (notmuch, "Failed to verify PKCS#7 SignedData during indexing. (%d:%d) [%s]\n", + err->domain, err->code, err->message); + g_error_free (err); + goto DONE; + } + _notmuch_message_add_term (message, "tag", "signed"); + GMimeObject *toindex = mimeobj; + if (_notmuch_message_crypto_potential_payload (msg_crypto, mimeobj, part, 0) && + msg_crypto->decryption_status == NOTMUCH_MESSAGE_DECRYPTED_FULL) { + toindex = _notmuch_repair_crypto_payload_skip_legacy_display (mimeobj); + if (toindex != mimeobj) + notmuch_message_add_property (message, "index.repaired", "skip-protected-headers-legacy-display"); + } + _index_mime_part (message, indexopts, toindex, msg_crypto); + } else { + _notmuch_database_log (notmuch, "Cannot currently handle PKCS#7 smime-type '%s'\n", + g_mime_object_get_content_type_parameter (part, "smime-type")); + } + DONE: + if (mimeobj) + g_object_unref (mimeobj); + if (sigs) + g_object_unref (sigs); +} + static notmuch_status_t _notmuch_message_index_user_headers (notmuch_message_t *message, GMimeMessage *mime_message) { diff --git a/test/T355-smime.sh b/test/T355-smime.sh index f8e8e396..a7eecedf 100755 --- a/test/T355-smime.sh +++ b/test/T355-smime.sh @@ -132,13 +132,11 @@ expected='' test_expect_equal "$expected" "$output" test_begin_subtest "know the MIME type of the embedded part in PKCS#7 SignedData" -test_subtest_known_broken output=$(notmuch search --output=messages 'mimetype:text/plain') expected=id:smime-onepart-signed@protected-headers.example test_expect_equal "$expected" "$output" test_begin_subtest "PKCS#7 SignedData message is tagged 'signed'" -test_subtest_known_broken output=$(notmuch dump id:smime-onepart-signed@protected-headers.example) expected='#notmuch-dump batch-tag:3 config,properties,tags +inbox +signed +unread -- id:smime-onepart-signed@protected-headers.example' -- 2.26.2