Inline PGP encrypted messages are clearly worse than PGP/MIME structured encrypted messages. There are no standards for how they are formed, and they don't offer any structured metadata about how to interpret the bytestream produced by decrypting them. However, some other MUAs and end-user workflows may make creation of inline PGP encrypted messages the only available option for message encryption, and when Notmuch encounters such a message, it should make a reasonable best-effort to render the cleartext to the user. Due to ambiguities in interpretation of signatures on inline messages (e.g. which parts of the message were actually signed? what character encoding should the bytestream be interpreted as), we continue to ignore inline-signed messages entirely, and we do not look at the validity of any signatures that might be found when decrypting inline PGP encrypted messages. We make use here of GMime's optimization function for detecting the presence of inline PGP encrypted content, which is only found in GMime 3.0 or later. This change prepares the internal codebase for decrypting inline encrypted messages, but does not yet actually use the capability. --- lib/index.cc | 6 +++--- mime-node.c | 24 ++++++++++++++---------- util/crypto.c | 35 +++++++++++++++++++++++++++-------- util/crypto.h | 2 +- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 22ca9ec1..f144b9fb 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -367,7 +367,7 @@ _index_content_type (notmuch_message_t *message, GMimeObject *part) static void _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, GMimeContentType *content_type, - GMimeMultipartEncrypted *part); + GMimeObject *part); /* Callback to generate terms for each mime part of a message. */ static void @@ -421,7 +421,7 @@ _index_mime_part (notmuch_message_t *message, if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) { _index_encrypted_mime_part(message, indexopts, content_type, - GMIME_MULTIPART_ENCRYPTED (part)); + part); } else { if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) { _notmuch_database_log (notmuch_message_get_database (message), @@ -518,7 +518,7 @@ static void _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, g_mime_3_unused(GMimeContentType *content_type), - GMimeMultipartEncrypted *encrypted_data) + GMimeObject *encrypted_data) { notmuch_status_t status; GError *err = NULL; diff --git a/mime-node.c b/mime-node.c index 75b79f98..973133d9 100644 --- a/mime-node.c +++ b/mime-node.c @@ -196,10 +196,10 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, { GError *err = NULL; GMimeDecryptResult *decrypt_result = NULL; - GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part); notmuch_message_t *message = NULL; - if (! node->decrypted_child) { + if (GMIME_IS_PART (part) || /* must be inline */ + (GMIME_IS_MULTIPART_ENCRYPTED (part) && ! node->decrypted_child)) { for (mime_node_t *parent = node; parent; parent = parent->parent) if (parent->envelope_file) { message = parent->envelope_file; @@ -209,7 +209,7 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, node->decrypted_child = _notmuch_crypto_decrypt (&node->decrypt_attempted, node->ctx->crypto->decrypt, message, - cryptoctx, encrypteddata, &decrypt_result, &err); + cryptoctx, part, &decrypt_result, &err); } if (! node->decrypted_child) { fprintf (stderr, "Failed to decrypt part: %s\n", @@ -217,15 +217,19 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, goto DONE; } - node->decrypt_success = true; - node->verify_attempted = true; if (decrypt_result) { - /* This may be NULL if the part is not signed. */ - node->sig_list = g_mime_decrypt_result_get_signatures (decrypt_result); - if (node->sig_list) { - g_object_ref (node->sig_list); - set_signature_list_destructor (node); + node->decrypt_success = true; + if (GMIME_IS_MULTIPART_ENCRYPTED (part)) { + /* Only check signatures on PGP/MIME messages, not inline + messages. To understand why, see + https://dkg.fifthhorseman.net/notes/inline-pgp-harmful/ */ + node->verify_attempted = true; + node->sig_list = g_mime_decrypt_result_get_signatures (decrypt_result); + if (node->sig_list) { + g_object_ref (node->sig_list); + set_signature_list_destructor (node); + } } #if HAVE_GMIME_SESSION_KEYS diff --git a/util/crypto.c b/util/crypto.c index 9d3b6dad..7965ab8e 100644 --- a/util/crypto.c +++ b/util/crypto.c @@ -144,7 +144,7 @@ _notmuch_crypto_decrypt (bool *attempted, notmuch_decryption_policy_t decrypt, notmuch_message_t *message, g_mime_3_unused(GMimeCryptoContext* crypto_ctx), - GMimeMultipartEncrypted *part, + GMimeObject *part, GMimeDecryptResult **decrypt_result, GError **err) { @@ -166,15 +166,26 @@ _notmuch_crypto_decrypt (bool *attempted, if (attempted) *attempted = true; #if (GMIME_MAJOR_VERSION < 3) - ret = g_mime_multipart_encrypted_decrypt_session (part, + ret = g_mime_multipart_encrypted_decrypt_session (GMIME_MULTIPART_ENCRYPTED (part), crypto_ctx, notmuch_message_properties_value (list), decrypt_result, err); #else - ret = g_mime_multipart_encrypted_decrypt (part, - GMIME_DECRYPT_NONE, - notmuch_message_properties_value (list), - decrypt_result, err); + if (GMIME_IS_MULTIPART_ENCRYPTED (part)) { + ret = g_mime_multipart_encrypted_decrypt (GMIME_MULTIPART_ENCRYPTED (part), + GMIME_DECRYPT_NONE, + notmuch_message_properties_value (list), + decrypt_result, err); + } else if (GMIME_IS_PART (part) && g_mime_part_get_openpgp_data (GMIME_PART (part)) == GMIME_OPENPGP_DATA_ENCRYPTED) { + *decrypt_result = g_mime_part_openpgp_decrypt (GMIME_PART (part), + GMIME_DECRYPT_NONE, + notmuch_message_properties_value (list), + err); + if (decrypt_result) { + ret = part; + g_object_ref (ret); + } + } #endif if (ret) break; @@ -214,8 +225,16 @@ _notmuch_crypto_decrypt (bool *attempted, GMimeDecryptFlags flags = GMIME_DECRYPT_NONE; if (decrypt == NOTMUCH_DECRYPT_TRUE && decrypt_result) flags |= GMIME_DECRYPT_EXPORT_SESSION_KEY; - ret = g_mime_multipart_encrypted_decrypt(part, flags, NULL, - decrypt_result, err); + if (GMIME_IS_MULTIPART_ENCRYPTED (part)) { + ret = g_mime_multipart_encrypted_decrypt(GMIME_MULTIPART_ENCRYPTED (part), flags, NULL, + decrypt_result, err); + } else if (GMIME_IS_PART (part) && g_mime_part_get_openpgp_data (GMIME_PART (part)) == GMIME_OPENPGP_DATA_ENCRYPTED) { + *decrypt_result = g_mime_part_openpgp_decrypt (GMIME_PART (part), flags, NULL, err); + if (decrypt_result) { + ret = part; + g_object_ref (ret); + } + } #endif return ret; } diff --git a/util/crypto.h b/util/crypto.h index c384601c..d9e4a1c7 100644 --- a/util/crypto.h +++ b/util/crypto.h @@ -20,7 +20,7 @@ _notmuch_crypto_decrypt (bool *attempted, notmuch_decryption_policy_t decrypt, notmuch_message_t *message, GMimeCryptoContext* crypto_ctx, - GMimeMultipartEncrypted *part, + GMimeObject *part, GMimeDecryptResult **decrypt_result, GError **err); -- 2.15.1 _______________________________________________ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch