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 1DA2B6DE0191 for ; Wed, 29 Nov 2017 20:20:45 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.016 X-Spam-Level: X-Spam-Status: No, score=-0.016 tagged_above=-999 required=5 tests=[AWL=-0.016] 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 IFtR7-PYqOR5 for ; Wed, 29 Nov 2017 20:20:43 -0800 (PST) Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118]) by arlo.cworth.org (Postfix) with ESMTPS id B1C076DE00C4 for ; Wed, 29 Nov 2017 20:20:43 -0800 (PST) Received: from fifthhorseman.net (ool-6c3a0662.static.optonline.net [108.58.6.98]) by che.mayfirst.org (Postfix) with ESMTPSA id AD090F99A for ; Wed, 29 Nov 2017 23:20:40 -0500 (EST) Received: by fifthhorseman.net (Postfix, from userid 1000) id 60D892079B; Wed, 29 Nov 2017 23:20:35 -0500 (EST) From: Daniel Kahn Gillmor To: Notmuch Mail Subject: [PATCH] crypto: signature verification reports valid User IDs Date: Wed, 29 Nov 2017 23:20:35 -0500 Message-Id: <20171130042035.9502-1-dkg@fifthhorseman.net> X-Mailer: git-send-email 2.15.0 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.23 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: Thu, 30 Nov 2017 04:20:45 -0000 When i'm trying to understand a message signature, i care that i know who it came from (the "validity" of the identity associated with the key), *not* whether i'm willing to accept the keyholder's other identity assertions (the "trust" associated with the certificate). We've been reporting User ID information based on the "trust" associated with the certificate, because GMime didn't clearly expose the validity of the User IDs. This change relies on fixes made in GMime 3.0.3 and later which include https://github.com/jstedfast/gmime/pull/18. --- configure | 3 ++- notmuch-show.c | 36 +++++++++++++++++++++++++++++------- test/T355-smime.sh | 8 +++++++- util/gmime-extra.h | 11 ----------- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/configure b/configure index d3e30b53..cfbf827c 100755 --- a/configure +++ b/configure @@ -478,9 +478,10 @@ fi # we need to have a version >= 2.6.5 to avoid a crypto bug. We need # 2.6.7 for permissive "From " header handling. GMIME_MINVER=2.6.7 +GMIME3_MINVER=3.0.3 printf "Checking for GMime development files... " -if pkg-config --exists "gmime-3.0"; then +if pkg-config --exists "gmime-3.0 > $GMIME3_MINVER"; then printf "Yes (3.0).\n" have_gmime=1 gmime_cflags=$(pkg-config --cflags gmime-3.0) diff --git a/notmuch-show.c b/notmuch-show.c index 7afd3947..4b89be0a 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -401,6 +401,32 @@ format_signature_errors (sprinter_t *sp, GMimeSignature *signature) } #endif + +static const char* +_get_certificate_valid_userid (GMimeCertificate *cert) +{ + /* output user id only if validity is FULL or ULTIMATE. */ +#if (GMIME_MAJOR_VERSION < 3) + /* note that gmime 2.6 is using the term "trust" here, which + * is WRONG. It's actually user id "validity". */ + const char *name = g_mime_certificate_get_name (cert); + if (name == NULL) + return name; + GMimeCertificateTrust trust = g_mime_certificate_get_trust (cert); + if (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE) + return name; + return NULL; +#else + const char *uid = g_mime_certificate_get_user_id (cert); + if (uid == NULL) + return uid; + GMimeValidity validity = g_mime_certificate_get_id_validity (cert); + if (validity == GMIME_VALIDITY_FULL || validity == GMIME_VALIDITY_ULTIMATE) + return uid; + return NULL; +#endif +} + /* Signature status sprinter (GMime 2.6) */ static void format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node) @@ -446,15 +472,11 @@ format_part_sigstatus_sprinter (sprinter_t *sp, mime_node_t *node) sp->map_key (sp, "expires"); sp->integer (sp, expires); } - /* output user id only if validity is FULL or ULTIMATE. */ - /* note that gmime is using the term "trust" here, which - * is WRONG. It's actually user id "validity". */ if (certificate) { - const char *name = g_mime_certificate_get_uid (certificate); - GMimeCertificateTrust trust = g_mime_certificate_get_trust (certificate); - if (name && (trust == GMIME_CERTIFICATE_TRUST_FULLY || trust == GMIME_CERTIFICATE_TRUST_ULTIMATE)) { + const char *uid = _get_certificate_valid_userid (certificate); + if (uid) { sp->map_key (sp, "userid"); - sp->string (sp, name); + sp->string (sp, uid); } } } else if (certificate) { diff --git a/test/T355-smime.sh b/test/T355-smime.sh index 1523f17b..be45e3b1 100755 --- a/test/T355-smime.sh +++ b/test/T355-smime.sh @@ -48,6 +48,12 @@ EOF test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "signature verification (notmuch CLI)" +if [ "${NOTMUCH_GMIME_MAJOR}" -lt 3 ]; then + # gmime 2 can't report User IDs properly for S/MIME + USERID='' +else + USERID='"userid": "CN=Notmuch Test Suite",' +fi output=$(notmuch show --format=json --verify subject:"test signed message 001" \ | notmuch_json_show_sanitize \ | sed -e 's|"created": [-1234567890]*|"created": 946728000|' \ @@ -65,7 +71,7 @@ expected='[[[{"id": "XXXXX", "Date": "Sat, 01 Jan 2000 12:00:00 +0000"}, "body": [{"id": 1, "sigstatus": [{"fingerprint": "'$FINGERPRINT'", - "status": "good", + "status": "good",'$USERID' "expires": 424242424, "created": 946728000}], "content-type": "multipart/signed", diff --git a/util/gmime-extra.h b/util/gmime-extra.h index 40bf1454..ec4ca186 100644 --- a/util/gmime-extra.h +++ b/util/gmime-extra.h @@ -16,11 +16,9 @@ GMimeStream *g_mime_stream_stdout_new(void); #define g_mime_2_6_unref(obj) g_object_unref (obj) #define g_mime_3_unused(arg) arg #define g_mime_certificate_get_fpr16(cert) g_mime_certificate_get_key_id (cert) -#define g_mime_certificate_get_uid(cert) g_mime_certificate_get_name (cert); #else /* GMime >= 3.0 */ #define GMIME_ENABLE_RFC_2047_WORKAROUNDS 0xdeadbeef -#define g_mime_certificate_get_uid(cert) g_mime_certificate_get_key_id (cert); #define g_mime_content_type_to_string(c) g_mime_content_type_get_mime_type (c) #define g_mime_filter_crlf_new(encode,dots) g_mime_filter_dos2unix_new (FALSE) #define g_mime_gpg_context_new(func,path) g_mime_gpg_context_new () @@ -45,15 +43,6 @@ typedef GMimeAddressType GMimeRecipientType; typedef GMimeSignatureStatus GMimeSignatureError; -typedef GMimeTrust GMimeCertificateTrust; - -#define GMIME_CERTIFICATE_TRUST_UNKNOWN GMIME_TRUST_UNKNOWN -#define GMIME_CERTIFICATE_TRUST_UNDEFINED GMIME_TRUST_UNDEFINED -#define GMIME_CERTIFICATE_TRUST_NEVER GMIME_TRUST_NEVER -#define GMIME_CERTIFICATE_TRUST_MARGINAL GMIME_TRUST_MARGINAL -#define GMIME_CERTIFICATE_TRUST_FULLY GMIME_TRUST_FULL -#define GMIME_CERTIFICATE_TRUST_ULTIMATE GMIME_TRUST_ULTIMATE - #define g_mime_2_6_unref(obj) /*ignore*/ #define g_mime_3_unused(arg) unused(arg) #endif -- 2.15.0