mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-24 20:08:10 +01:00
util/crypto: _notmuch_message_crypto: tracks message-wide crypto state
E-mail encryption and signatures reported by notmuch are at the MIME part level. This makes sense in the dirty details, but for users we need to have a per-message conception of the cryptographic state of the e-mail. (see https://dkg.fifthhorseman.net/blog/e-mail-cryptography.html for more discussion of why this is important). The object created in this patch is a useful for tracking the cryptographic state of the underlying message as a whole, based on a depth-first search of the message's MIME structure. This object stores a signature list of the message, but we don't handle it yet. Further patches in this series will make use of the signature list.
This commit is contained in:
parent
9300defd64
commit
74919c226e
2 changed files with 158 additions and 0 deletions
|
@ -82,3 +82,96 @@ _notmuch_crypto_decrypt (bool *attempted,
|
||||||
decrypt_result, err);
|
decrypt_result, err);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_notmuch_message_crypto_destructor (_notmuch_message_crypto_t *msg_crypto)
|
||||||
|
{
|
||||||
|
if (!msg_crypto)
|
||||||
|
return 0;
|
||||||
|
if (msg_crypto->sig_list)
|
||||||
|
g_object_unref (msg_crypto->sig_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_notmuch_message_crypto_t *
|
||||||
|
_notmuch_message_crypto_new (void *ctx)
|
||||||
|
{
|
||||||
|
_notmuch_message_crypto_t *ret = talloc_zero (ctx, _notmuch_message_crypto_t);
|
||||||
|
talloc_set_destructor (ret, _notmuch_message_crypto_destructor);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_potential_sig_list (_notmuch_message_crypto_t *msg_crypto, GMimeSignatureList *sigs)
|
||||||
|
{
|
||||||
|
if (!msg_crypto)
|
||||||
|
return NOTMUCH_STATUS_NULL_POINTER;
|
||||||
|
|
||||||
|
/* Signatures that arrive after a payload part during DFS are not
|
||||||
|
* part of the cryptographic envelope: */
|
||||||
|
if (msg_crypto->payload_encountered)
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (msg_crypto->sig_list)
|
||||||
|
g_object_unref (msg_crypto->sig_list);
|
||||||
|
|
||||||
|
/* This signature list needs to persist as long as the _n_m_crypto
|
||||||
|
* object survives. Increasing its reference counter prevents
|
||||||
|
* garbage-collection until after _n_m_crypto_destroy is
|
||||||
|
* called. */
|
||||||
|
msg_crypto->sig_list = sigs;
|
||||||
|
if (sigs)
|
||||||
|
g_object_ref (sigs);
|
||||||
|
|
||||||
|
if (msg_crypto->decryption_status == NOTMUCH_MESSAGE_DECRYPTED_FULL)
|
||||||
|
msg_crypto->signature_encrypted = true;
|
||||||
|
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_potential_payload (_notmuch_message_crypto_t *msg_crypto, GMimeObject *payload, GMimeObject *parent, int childnum)
|
||||||
|
{
|
||||||
|
if (!msg_crypto || !payload)
|
||||||
|
return NOTMUCH_STATUS_NULL_POINTER;
|
||||||
|
|
||||||
|
/* only fire on the first payload part encountered */
|
||||||
|
if (msg_crypto->payload_encountered)
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* the first child of multipart/encrypted that matches the
|
||||||
|
* encryption protocol should be "control information" metadata,
|
||||||
|
* not payload. So we skip it. (see
|
||||||
|
* https://tools.ietf.org/html/rfc1847#page-8) */
|
||||||
|
if (parent && GMIME_IS_MULTIPART_ENCRYPTED (parent) && childnum == GMIME_MULTIPART_ENCRYPTED_VERSION) {
|
||||||
|
const char *enc_type = g_mime_object_get_content_type_parameter (parent, "protocol");
|
||||||
|
GMimeContentType *ct = g_mime_object_get_content_type (payload);
|
||||||
|
if (ct && enc_type) {
|
||||||
|
const char *part_type = g_mime_content_type_get_mime_type (ct);
|
||||||
|
if (part_type && strcmp (part_type, enc_type) == 0)
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_crypto->payload_encountered = true;
|
||||||
|
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_successful_decryption (_notmuch_message_crypto_t *msg_crypto)
|
||||||
|
{
|
||||||
|
if (!msg_crypto)
|
||||||
|
return NOTMUCH_STATUS_NULL_POINTER;
|
||||||
|
|
||||||
|
/* see the rationale for different values of
|
||||||
|
* _notmuch_message_decryption_status_t in util/crypto.h */
|
||||||
|
if (!msg_crypto->payload_encountered)
|
||||||
|
msg_crypto->decryption_status = NOTMUCH_MESSAGE_DECRYPTED_FULL;
|
||||||
|
else if (msg_crypto->decryption_status == NOTMUCH_MESSAGE_DECRYPTED_NONE)
|
||||||
|
msg_crypto->decryption_status = NOTMUCH_MESSAGE_DECRYPTED_PARTIAL;
|
||||||
|
|
||||||
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,71 @@ _notmuch_crypto_decrypt (bool *attempted,
|
||||||
void
|
void
|
||||||
_notmuch_crypto_cleanup (_notmuch_crypto_t *crypto);
|
_notmuch_crypto_cleanup (_notmuch_crypto_t *crypto);
|
||||||
|
|
||||||
|
/* The user probably wants to know if the entire message was in the
|
||||||
|
* clear. When replying, the MUA probably wants to know whether there
|
||||||
|
* was any part decrypted in the message. And when displaying to the
|
||||||
|
* user, we probably only want to display "encrypted message" if the
|
||||||
|
* entire message was covered by encryption. */
|
||||||
|
typedef enum {
|
||||||
|
NOTMUCH_MESSAGE_DECRYPTED_NONE = 0,
|
||||||
|
NOTMUCH_MESSAGE_DECRYPTED_PARTIAL,
|
||||||
|
NOTMUCH_MESSAGE_DECRYPTED_FULL,
|
||||||
|
} _notmuch_message_decryption_status_t;
|
||||||
|
|
||||||
|
/* description of the cryptographic state of a given message overall;
|
||||||
|
* for use by simple user agents.
|
||||||
|
*/
|
||||||
|
typedef struct _notmuch_message_crypto {
|
||||||
|
/* encryption status: partial, full, none */
|
||||||
|
_notmuch_message_decryption_status_t decryption_status;
|
||||||
|
/* FIXME: can we show what key(s) a fully-encrypted message was
|
||||||
|
* encrypted to? This data is not necessarily cryptographically
|
||||||
|
* reliable; even when we decrypt, we might not know which public
|
||||||
|
* key was used (e.g. if we're using a session key). */
|
||||||
|
|
||||||
|
/* signature status of the whole message (either the whole message
|
||||||
|
* is signed, or it is not) -- this means that partially-signed
|
||||||
|
* messages will get no signature status. */
|
||||||
|
GMimeSignatureList * sig_list;
|
||||||
|
/* if part of the message was signed, and the MUA is clever, it
|
||||||
|
* can determine on its own exactly which part and try to make
|
||||||
|
* more sense of it. */
|
||||||
|
|
||||||
|
/* mark this flag once we encounter a payload (i.e. something that
|
||||||
|
* is not part of the cryptographic envelope) */
|
||||||
|
bool payload_encountered;
|
||||||
|
|
||||||
|
/* if both signed and encrypted, was the signature encrypted? */
|
||||||
|
bool signature_encrypted;
|
||||||
|
} _notmuch_message_crypto_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* _notmuch_message_crypto_t objects should be released with
|
||||||
|
* talloc_free (), or they will be released along with their parent
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
_notmuch_message_crypto_t *
|
||||||
|
_notmuch_message_crypto_new (void *ctx);
|
||||||
|
|
||||||
|
/* call potential_sig_list during a depth-first-search on a message to
|
||||||
|
* consider a particular signature as relevant for the message.
|
||||||
|
*/
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_potential_sig_list (_notmuch_message_crypto_t *msg_crypto, GMimeSignatureList *sigs);
|
||||||
|
|
||||||
|
/* call successful_decryption during a depth-first-search on a message
|
||||||
|
* to indicate that a part was successfully decrypted.
|
||||||
|
*/
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_successful_decryption (_notmuch_message_crypto_t *msg_crypto);
|
||||||
|
|
||||||
|
/* call potential_payload during a depth-first-search on a message
|
||||||
|
* when encountering a message part that is not part of the envelope.
|
||||||
|
*/
|
||||||
|
notmuch_status_t
|
||||||
|
_notmuch_message_crypto_potential_payload (_notmuch_message_crypto_t *msg_crypto, GMimeObject *payload, GMimeObject *parent, int childnum);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue