From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms0.migadu.com with LMTPS id EFV/L6/5rmCDUwAAgWs5BA (envelope-from ) for ; Thu, 27 May 2021 03:45:19 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0 with LMTPS id yFMxK6/5rmCQfQAA1q6Kng (envelope-from ) for ; Thu, 27 May 2021 01:45:19 +0000 Received: from mail.notmuchmail.org (nmbug.tethera.net [IPv6:2607:5300:201:3100::1657]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 0296714A58 for ; Thu, 27 May 2021 03:45:18 +0200 (CEST) Received: from nmbug.tethera.net (localhost [127.0.0.1]) by mail.notmuchmail.org (Postfix) with ESMTP id 4273027DEE; Wed, 26 May 2021 21:45:09 -0400 (EDT) Received: from che.mayfirst.org (che.mayfirst.org [IPv6:2001:470:1:116::7]) by mail.notmuchmail.org (Postfix) with ESMTPS id 11B15271D6 for ; Wed, 26 May 2021 21:45:06 -0400 (EDT) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019; t=1622079903; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=ruje6g1MfCjB0vTxNSSW4Mic1M5ZzyPP/tkg4sNdnC8=; b=bxMFT1h5cn0Ea8U4kbP6TQsTAf24FrRUEPEcXhj3i1DFJvQBVDvTV2r8/BubqEn6QbOS3 hb9ecBfNibzE0RjAw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=fifthhorseman.net; i=@fifthhorseman.net; q=dns/txt; s=2019rsa; t=1622079903; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : from; bh=ruje6g1MfCjB0vTxNSSW4Mic1M5ZzyPP/tkg4sNdnC8=; b=ZQRxpBb7vJt0x0/y5PQD26DoWu13Lnoefs/Xbblsb+eQgV4IxBZ7COakM4aA2pUv3t90p znRMKZ6jUOe496RY0bxk4UEBWJF9IEPe4faTNqffvxh+mnjT41BRVmDrbbe0NOORQkrpS8Q 2Nk/E/u8A5Nf4vgLjSm0AdPZf45ow9/X2fnv3TDsPs1I+zhA1bIYJ/esZUkQmrDw0z7RoDX K2IVwx6moUuoByfQNL/DKa/fiYgWvxwuB1h/5vfaoN3Pcpy9WXkKOiGln0nQnylMu1pzEon r9xkMdnd3jNCPGes0YdmKzRMxSOzlqZ68fR2lM2fqjmethpwJKNw0J72mfMA== Received: from fifthhorseman.net (lair.fifthhorseman.net [108.58.6.98]) (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 7A413F9A6 for ; Wed, 26 May 2021 21:45:02 -0400 (EDT) Received: by fifthhorseman.net (Postfix, from userid 1000) id 53E032054B; Wed, 26 May 2021 21:44:59 -0400 (EDT) From: Daniel Kahn Gillmor To: Notmuch Mail Subject: [PATCH 1/2] cli/show: produce "email" element in sigstatus Date: Wed, 26 May 2021 21:44:58 -0400 Message-Id: <20210527014459.3082888-1-dkg@fifthhorseman.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <878s41ax6t.fsf@fifthhorseman.net> References: <878s41ax6t.fsf@fifthhorseman.net> MIME-Version: 1.0 Message-ID-Hash: YAXBP4U3JEYRETBPIUQPVMWBJANZ7IL7 X-Message-ID-Hash: YAXBP4U3JEYRETBPIUQPVMWBJANZ7IL7 X-MailFrom: dkg@fifthhorseman.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-notmuch.notmuchmail.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.1 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1622079919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=NcUc295Xi/rV345f4uWDxTM4q7SnfL1Nmc16ytHCbdg=; b=LQxPPCD6+OSdXXd5wzddAODFXvVXOcadnjZr8JqPeTPNOan6urVp+J/OmMkOgYR1KY6K4/ NiZ08x0oitcJg4ZwGlMAlKZBp6OZOonLYpveJ44+gmJ7sDibT0ZS0Pz+aMhrnQQcr4p6e1 N/2ru2WLhGp7/LCwkyCiHiue6r+QabFS4RMMJCfOFDSZoXlhsFr5LNp3uA650RGsZp98kL +lBcK7lxoaTJy+xDKjfiaogd9vv1EAKLrTo/8PgN5/Soa3EQxWn5sbHAd7wjI7vOqbJvoa DJPW4hKwPPr29Vz+XWYis360OEKoudXHkx5owMvRVdOe/hhwE1AogjxGLM6bSA== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1622079919; a=rsa-sha256; cv=none; b=CUjhws7BBECMii1cNCjrmt9a1LIKHnvCtUEcYenW2gdewmx4gOjogPNF2KAMEi0rncJOEp JAlWbZ8wtcrEJELZQPJGqG4Ctt3HAM9LoPElbFeefsz40N5S6nEmDObRR+wwGhtyT3b1vs L1JFgafBMGdQCKCgJjSrkGWSC2TSN5H0eKUKcRgLPFwx7r3V0rrd91YPGoQAkuZZu9jCP7 rTx/0syoVgT+9TYnZ7D0hGh7D5XEQg693d9p6D4e1DtT/j1MkJSoG9P+7X6fTEuGCvlZm8 BcB/qRHLDPATtbH0PnkGx/kSJlr2m7i9tgemWQtBP5s4rUXw6T0dBIdfsGJdXg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=fifthhorseman.net header.s=2019 header.b=bxMFT1h5; dkim=fail ("body hash did not verify") header.d=fifthhorseman.net header.s=2019rsa header.b=ZQRxpBb7; 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 2607:5300:201:3100::1657 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Spam-Score: 1.53 Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=fifthhorseman.net header.s=2019 header.b=bxMFT1h5; dkim=fail ("body hash did not verify") header.d=fifthhorseman.net header.s=2019rsa header.b=ZQRxpBb7; 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 2607:5300:201:3100::1657 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Queue-Id: 0296714A58 X-Spam-Score: 1.53 X-Migadu-Scanner: scn0.migadu.com X-TUID: 7FPNlskLBbjI When the certificate that signs a message is known to be valid, GMime is capable of reporting on the e-mail address embedded in the certificate. We pass this information along to the caller of "notmuch show", as often only the e-mail address of the certificate has actually been checked/verified. Furthermore, signature verification should probably at some point compare the e-mail address of the caller against the sender address of the message itself. Having to parse what gmime thinks is a "userid" to extract an e-mail address seems clunky and unnecessary if gmime already thinks it knows what the e-mail address is. See id:878s41ax6t.fsf@fifthhorseman.net for more motivation and discussion. Signed-off-by: Daniel Kahn Gillmor --- devel/schemata | 1 + notmuch-show.c | 5 +++++ test/T350-crypto.sh | 6 ++++-- test/T355-smime.sh | 3 ++- test/T356-protected-headers.sh | 8 ++++---- test/test-lib.sh | 1 + util/gmime-extra.c | 15 +++++++++++++++ util/gmime-extra.h | 4 ++++ 8 files changed, 36 insertions(+), 7 deletions(-) diff --git a/devel/schemata b/devel/schemata index 28332c6b..ae84a528 100644 --- a/devel/schemata +++ b/devel/schemata @@ -158,6 +158,7 @@ signature = { created?: unix_time, expires?: unix_time, userid?: string + email?: string # if status is not "good": keyid?: string errors?: sig_errors diff --git a/notmuch-show.c b/notmuch-show.c index bdb87321..232557d5 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -475,6 +475,11 @@ format_part_sigstatus_sprinter (sprinter_t *sp, GMimeSignatureList *siglist) sp->map_key (sp, "userid"); sp->string (sp, uid); } + const char *email = g_mime_certificate_get_valid_email (certificate); + if (email) { + sp->map_key (sp, "email"); + sp->string (sp, email); + } } } else if (certificate) { const char *key_id = g_mime_certificate_get_fpr16 (certificate); diff --git a/test/T350-crypto.sh b/test/T350-crypto.sh index 4508c984..a25c4b0b 100755 --- a/test/T350-crypto.sh +++ b/test/T350-crypto.sh @@ -35,7 +35,7 @@ expected='[[[{"id": "XXXXX", "timestamp": 946728000, "date_relative": "2000-01-01", "tags": ["inbox","signed"], - "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'"}]}}, + "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "email": "'"$SELF_EMAIL"'", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'"}]}}, "headers": {"Subject": "test signed message 001", "From": "Notmuch Test Suite ", "To": "test_suite@notmuchmail.org", @@ -44,6 +44,7 @@ expected='[[[{"id": "XXXXX", "sigstatus": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "created": 946728000, + "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'"}], "content-type": "multipart/signed", "content": [{"id": 2, @@ -367,7 +368,7 @@ expected='[[[{"id": "XXXXX", "timestamp": 946728000, "date_relative": "2000-01-01", "tags": ["encrypted","inbox"], - "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'"}], + "crypto": {"signed": {"status": [{ "status": "good", "created": 946728000, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'"}], "encrypted": true }, "decrypted": {"status": "full"}}, "headers": {"Subject": "test encrypted message 002", @@ -379,6 +380,7 @@ expected='[[[{"id": "XXXXX", "sigstatus": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "created": 946728000, + "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'"}], "content-type": "multipart/encrypted", "content": [{"id": 2, diff --git a/test/T355-smime.sh b/test/T355-smime.sh index 69bdcfac..9c6e7340 100755 --- a/test/T355-smime.sh +++ b/test/T355-smime.sh @@ -46,7 +46,7 @@ expected='[[[{"id": "XXXXX", "timestamp": 946728000, "date_relative": "2000-01-01", "tags": ["inbox","signed"], - "crypto": {"signed": {"status": [{"fingerprint": "'$FINGERPRINT'", "status": "good","userid": "CN=Notmuch Test Suite","expires": 424242424, "created": 946728000}]}}, + "crypto": {"signed": {"status": [{"fingerprint": "'$FINGERPRINT'", "status": "good","userid": "CN=Notmuch Test Suite", "email": "", "expires": 424242424, "created": 946728000}]}}, "headers": {"Subject": "test signed message 001", "From": "Notmuch Test Suite ", "To": "test_suite@notmuchmail.org", @@ -55,6 +55,7 @@ expected='[[[{"id": "XXXXX", "sigstatus": [{"fingerprint": "'$FINGERPRINT'", "status": "good", "userid": "CN=Notmuch Test Suite", + "email": "", "expires": 424242424, "created": 946728000}], "content-type": "multipart/signed", diff --git a/test/T356-protected-headers.sh b/test/T356-protected-headers.sh index 074a2345..f0aba14e 100755 --- a/test/T356-protected-headers.sh +++ b/test/T356-protected-headers.sh @@ -69,12 +69,12 @@ test_json_nodes <<<"$output" \ test_begin_subtest "show cryptographic envelope on signed mail" output=$(notmuch show --verify --format=json id:simple-signed-mail@crypto.notmuchmail.org) test_json_nodes <<<"$output" \ - 'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525609971, "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "status": "good"}]}}' + 'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525609971, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}]}}' test_begin_subtest "verify signed protected header" output=$(notmuch show --verify --format=json id:signed-protected-header@crypto.notmuchmail.org) test_json_nodes <<<"$output" \ - 'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525350527, "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "status": "good"}], "headers": ["Subject"]}}' + 'crypto:[0][0][0]["crypto"]={"signed": {"status": [{"created": 1525350527, "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "status": "good"}], "headers": ["Subject"]}}' test_begin_subtest "protected subject does not leak by default in replies" output=$(notmuch reply --decrypt=true --format=json id:protected-header@crypto.notmuchmail.org) @@ -115,7 +115,7 @@ test_begin_subtest "verify protected header is both signed and encrypted" output=$(notmuch show --decrypt=true --format=json id:encrypted-signed@crypto.notmuchmail.org) test_json_nodes <<<"$output" \ 'crypto:[0][0][0]["crypto"]={ - "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "created": 1525812676}], + "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "email": "'"$SELF_EMAIL"'", "userid": "'"$SELF_USERID"'", "created": 1525812676}], "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full", "header-mask": {"Subject": "Subject Unavailable"}}}' \ 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"' @@ -123,7 +123,7 @@ test_begin_subtest "verify protected header is signed even when not masked" output=$(notmuch show --decrypt=true --format=json id:encrypted-signed-not-masked@crypto.notmuchmail.org) test_json_nodes <<<"$output" \ 'crypto:[0][0][0]["crypto"]={ - "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "created": 1525812676}], + "signed":{"status": [{"status": "good", "fingerprint": "'$FINGERPRINT'", "userid": "'"$SELF_USERID"'", "email": "'"$SELF_EMAIL"'", "created": 1525812676}], "encrypted": true, "headers": ["Subject"]},"decrypted": {"status": "full"}}' \ 'subject:[0][0][0]["headers"]["Subject"]="Rhinoceros dinner"' diff --git a/test/test-lib.sh b/test/test-lib.sh index 0bca76df..7c7c3354 100644 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -131,6 +131,7 @@ add_gnupg_home () { # Change this if we ship a new test key FINGERPRINT="5AEAB11F5E33DCE875DDB75B6D92612D94E46381" SELF_USERID="Notmuch Test Suite (INSECURE!)" + SELF_EMAIL="test_suite@notmuchmail.org" printf '%s:6:\n' "$FINGERPRINT" | gpg --quiet --batch --no-tty --import-ownertrust } diff --git a/util/gmime-extra.c b/util/gmime-extra.c index 81a5b174..192cb078 100644 --- a/util/gmime-extra.c +++ b/util/gmime-extra.c @@ -107,6 +107,21 @@ g_mime_certificate_get_valid_userid (GMimeCertificate *cert) return NULL; } +const char * +g_mime_certificate_get_valid_email (GMimeCertificate *cert) +{ + /* output e-mail address only if validity is FULL or ULTIMATE. */ + const char *email = g_mime_certificate_get_email(cert); + + if (email == NULL) + return email; + GMimeValidity validity = g_mime_certificate_get_id_validity (cert); + + if (validity == GMIME_VALIDITY_FULL || validity == GMIME_VALIDITY_ULTIMATE) + return email; + return NULL; +} + const char * g_mime_certificate_get_fpr16 (GMimeCertificate *cert) { diff --git a/util/gmime-extra.h b/util/gmime-extra.h index 094309ec..889e91f3 100644 --- a/util/gmime-extra.h +++ b/util/gmime-extra.h @@ -69,6 +69,10 @@ gint64 g_mime_utils_header_decode_date_unix (const char *date); * Return string for valid User ID (or NULL if no valid User ID exists) */ const char *g_mime_certificate_get_valid_userid (GMimeCertificate *cert); +/** + * Return string for valid e-mail address (or NULL if no valid e-mail address exists) + */ +const char *g_mime_certificate_get_valid_email (GMimeCertificate *cert); #ifdef __cplusplus } -- 2.30.2