crypto: add --decrypt=nostash to avoid stashing session keys

Here's the configuration choice for people who want a cleartext index,
but don't want stashed session keys.

Interestingly, this "nostash" decryption policy is actually the same
policy that should be used by "notmuch show" and "notmuch reply",
since they never modify the index or database when they are invoked
with --decrypt.

We take advantage of this parallel to tune the behavior of those
programs so that we're not requesting session keys from GnuPG during
"show" and "reply" that we would then otherwise just throw away.
This commit is contained in:
Daniel Kahn Gillmor 2017-12-08 01:24:02 -05:00 committed by David Bremner
parent 29648a137c
commit fccebbaeef
12 changed files with 71 additions and 27 deletions

View file

@ -288,7 +288,7 @@ _notmuch_insert()
return
;;
--decrypt)
COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) )
COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
return
;;
esac
@ -320,7 +320,7 @@ _notmuch_new()
$split &&
case "${prev}" in
--decrypt)
COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) )
COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
return
;;
esac
@ -442,7 +442,7 @@ _notmuch_reindex()
$split &&
case "${prev}" in
--decrypt)
COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) )
COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
return
;;
esac

View file

@ -141,6 +141,9 @@ The available configuration items are described below.
**index.decrypt**
**[STORED IN DATABASE]**
One of ``false``, ``auto``, ``nostash``, or ``true``.
When indexing an encrypted e-mail message, if this variable is
set to ``true``, notmuch will try to decrypt the message and
index the cleartext, stashing a copy of any discovered session
@ -150,11 +153,15 @@ The available configuration items are described below.
secret keys. Use ``false`` to avoid decrypting even when a
stashed session key is already present.
Be aware that the notmuch index is likely sufficient to
reconstruct the cleartext of the message itself, so please
ensure that the notmuch message index is adequately protected.
DO NOT USE ``index.decrypt=true`` without considering the
security of your index.
``nostash`` is the same as ``true`` except that it will not
stash newly-discovered session keys in the database.
Be aware that the notmuch index is likely sufficient (and a
stashed session key is certainly sufficient) to reconstruct
the cleartext of the message itself, so please ensure that the
notmuch message index is adequately protected. DO NOT USE
``index.decrypt=true`` or ``index.decrypt=nostash`` without
considering the security of your index.
Default: ``auto``.

View file

@ -51,10 +51,10 @@ Supported options for **insert** include
``--no-hooks``
Prevent hooks from being run.
``--decrypt=(true|auto|false)``
``--decrypt=(true|nostash|auto|false)``
If ``true`` and the message is encrypted, try to decrypt the
message while indexing, storing any session keys discovered.
message while indexing, stashing any session keys discovered.
If ``auto``, and notmuch already knows about a session key for
the message, it will try decrypting using that session key but
will not try to access the user's secret keys. If decryption
@ -62,11 +62,15 @@ Supported options for **insert** include
message is always stored to disk in its original form
(ciphertext).
Be aware that the index is likely sufficient to reconstruct
the cleartext of the message itself, so please ensure that the
``nostash`` is the same as ``true`` except that it will not
stash newly-discovered session keys in the database.
Be aware that the index is likely sufficient (and a stashed
session key is certainly sufficient) to reconstruct the
cleartext of the message itself, so please ensure that the
notmuch message index is adequately protected. DO NOT USE
``--decrypt=true`` without considering the security of
your index.
``--decrypt=true`` or ``--decrypt=nostash`` without
considering the security of your index.
See also ``index.decrypt`` in **notmuch-config(1)**.

View file

@ -43,10 +43,10 @@ Supported options for **new** include
``--quiet``
Do not print progress or results.
``--decrypt=(true|auto|false)``
``--decrypt=(true|nostash|auto|false)``
If ``true``, when encountering an encrypted message, try to
decrypt it while indexing, and store any discovered session
decrypt it while indexing, and stash any discovered session
keys. If ``auto``, try to use any session key already known
to belong to this message, but do not attempt to use the
user's secret keys. If decryption is successful, index the
@ -56,7 +56,8 @@ Supported options for **new** include
key is certainly sufficient) to reconstruct the cleartext of
the message itself, so please ensure that the notmuch message
index is adequately protected. DO NOT USE ``--decrypt=true``
without considering the security of your index.
or ``--decrypt=nostash`` without considering the security of
your index.
See also ``index.decrypt`` in **notmuch-config(1)**.

View file

@ -21,23 +21,27 @@ messages using the supplied options.
Supported options for **reindex** include
``--decrypt=(true|auto|false)``
``--decrypt=(true|nostash|auto|false)``
If ``true``, when encountering an encrypted message, try to
decrypt it while reindexing, storing any session keys
decrypt it while reindexing, stashing any session keys
discovered. If ``auto``, and notmuch already knows about a
session key for the message, it will try decrypting using that
session key but will not try to access the user's secret keys.
If decryption is successful, index the cleartext itself.
``nostash`` is the same as ``true`` except that it will not
stash newly-discovered session keys in the database.
If ``false``, notmuch reindex will also delete any stashed
session keys for all messages matching the search terms.
Be aware that the index is likely sufficient to reconstruct
the cleartext of the message itself, so please ensure that the
Be aware that the index is likely sufficient (and a stashed
session key is certainly sufficient) to reconstruct the
cleartext of the message itself, so please ensure that the
notmuch message index is adequately protected. DO NOT USE
``--decrypt=true`` without considering the security of your
index.
``--decrypt=true`` or ``--decrypt=nostash`` without
considering the security of your index.
See also ``index.decrypt`` in **notmuch-config(1)**.

View file

@ -42,6 +42,8 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db)
(!(strcasecmp(decrypt_policy, "no"))) ||
(!(strcasecmp(decrypt_policy, "0"))))
notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_FALSE);
else if (!strcasecmp(decrypt_policy, "nostash"))
notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_NOSTASH);
}
free (decrypt_policy);

View file

@ -2242,6 +2242,7 @@ typedef enum {
NOTMUCH_DECRYPT_FALSE,
NOTMUCH_DECRYPT_TRUE,
NOTMUCH_DECRYPT_AUTO,
NOTMUCH_DECRYPT_NOSTASH,
} notmuch_decryption_policy_t;
/**

View file

@ -730,7 +730,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])
notmuch_process_shared_options (argv[0]);
if (decrypt_set)
params.crypto.decrypt = decrypt ? NOTMUCH_DECRYPT_TRUE : NOTMUCH_DECRYPT_FALSE;
params.crypto.decrypt = decrypt ? NOTMUCH_DECRYPT_NOSTASH : NOTMUCH_DECRYPT_FALSE;
notmuch_exit_if_unsupported_format ();

View file

@ -1121,7 +1121,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
if (decrypt_set) {
if (decrypt) {
params.crypto.decrypt = NOTMUCH_DECRYPT_TRUE;
/* we do not need or want to ask for session keys */
params.crypto.decrypt = NOTMUCH_DECRYPT_NOSTASH;
/* decryption implies verification */
params.crypto.verify = true;
} else {

View file

@ -104,6 +104,7 @@ const notmuch_opt_desc_t notmuch_shared_indexing_options [] = {
(notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE },
{ "true", NOTMUCH_DECRYPT_TRUE },
{ "auto", NOTMUCH_DECRYPT_AUTO },
{ "nostash", NOTMUCH_DECRYPT_NOSTASH },
{ 0, 0 } },
.name = "decrypt" },
{ }

View file

@ -188,6 +188,29 @@ test_expect_equal \
"$output" \
"$expected"
test_begin_subtest "index cleartext without keeping session keys"
test_expect_success "notmuch reindex --decrypt=nostash tag:blarney"
test_begin_subtest "Ensure that the indexed terms are present"
output=$(notmuch search wumpus)
test_expect_equal \
"$output" \
"$expected"
test_begin_subtest "show one of the messages with --decrypt"
output=$(notmuch show --decrypt thread:0000000000000001 | awk '/^\014part}/{ f=0 }; { if (f) { print $0 } } /^\014part{ ID: 3/{ f=1 }')
expected='This is a test encrypted message with a wumpus.'
test_expect_equal \
"$output" \
"$expected"
test_begin_subtest "Ensure that we cannot show the message without --decrypt"
output=$(notmuch show thread:0000000000000001 | awk '/^\014part}/{ f=0 }; { if (f) { print $0 } } /^\014part{ ID: 3/{ f=1 }')
expected='Non-text part: application/octet-stream'
test_expect_equal \
"$output" \
"$expected"
add_email_corpus crypto
test_begin_subtest "indexing message fails when secret key not available"

View file

@ -199,7 +199,7 @@ _notmuch_crypto_decrypt (bool *attempted,
#if (GMIME_MAJOR_VERSION < 3)
#if HAVE_GMIME_SESSION_KEYS
gboolean oldgetsk = g_mime_crypto_context_get_retrieve_session_key (crypto_ctx);
gboolean newgetsk = (decrypt_result);
gboolean newgetsk = (decrypt == NOTMUCH_DECRYPT_TRUE && decrypt_result);
if (newgetsk != oldgetsk)
/* This could return an error, but we can't do anything about it, so ignore it */
g_mime_crypto_context_set_retrieve_session_key (crypto_ctx, newgetsk, NULL);
@ -212,7 +212,7 @@ _notmuch_crypto_decrypt (bool *attempted,
#endif
#else
GMimeDecryptFlags flags = GMIME_DECRYPT_NONE;
if (decrypt_result)
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);