]> git.cworth.org Git - notmuch/commitdiff
cli/show: produce "email" element in sigstatus
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>
Thu, 27 May 2021 01:44:58 +0000 (21:44 -0400)
committerDavid Bremner <david@tethera.net>
Sat, 26 Jun 2021 16:07:47 +0000 (13:07 -0300)
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 <dkg@fifthhorseman.net>
devel/schemata
notmuch-show.c
test/T350-crypto.sh
test/T355-smime.sh
test/T356-protected-headers.sh
test/test-lib.sh
util/gmime-extra.c
util/gmime-extra.h

index 28332c6bd1d9b0de96db2be77b695183e6a896df..ae84a5285e6e23f978b15840b526232b40edae7c 100644 (file)
@@ -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
index bdb87321f1f02d74a400cffe3c6a4cc02c82b40a..232557d5016f3ee3f555569de8107eb0da9a615d 100644 (file)
@@ -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);
index c1c1fcccc81ac2467fa409cf0ee71ce605867297..8dbf89352a60e4af75efd19d6c3c0eb9bfe246c3 100755 (executable)
@@ -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 <test_suite@notmuchmail.org>",
  "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,
index b7269686ce70e82cb07f2f53349c788c2f1bc340..31fa4b4e9e5bb3bdf56c6bc62bfdf6049375dfb3 100755 (executable)
@@ -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": "<test_suite@notmuchmail.org>", "expires": 424242424, "created": 946728000}]}},
  "headers": {"Subject": "test signed message 001",
  "From": "Notmuch Test Suite <test_suite@notmuchmail.org>",
  "To": "test_suite@notmuchmail.org",
@@ -55,6 +55,7 @@ expected='[[[{"id": "XXXXX",
  "sigstatus": [{"fingerprint": "'$FINGERPRINT'",
  "status": "good",
  "userid": "CN=Notmuch Test Suite",
+ "email": "<test_suite@notmuchmail.org>",
  "expires": 424242424,
  "created": 946728000}],
  "content-type": "multipart/signed",
index 074a23451cf7cf07aaadd1503e7dd90709e30d52..f0aba14eaa1d7d90296367ba1ce83981334e9175 100755 (executable)
@@ -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"'
 
index f83f7c6aab25d8c040b25378074616a5f1167f19..67ad88539e393a1c5c4858a55631d83bab7631c5 100644 (file)
@@ -131,6 +131,7 @@ add_gnupg_home () {
     # Change this if we ship a new test key
     FINGERPRINT="5AEAB11F5E33DCE875DDB75B6D92612D94E46381"
     SELF_USERID="Notmuch Test Suite <test_suite@notmuchmail.org> (INSECURE!)"
+    SELF_EMAIL="test_suite@notmuchmail.org"
     printf '%s:6:\n' "$FINGERPRINT" | gpg --quiet --batch --no-tty --import-ownertrust
 }
 
index 81a5b1743b7bee88ff05277021a6195a20c85bff..192cb07812b38cb29649e68c494a7347bccffd73 100644 (file)
@@ -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)
 {
index 094309ec26041e4af3e6356087166a1873e594a6..889e91f3e8c0e000ec9ab3660851a755ce9d2507 100644 (file)
@@ -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
 }