Re: DRAFT Introduce CFFI-based Python bindings
I guess you'll have to convince the maintainers / users of alot and afew that this makes sense before we go much further. I'd point out that Debian stable is only at python 3.5, so that makes me a bit wary of this (being able to run the test suite on debian stable and similar aged distros useful for me, and I suspect other developers). I know there are issues with memory management in the current bindings, so that may be a strong reason to push to python 3.6; it seems to need more investigation at the moment. I am generally in favour of modernizing the notmuch python bindings, especially when it comes to memory management and exception handling. At the moment, the alot interface officially only supports python v2.7 but our dependencies have now mostly been updated and we are working on port to python 3, see here: https://github.com/pazz/alot/pull/1055 afew maintainer here ;-) I'm also very much in favor of a more modern and pythonic interface, and would gladly support retiring python 2, moving to the new interface. I had a quick glimpse on the code, and would like to do some annotations. I fear it's a bit awkward to do this inside the huge patch, which might already have changed, and send back via email. Did you publish a changeset to github, or somewhere else where I could comment on it? Cheers, Florian signature.asc Description: PGP signature ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 15/18] crypto: actually stash session keys when try-decrypt=true
On Thu 2017-11-16 08:53:14 -0400, David Bremner wrote: > I'd be happier if we didn't further entrench the text format in the test > suite. How hard would it be to use json output (+maybe python?) here? json output seems clunkier to me, and i don't think it's necessary for the purposes of these tests. Using python here isn't possible without updating the python bindings to accomodate decryption policy, which doesn't come until later in the series. so i'd prefer to leave it as-is, but i wouldn't object if someone wanted to propose a good patch to these tests that uses json. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 18/18] python: add try_decrypt argument to Database.index_file()
On Thu 2017-11-16 09:06:09 -0400, David Bremner wrote: > I think this new bindings functionality needs a test. agreed, the python bindings do need to be added to the test suite (this is also true in the newer version of the series). I'm happy to add those tests as a condition of getting the python bindings merged, but i hope they won't block the review and merge of the rest of the series :) --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 21/21] python: add decrypt_policy argument to Database.index_file()
On Thu 2017-11-30 03:59:46 -0500, Daniel Kahn Gillmor wrote: > @@ -454,10 +487,19 @@ class Database(object): >:attr:`STATUS`.READ_ONLY_DATABASE >Database was opened in read-only mode so no message can >be added. > + > """ > self._assert_db_is_initialized() ugh, somehow i missed this gratuitous whitespace addition the second time around. This is fixed in my gitlab session-keys branch [0], but it doesn't seem worth re-posting the entire 21-message series here to fix it. --dkg [0] https://gitlab.com/dkg/notmuch ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 04/21] crypto: use stashed session-key properties for decryption, if available
On Thu 2017-11-30 03:59:29 -0500, Daniel Kahn Gillmor wrote: > +hexidecimal representation of the algorithm-specific key. For ugh, this should be hexadecimal, not hexidecimal. This is fixed in my gitlab session-keys branch [0], but doesn't seem worth re-posting the entire series for. :) --dkg [0] https://gitlab.com/dkg/notmuch ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
On Thu 2017-11-30 09:44:19 -0400, David Bremner wrote: > Floris Bruynooghe writes: > >> This also has the binary question problem, is this returned as bytes or >> as str? Current Python bindings seem to go for .decode('utf-8', >> errors='ignore') afaik which is somewhat lossy. >> > > IMHO there's no reason to support non-utf8 properties. We should > document this restriction now while adoption is relatively light. Agreed, my reading of the source is that we expect strings for both property names and property values. If they're both strings, we should not support anything other than UTF-8 in either case. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] cli/help: give a hint about notmuch-emacs-mua
On Thu 2017-11-30 11:08:05 +0200, Tomi Ollila wrote: > On Thu, Nov 30 2017, Daniel Kahn Gillmor wrote: > >> On Thu 2017-10-26 18:27:51 -0400, Daniel Kahn Gillmor wrote: >>> "notmuch help" doesn't mention "notmuch-emacs-mua" even though we >>> support it through the try_external_command() mechanism. >>> >>> In addition, "notmuch help emacs-mua" doesn't work, even though we >>> ship the appropriate manpage. >>> >>> This changeset fixes both of these problems. >> >> Ping! i don't think this patch is complex or objectionable. Can it be >> merged? > > it may (*) look like we don't have #if WITH_EMACS (**) cpp macros defined ??? > > Tomi > > (*) did not check... > > (**) this is emacs-specific stull, less generic that other hints (if that > matters) ... > > Sorry to cause confusion... confusion is right! i don't understand what you're saying, sorry. are you suggesting a different change somehow? Want to propose a different patch? --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 1/5] debian/control: build-depend on python3-sphinx instead of python-sphinx
On Thu 2017-11-30 04:40:39 -0500, Daniel Kahn Gillmor wrote: > python2 is going to be deprecated, and python3-sphinx is available all > the way back to oldoldstable. let's use the more modern version. > --- > debian/control | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/debian/control b/debian/control > index 20b8a2db..3a624fdc 100644 > --- a/debian/control > +++ b/debian/control > @@ -18,7 +18,7 @@ Build-Depends: > python3-all (>= 3.1.2-7~), > dh-python, > dh-elpa (>= 1.3), > - python-sphinx (>= 1.0), > + python3-sphinx, > ruby, ruby-dev (>>1:1.9.3~), > emacs25-nox | emacs25 (>=25~) | emacs25-lucid (>=25~) | > emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~) | hm, on further reflection, this one is specifically problematic because of the use of: ${python} -m sphinx.writers.manpage in ./configure, used to test for the presence of the sphinx module. This can be fixed by preferring python3 here: --- a/configure +++ b/configure @@ -557,7 +557,7 @@ fi printf "Checking for python... " have_python=0 -for name in ${PYTHON} python python2 python3; do +for name in ${PYTHON} python3 python python2; do if command -v $name > /dev/null; then have_python=1 python=$name any thoughts or preferences on this? --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: debian packaging cleanup
On Thu 2017-11-30 08:01:18 -0400, David Bremner wrote: > Daniel Kahn Gillmor writes: > >> The following patch series should be fairly unobjectionable cleanup of >> the debian packaging for notmuch. >> >> Let me know if you think there are problems with any of it. > > Not problems per se, but I would expect several of these things to be > documented in debian/changelog, including the standards version change. I was presuming to do one rollup patch to build out the debian/changelog entry as release time approaches, rather than including changelog messages in the patches themselves. That rollup patch should be fairly easy to do with, e.g.: gbp dch --new-version=0.26-1 debian/ I prefer this approach because: (a) it doesn't confuse changelog messages with patches, and (b) it means that we don't end up with heavily-ordered patches, where it's more difficult merge some patches from a series than others, because each patch to d/changelog depends on the immediately prior changeset. I'd much rather you (or anyone else reviewing) can immediately and trivially pull the changes you like from the series while leaving the ones you're less certain about unmerged, for further discussion. Case in point here, the change to python3-sphinx might be more problematic than i'd originally expected. I wouldn't want anyone to have to rewrite the subsequent trivial patches just to leave that one behind. Is there a reason to prefer patching d/changelog in each individual changeset? --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
Floris Bruynooghe writes: > Daniel Kahn Gillmor writes: > > This also has the binary question problem, is this returned as bytes or > as str? Current Python bindings seem to go for .decode('utf-8', > errors='ignore') afaik which is somewhat lossy. > IMHO there's no reason to support non-utf8 properties. We should document this restriction now while adoption is relatively light. d ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: debian packaging cleanup
Daniel Kahn Gillmor writes: > The following patch series should be fairly unobjectionable cleanup of > the debian packaging for notmuch. > > Let me know if you think there are problems with any of it. > Not problems per se, but I would expect several of these things to be documented in debian/changelog, including the standards version change. d ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/5] debian/control: build-depend on python3-sphinx instead of python-sphinx
python2 is going to be deprecated, and python3-sphinx is available all the way back to oldoldstable. let's use the more modern version. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 20b8a2db..3a624fdc 100644 --- a/debian/control +++ b/debian/control @@ -18,7 +18,7 @@ Build-Depends: python3-all (>= 3.1.2-7~), dh-python, dh-elpa (>= 1.3), - python-sphinx (>= 1.0), + python3-sphinx, ruby, ruby-dev (>>1:1.9.3~), emacs25-nox | emacs25 (>=25~) | emacs25-lucid (>=25~) | emacs24-nox | emacs24 (>=24~) | emacs24-lucid (>=24~) | -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 4/5] debian: bump Standards-Version to 4.1.1
No minor changes were necessary to become compliant with Debian policy version 4.1.1, so this is basically a freebie. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index bb88b0f7..51129886 100644 --- a/debian/control +++ b/debian/control @@ -28,7 +28,7 @@ Build-Depends: gpgsm , gnupg , bash-completion (>=1.9.0~) -Standards-Version: 4.0.0 +Standards-Version: 4.1.1 Homepage: https://notmuchmail.org/ Vcs-Git: git://notmuchmail.org/git/notmuch Vcs-Browser: https://git.notmuchmail.org/git/notmuch -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 5/5] debian/control: put elpa-notmuch in Section: lisp.
This makes lintian stop complaining about: W: elpa-notmuch: wrong-section-according-to-package-name elpa-notmuch => lisp --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 51129886..cff610cf 100644 --- a/debian/control +++ b/debian/control @@ -121,6 +121,7 @@ Description: thread-based email index, search and tagging (transitional package) Package: elpa-notmuch Architecture: all Depends: ${misc:Depends}, ${elpa:Depends} +Section: lisp Description: thread-based email index, search and tagging (emacs interface) Notmuch is a system for indexing, searching, reading, and tagging large collections of email messages in maildir or mh format. It uses -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/5] debian/changelog: remove trailing whitespace
--- debian/changelog | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/debian/changelog b/debian/changelog index 67282a07..decef1e9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -836,7 +836,7 @@ notmuch (0.9~rc2-1) experimental; urgency=low - New SONAME for libnotmuch - bindings changes for ruby and python * Less non-text parts reported in replies. - * emacs: provide button action to fetch unknown gpg keys + * emacs: provide button action to fetch unknown gpg keys -- David Bremner Fri, 07 Oct 2011 18:53:04 -0300 @@ -845,7 +845,7 @@ notmuch (0.9~rc1-1) experimental; urgency=low * Upstream release candidate - Atomicity improvements, thanks to Austin Clements - Add missing call to g_type_init, thanks to Aaron Ecay - * notmuch-emacs: add versioned dependency on notmuch. + * notmuch-emacs: add versioned dependency on notmuch. (Closes: #642240). -- David Bremner Sun, 25 Sep 2011 11:26:01 -0300 @@ -854,7 +854,7 @@ notmuch (0.8-1) unstable; urgency=low * New upstream version. - Improved handling of message/rfc822 parts -- Improved Build system portability +- Improved Build system portability - Documentation update for Ruby bindings - Unicode, iterator, PEP8 changes for python bindings @@ -936,7 +936,7 @@ notmuch (0.6~254) experimental; urgency=low [ Jameson Rollins ] * Bump standards version to 3.9.2 (No changes). - + -- David Bremner Thu, 23 Jun 2011 07:50:05 -0300 notmuch (0.6~237) experimental; urgency=low @@ -981,8 +981,8 @@ notmuch (0.6~171) experimental; urgency=low * notmuch reply: Avoid segmentation fault when printing multiple parts * notmuch show: New part output handling. * emacs: Show cleaner `From:' addresses in the summary line. - * emacs: Add custom `notmuch-show-elide-same-subject', -`notmuch-show-always-show-subject' + * emacs: Add custom `notmuch-show-elide-same-subject', +`notmuch-show-always-show-subject' * emacs: Render text/x-vcalendar parts. * emacs: Add `notmuch-show-multipart/alternative-discouraged'. * vim: parse 'from' address, use sendmail directly, implement archive in @@ -1114,7 +1114,7 @@ notmuch (0.2) unstable; urgency=low * Fix headers to be properly decoded in "notmuch reply" * emacs: Show the last few lines of citations as well as the first few lines. * emacs: The '+' and '-' commands can now add and remove tags by region. - * emacs: More meaningful buffer names for thread-view buffers. + * emacs: More meaningful buffer names for thread-view buffers. * emacs: Customized colors of threads in search view based on tags. -- Carl Worth Fri, 16 Apr 2010 10:20:23 -0700 -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
debian packaging cleanup
The following patch series should be fairly unobjectionable cleanup of the debian packaging for notmuch. Let me know if you think there are problems with any of it. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 3/5] debian/control: Priority: extra is deprecated
Move transitional package to to "oldlibs/optional" This resolves two lintian warnings: W: notmuch-emacs: transitional-package-should-be-oldlibs-optional oldlibs/extra W: notmuch-emacs: priority-extra-is-replaced-by-priority-optional --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 3a624fdc..bb88b0f7 100644 --- a/debian/control +++ b/debian/control @@ -113,7 +113,6 @@ Description: Ruby interface to the notmuch mail search and index library Package: notmuch-emacs Section: oldlibs -Priority: extra Architecture: all Depends: elpa-notmuch, ${misc:Depends} Description: thread-based email index, search and tagging (transitional package) -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] cli/help: give a hint about notmuch-emacs-mua
On Thu, Nov 30 2017, Daniel Kahn Gillmor wrote: > On Thu 2017-10-26 18:27:51 -0400, Daniel Kahn Gillmor wrote: >> "notmuch help" doesn't mention "notmuch-emacs-mua" even though we >> support it through the try_external_command() mechanism. >> >> In addition, "notmuch help emacs-mua" doesn't work, even though we >> ship the appropriate manpage. >> >> This changeset fixes both of these problems. > > Ping! i don't think this patch is complex or objectionable. Can it be > merged? it may (*) look like we don't have #if WITH_EMACS (**) cpp macros defined ??? Tomi (*) did not check... (**) this is emacs-specific stull, less generic that other hints (if that matters) ... Sorry to cause confusion... > > --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 01/21] mime-node: handle decrypt_result more safely
If (for whatever reason) we don't get a decrypt_result back, or it's not structured the way we expect it to be, we shouldn't choke on it. --- mime-node.c | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mime-node.c b/mime-node.c index e1aca969..7c8b2602 100644 --- a/mime-node.c +++ b/mime-node.c @@ -214,13 +214,15 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, node->decrypt_success = true; node->verify_attempted = true; -/* 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); +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); + } + g_object_unref (decrypt_result); } -g_object_unref (decrypt_result); DONE: if (err) -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 02/21] crypto: add _notmuch_crypto_decrypt wrapper function
We will use this centralized function to consolidate the awkward behavior around different gmime versions. It's only invoked from two places: mime-node.c's node_decrypt_and_verify() and lib/index.cc's _index_encrypted_mime_part(). However, those two places have some markedly distinct logic, so the interface for this _notmuch_crypto_decrypt function is going to get a little bit clunky. It's worthwhile, though, for the sake of keeping these #if directives reasonably well-contained. --- lib/index.cc | 8 ++-- mime-node.c | 8 ++-- util/crypto.c | 18 ++ util/crypto.h | 7 +-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 6e684f5f..19d03456 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -530,9 +530,9 @@ _index_encrypted_mime_part (notmuch_message_t *message, notmuch = _notmuch_message_database (message); +GMimeCryptoContext* crypto_ctx = NULL; #if (GMIME_MAJOR_VERSION < 3) { - GMimeCryptoContext* crypto_ctx = NULL; const char *protocol = NULL; protocol = g_mime_content_type_get_parameter (content_type, "protocol"); status = _notmuch_crypto_get_gmime_ctx_for_protocol (&(indexopts->crypto), @@ -546,13 +546,9 @@ _index_encrypted_mime_part (notmuch_message_t *message, "property (%d)\n", status); return; } - clear = g_mime_multipart_encrypted_decrypt(encrypted_data, crypto_ctx, - NULL, &err); } -#else -clear = g_mime_multipart_encrypted_decrypt(encrypted_data, GMIME_DECRYPT_NONE, NULL, - NULL, &err); #endif +clear = _notmuch_crypto_decrypt (crypto_ctx, encrypted_data, NULL, &err); if (err) { _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", err->domain, err->code, err->message); diff --git a/mime-node.c b/mime-node.c index 7c8b2602..ae3ebef6 100644 --- a/mime-node.c +++ b/mime-node.c @@ -199,12 +199,8 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part); node->decrypt_attempted = true; -node->decrypted_child = g_mime_multipart_encrypted_decrypt -#if (GMIME_MAJOR_VERSION < 3) - (encrypteddata, cryptoctx, &decrypt_result, &err); -#else -(encrypteddata, GMIME_DECRYPT_NONE, NULL, &decrypt_result, &err); -#endif +if (! node->decrypted_child) + node->decrypted_child = _notmuch_crypto_decrypt (cryptoctx, encrypteddata, &decrypt_result, &err); if (! node->decrypted_child) { fprintf (stderr, "Failed to decrypt part: %s\n", err ? err->message : "no error explanation given"); diff --git a/util/crypto.c b/util/crypto.c index 5c84282e..087536ec 100644 --- a/util/crypto.c +++ b/util/crypto.c @@ -138,3 +138,21 @@ void _notmuch_crypto_cleanup (unused(_notmuch_crypto_t *crypto)) { } #endif + +GMimeObject * +_notmuch_crypto_decrypt (g_mime_3_unused(GMimeCryptoContext* crypto_ctx), +GMimeMultipartEncrypted *part, +GMimeDecryptResult **decrypt_result, +GError **err) +{ +GMimeObject *ret = NULL; + +#if (GMIME_MAJOR_VERSION < 3) +ret = g_mime_multipart_encrypted_decrypt(part, crypto_ctx, +decrypt_result, err); +#else +ret = g_mime_multipart_encrypted_decrypt(part, GMIME_DECRYPT_NONE, NULL, +decrypt_result, err); +#endif +return ret; +} diff --git a/util/crypto.h b/util/crypto.h index 1ff0297d..d68634f3 100644 --- a/util/crypto.h +++ b/util/crypto.h @@ -2,10 +2,8 @@ #define _CRYPTO_H #include -#if (GMIME_MAJOR_VERSION < 3) #include "gmime-extra.h" #include "notmuch.h" -#endif typedef struct _notmuch_crypto { bool verify; @@ -17,6 +15,11 @@ typedef struct _notmuch_crypto { #endif } _notmuch_crypto_t; +GMimeObject * +_notmuch_crypto_decrypt (GMimeCryptoContext* crypto_ctx, +GMimeMultipartEncrypted *part, +GMimeDecryptResult **decrypt_result, +GError **err); #if (GMIME_MAJOR_VERSION < 3) notmuch_status_t -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 03/21] configure: session key handling in gmime maps to built_with("session_key")
This flag should make it easier to write the code for session-key handling. Note that this only works for GMime 2.6.21 and later (the session key interface wasn't available before then). It should be fine to build the rest of notmuch if this functionality isn't available. Note that this also adds the "session_key" built_with() aspect to libnotmuch. --- configure| 14 ++ lib/built-with.c | 2 ++ 2 files changed, 16 insertions(+) diff --git a/configure b/configure index cfbf827c..bd034f91 100755 --- a/configure +++ b/configure @@ -487,14 +487,21 @@ if pkg-config --exists "gmime-3.0 > $GMIME3_MINVER"; then gmime_cflags=$(pkg-config --cflags gmime-3.0) gmime_ldflags=$(pkg-config --libs gmime-3.0) gmime_major=3 +have_gmime_session_keys=1 elif pkg-config --exists "gmime-2.6 >= $GMIME_MINVER"; then printf "Yes (2.6).\n" have_gmime=1 gmime_cflags=$(pkg-config --cflags gmime-2.6) gmime_ldflags=$(pkg-config --libs gmime-2.6) gmime_major=2 +if pkg-config --exists "gmime-2.6 >= 2.6.21"; then +have_gmime_session_keys=1 +else +have_gmime_session_keys=0 +fi else have_gmime=0 +have_gmime_session_keys=0 printf "No.\n" errors=$((errors + 1)) fi @@ -1097,6 +1104,9 @@ HAVE_TIMEGM = ${have_timegm} # Whether struct dirent has d_type (if not, then notmuch will use stat) HAVE_D_TYPE = ${have_d_type} +# Whether the GMime version can handle extraction and reuse of session keys +HAVE_GMIME_SESSION_KEYS = ${have_gmime_session_keys} + # Whether the Xapian version in use supports compaction HAVE_XAPIAN_COMPACT = ${have_xapian_compact} @@ -1182,6 +1192,7 @@ COMMON_CONFIGURE_CFLAGS = \\ -DHAVE_D_TYPE=\$(HAVE_D_TYPE) \\ -DSTD_GETPWUID=\$(STD_GETPWUID) \\ -DSTD_ASCTIME=\$(STD_ASCTIME) \\ + -DHAVE_GMIME_SESSION_KEYS=\$(HAVE_GMIME_SESSION_KEYS) \\ -DHAVE_XAPIAN_COMPACT=\$(HAVE_XAPIAN_COMPACT) \\ -DSILENCE_XAPIAN_DEPRECATION_WARNINGS \\ -DHAVE_XAPIAN_FIELD_PROCESSOR=\$(HAVE_XAPIAN_FIELD_PROCESSOR) \\ @@ -1210,6 +1221,9 @@ NOTMUCH_HAVE_XAPIAN_FIELD_PROCESSOR=${have_xapian_field_processor} # Whether the Xapian version in use supports lock retry NOTMUCH_HAVE_XAPIAN_DB_RETRY_LOCK=${have_xapian_db_retry_lock} +# Whether the GMime version can handle extraction and reuse of session keys +NOTMUCH_HAVE_GMIME_SESSION_KEYS=${have_gmime_session_keys} + # Which backend will Xapian use by default? NOTMUCH_DEFAULT_XAPIAN_BACKEND=${default_xapian_backend} diff --git a/lib/built-with.c b/lib/built-with.c index 27384bd0..9cffd9f9 100644 --- a/lib/built-with.c +++ b/lib/built-with.c @@ -30,6 +30,8 @@ notmuch_built_with (const char *name) return HAVE_XAPIAN_FIELD_PROCESSOR; } else if (STRNCMP_LITERAL (name, "retry_lock") == 0) { return HAVE_XAPIAN_DB_RETRY_LOCK; +} else if (STRNCMP_LITERAL (name, "session_key") == 0) { + return HAVE_GMIME_SESSION_KEYS; } else { return false; } -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 16/21] cli/new, insert, reindex: change index.decrypt to "auto" by default
The new "auto" decryption policy is not only good for "notmuch show" and "notmuch reindex". It's also useful for indexing messages -- there's no good reason to not try to go ahead and index the cleartext of a message that we have a stashed session key for. This change updates the defaults and tunes the test suite to make sure that they have taken effect. --- doc/man1/notmuch-config.rst | 2 +- lib/indexopts.c | 8 +--- test/T357-index-decryption.sh | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index 4835f897..1a9e08a3 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -154,7 +154,7 @@ The available configuration items are described below. DO NOT USE ``index.decrypt=true`` without considering the security of your index. -Default: ``false``. +Default: ``auto``. **built_with.** diff --git a/lib/indexopts.c b/lib/indexopts.c index a04d1c1c..26a31e89 100644 --- a/lib/indexopts.c +++ b/lib/indexopts.c @@ -26,7 +26,7 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db) notmuch_indexopts_t *ret = talloc_zero (db, notmuch_indexopts_t); if (!ret) return ret; -ret->crypto.decrypt = NOTMUCH_DECRYPT_FALSE; +ret->crypto.decrypt = NOTMUCH_DECRYPT_AUTO; char * decrypt_policy; notmuch_status_t err = notmuch_database_get_config (db, "index.decrypt", &decrypt_policy); @@ -38,8 +38,10 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db) (!(strcasecmp(decrypt_policy, "yes"))) || (!(strcasecmp(decrypt_policy, "1" notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_TRUE); - else if (!strcasecmp(decrypt_policy, "auto")) - notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_AUTO); + else if ((!(strcasecmp(decrypt_policy, "false"))) || +(!(strcasecmp(decrypt_policy, "no"))) || +(!(strcasecmp(decrypt_policy, "0" + notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_FALSE); } free (decrypt_policy); diff --git a/test/T357-index-decryption.sh b/test/T357-index-decryption.sh index 3157fd8c..b2717a7a 100755 --- a/test/T357-index-decryption.sh +++ b/test/T357-index-decryption.sh @@ -142,7 +142,7 @@ test_expect_equal \ # ensure no session keys are present: test_begin_subtest 'reindex using only session keys' -test_expect_success 'notmuch reindex --decrypt=auto tag:encrypted and property:index.decryption=success' +test_expect_success 'notmuch reindex tag:encrypted and property:index.decryption=success' test_begin_subtest "reindexed encrypted messages, decrypting only with session keys" output=$(notmuch search wumpus) expected='' @@ -190,7 +190,7 @@ notmuch restore
[PATCH v2 08/21] indexopts: change _try_decrypt to _decrypt_policy
This terminology makes it clearer what's going on at the API layer, and paves the way for future changesets that offer more nuanced decryption policy. --- lib/index.cc | 2 +- lib/indexopts.c | 10 +- lib/notmuch.h| 8 notmuch-client.h | 4 ++-- notmuch.c| 12 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 6eb60f30..ff14e408 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -525,7 +525,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, notmuch_database_t * notmuch = NULL; GMimeObject *clear = NULL; -if (!indexopts || !notmuch_indexopts_get_try_decrypt (indexopts)) +if (!indexopts || !notmuch_indexopts_get_decrypt_policy (indexopts)) return; notmuch = _notmuch_message_database (message); diff --git a/lib/indexopts.c b/lib/indexopts.c index ca6bf6c9..0f65b97c 100644 --- a/lib/indexopts.c +++ b/lib/indexopts.c @@ -36,24 +36,24 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db) ((!(strcasecmp(decrypt, "true"))) || (!(strcasecmp(decrypt, "yes"))) || (!(strcasecmp(decrypt, "1") - notmuch_indexopts_set_try_decrypt (ret, true); + notmuch_indexopts_set_decrypt_policy (ret, true); free (decrypt); return ret; } notmuch_status_t -notmuch_indexopts_set_try_decrypt (notmuch_indexopts_t *indexopts, - notmuch_bool_t try_decrypt) +notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, + notmuch_bool_t decrypt_policy) { if (!indexopts) return NOTMUCH_STATUS_NULL_POINTER; -indexopts->crypto.decrypt = try_decrypt; +indexopts->crypto.decrypt = decrypt_policy; return NOTMUCH_STATUS_SUCCESS; } notmuch_bool_t -notmuch_indexopts_get_try_decrypt (const notmuch_indexopts_t *indexopts) +notmuch_indexopts_get_decrypt_policy (const notmuch_indexopts_t *indexopts) { if (!indexopts) return false; diff --git a/lib/notmuch.h b/lib/notmuch.h index 2c5dcab5..ef463090 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -2244,17 +2244,17 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db); * @since libnotmuch 5.1 (notmuch 0.26) */ notmuch_status_t -notmuch_indexopts_set_try_decrypt (notmuch_indexopts_t *indexopts, - notmuch_bool_t try_decrypt); +notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, + notmuch_bool_t decrypt_policy); /** * Return whether to decrypt encrypted parts while indexing. - * see notmuch_indexopts_set_try_decrypt. + * see notmuch_indexopts_set_decrypt_policy. * * @since libnotmuch 5.1 (notmuch 0.26) */ notmuch_bool_t -notmuch_indexopts_get_try_decrypt (const notmuch_indexopts_t *indexopts); +notmuch_indexopts_get_decrypt_policy (const notmuch_indexopts_t *indexopts); /** * Destroy a notmuch_indexopts_t object. diff --git a/notmuch-client.h b/notmuch-client.h index f7524e59..fc981459 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -500,8 +500,8 @@ int notmuch_minimal_options (const char* subcommand_name, /* the state chosen by the user invoking one of the notmuch * subcommands that does indexing */ struct _notmuch_client_indexing_cli_choices { -bool try_decrypt; -bool try_decrypt_set; +bool decrypt_policy; +bool decrypt_policy_set; notmuch_indexopts_t * opts; }; extern struct _notmuch_client_indexing_cli_choices indexing_cli_choices; diff --git a/notmuch.c b/notmuch.c index 5f5ac38a..e13f4b73 100644 --- a/notmuch.c +++ b/notmuch.c @@ -99,8 +99,8 @@ int notmuch_minimal_options (const char *subcommand_name, struct _notmuch_client_indexing_cli_choices indexing_cli_choices = { }; const notmuch_opt_desc_t notmuch_shared_indexing_options [] = { -{ .opt_bool = &indexing_cli_choices.try_decrypt, - .present = &indexing_cli_choices.try_decrypt_set, +{ .opt_bool = &indexing_cli_choices.decrypt_policy, + .present = &indexing_cli_choices.decrypt_policy_set, .name = "decrypt" }, { } }; @@ -111,21 +111,21 @@ notmuch_process_shared_indexing_options (notmuch_database_t *notmuch, g_mime_3_u { if (indexing_cli_choices.opts == NULL) indexing_cli_choices.opts = notmuch_database_get_default_indexopts (notmuch); -if (indexing_cli_choices.try_decrypt_set) { +if (indexing_cli_choices.decrypt_policy_set) { notmuch_status_t status; if (indexing_cli_choices.opts == NULL) return NOTMUCH_STATUS_OUT_OF_MEMORY; - status = notmuch_indexopts_set_try_decrypt (indexing_cli_choices.opts, indexing_cli_choices.try_decrypt); + status = notmuch_indexopts_set_decrypt_policy (indexing_cli_choices.opts, indexing_cli_choices.decrypt_policy); if (status != NOTMUCH_STATUS_SUCCESS) { fprintf (stderr, "Error: Failed to set index decryption policy to %s.
[PATCH v2 20/21] docs: clean up documentation about decryption policies
Now that the range of sensible decryption policies has come into full view, we take a bit of space to document the distinctions. Most people will use either "auto" or "true" -- but we provide "false" and "nostash" to handle use cases that might reasonably be requested. Note also that these can be combined in sensible ways. Like, if your mail comes in regularly to a service that doesn't have access to your secret keys, but does have access to your index, and you feel comfortable adding selected encrypted messages to the index after you've read them, you could stay in "auto" normally, and then when you find yourself reading an indexable message (e.g. one you want to be able to search for in the future, and that you don't mind exposing to whatever entities have access to your inde), you can do: notmuch reindex --decrypt=true id:whate...@example.biz That leaves your default the same (still "auto") but you get the cleartext index and stashed session key benefits for that particular message. --- doc/man1/notmuch-config.rst | 33 - 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index 773fd9da..3ba849b2 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -142,7 +142,9 @@ The available configuration items are described below. **[STORED IN DATABASE]** -One of ``false``, ``auto``, ``nostash``, or ``true``. +Policy for decrypting encrypted messages during indexing. +Must be 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 @@ -156,6 +158,34 @@ The available configuration items are described below. ``nostash`` is the same as ``true`` except that it will not stash newly-discovered session keys in the database. +From the command line (i.e. during **notmuch-new(1)**, +**notmuch-insert(1)**, or **notmuch-reindex(1)**), the user +can override the database's stored decryption policy with the +``--decrypt=`` option. + +Here is a table that summarizes the functionality of each of +these policies: + +++---+--+-+--+ +|| false | auto | nostash | true | +++===+==+=+==+ +| Index cleartext using | | X |X| X | +| stashed session keys | | | | | +++---+--+-+--+ +| Index cleartext| | |X| X | +| using secret keys | | | | | +++---+--+-+--+ +| Stash session keys | | | | X | +++---+--+-+--+ +| Delete stashed session | X | | | | +| keys on reindex| | | | | +++---+--+-+--+ + +Stashed session keys are kept in the database as properties +associated with the message. See ``session-key`` in +**notmuch-properties(7)** for more details about how they can +be useful. + 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 @@ -201,5 +231,6 @@ SEE ALSO **notmuch-restore(1)**, **notmuch-search(1)**, **notmuch-search-terms(7)**, +**notmuch-properties(7)**, **notmuch-show(1)**, **notmuch-tag(1)** -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 11/21] cli/reply: use decryption policy "auto" by default.
If the user doesn't specify --decrypt= at all, but a stashed session key is known to notmuch, when replying to an encrypted message, notmuch should just go ahead and decrypt. The user can disable this at the command line with --decrypt=false, though it's not clear why they would ever want to do that. --- completion/notmuch-completion.bash | 6 +- doc/man1/notmuch-reply.rst | 6 +- notmuch-reply.c| 9 + test/T357-index-decryption.sh | 7 +++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index e462a82a..1cd616b3 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -350,12 +350,16 @@ _notmuch_reply() COMPREPLY=( $( compgen -W "all sender" -- "${cur}" ) ) return ;; + --decrypt) + COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + return + ;; esac ! $split && case "${cur}" in -*) - local options="--format= --format-version= --reply-to= --decrypt ${_notmuch_shared_options}" + local options="--format= --format-version= --reply-to= --decrypt= ${_notmuch_shared_options}" compopt -o nospace COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ;; diff --git a/doc/man1/notmuch-reply.rst b/doc/man1/notmuch-reply.rst index b6aec3c8..ede77930 100644 --- a/doc/man1/notmuch-reply.rst +++ b/doc/man1/notmuch-reply.rst @@ -80,8 +80,12 @@ Supported options for **reply** include multipart/encrypted part will be replaced by the decrypted content. +If a session key is already known for the message, then it +will be decrypted automatically unless the user explicitly +sets ``--decrypt=false``. + Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will fail. +needed credentials. Without one, the decryption will likely fail. See **notmuch-search-terms(7)** for details of the supported syntax for . diff --git a/notmuch-reply.c b/notmuch-reply.c index eec34bed..fd990a9a 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -700,11 +700,12 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) int opt_index; notmuch_show_params_t params = { .part = -1, - .crypto = { .decrypt = NOTMUCH_DECRYPT_FALSE }, + .crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO }, }; int format = FORMAT_DEFAULT; int reply_all = true; bool decrypt = false; +bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = &format, .name = "format", .keywords = @@ -718,7 +719,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) (notmuch_keyword_t []){ { "all", true }, { "sender", false }, { 0, 0 } } }, - { .opt_bool = &decrypt, .name = "decrypt" }, + { .opt_bool = &decrypt, .name = "decrypt", .present = &decrypt_set }, { .opt_inherit = notmuch_shared_options }, { } }; @@ -728,8 +729,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; notmuch_process_shared_options (argv[0]); -if (decrypt) - params.crypto.decrypt = NOTMUCH_DECRYPT_TRUE; +if (decrypt_set) + params.crypto.decrypt = decrypt ? NOTMUCH_DECRYPT_TRUE : NOTMUCH_DECRYPT_FALSE; notmuch_exit_if_unsupported_format (); diff --git a/test/T357-index-decryption.sh b/test/T357-index-decryption.sh index 2901c390..06008e81 100755 --- a/test/T357-index-decryption.sh +++ b/test/T357-index-decryption.sh @@ -197,6 +197,13 @@ test_expect_equal \ "$output" \ "$expected" +test_begin_subtest "notmuch reply should show cleartext if session key is present" +output=$(notmuch reply id:simple-encryp...@crypto.notmuchmail.org | grep '^>') +expected='> This is a top sekrit message.' +test_expect_equal \ +"$output" \ +"$expected" + # TODO: test removal of a message from the message store between # indexing and reindexing. -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 12/21] cli/show: use decryption policy "auto" by default.
When showing a message, if the user doesn't specify --decrypt= at all, but a stashed session key is known to notmuch, notmuch should just go ahead and try to decrypt the message with the session key (without bothering the user for access to their asymmetric secret key). The user can disable this at the command line with --decrypt=false if they really don't want to look at the e-mail that they've asked notmuch to show them. and of course, "notmuch show --decrypt" still works for accessing the user's secret keys if necessary. --- completion/notmuch-completion.bash | 4 ++-- doc/man1/notmuch-show.rst | 4 notmuch-show.c | 17 +++-- test/T357-index-decryption.sh | 14 ++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 1cd616b3..f94dbeed 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -517,7 +517,7 @@ _notmuch_show() COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) ) return ;; - --exclude|--body) + --exclude|--body|--decrypt) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; @@ -526,7 +526,7 @@ _notmuch_show() ! $split && case "${cur}" in -*) - local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt --include-html ${_notmuch_shared_options}" + local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html ${_notmuch_shared_options}" compopt -o nospace COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ;; diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 7ba091cf..64caa7a6 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -123,6 +123,10 @@ Supported options for **show** include multipart/encrypted part will be replaced by the decrypted content. +If a session key is already known for the message, then it +will be decrypted automatically unless the user explicitly +sets ``--decrypt=false``. + Decryption expects a functioning **gpg-agent(1)** to provide any needed credentials. Without one, the decryption will fail. diff --git a/notmuch-show.c b/notmuch-show.c index e840a470..591889a9 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1105,13 +1105,14 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) .part = -1, .omit_excluded = true, .output_body = true, - .crypto = { .decrypt = NOTMUCH_DECRYPT_FALSE }, + .crypto = { .decrypt = NOTMUCH_DECRYPT_AUTO }, }; int format = NOTMUCH_FORMAT_NOT_SPECIFIED; bool exclude = true; bool entire_thread_set = false; bool single_message; bool decrypt = false; +bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = &format, .name = "format", .keywords = @@ -1126,7 +1127,7 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) { .opt_bool = ¶ms.entire_thread, .name = "entire-thread", .present = &entire_thread_set }, { .opt_int = ¶ms.part, .name = "part" }, - { .opt_bool = &decrypt, .name = "decrypt" }, + { .opt_bool = &decrypt, .name = "decrypt", .present = &decrypt_set }, { .opt_bool = ¶ms.crypto.verify, .name = "verify" }, { .opt_bool = ¶ms.output_body, .name = "body" }, { .opt_bool = ¶ms.include_html, .name = "include-html" }, @@ -1140,10 +1141,14 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) notmuch_process_shared_options (argv[0]); -if (decrypt) { - params.crypto.decrypt = NOTMUCH_DECRYPT_TRUE; - /* decryption implies verification */ - params.crypto.verify = true; +if (decrypt_set) { + if (decrypt) { + params.crypto.decrypt = NOTMUCH_DECRYPT_TRUE; + /* decryption implies verification */ + params.crypto.verify = true; + } else { + params.crypto.decrypt = NOTMUCH_DECRYPT_FALSE; + } } /* specifying a part implies single message display */ diff --git a/test/T357-index-decryption.sh b/test/T357-index-decryption.sh index 06008e81..3157fd8c 100755 --- a/test/T357-index-decryption.sh +++ b/test/T357-index-decryption.sh @@ -204,6 +204,20 @@ test_expect_equal \ "$output" \ "$expected" +test_begin_subtest "notmuch show should show cleartext if session key is present" +output=$(notmuch show id:simple-encryp...@crypto.notmuchmail.org | awk '/^\014part}/{ f=0 }; { if (f) { print $0 } } /^\014part{ ID: 3/{ f=1 }') +expected='This is a top sekrit message.' +test_expect_equal \ +"$output" \ +"$expected" + +test_begin_subtes
[PATCH v2 10/21] crypto: new decryption policy "auto"
This new automatic decryption policy should make it possible to decrypt messages that we have stashed session keys for, without incurring a call to the user's asymmetric keys. --- doc/man1/notmuch-config.rst | 11 --- lib/index.cc | 3 ++- lib/indexopts.c | 13 - lib/notmuch.h | 1 + mime-node.c | 7 --- notmuch-client.h | 4 +++- notmuch.c | 3 ++- test/T357-index-decryption.sh | 12 +++- util/crypto.c | 9 - util/crypto.h | 3 ++- 10 files changed, 49 insertions(+), 17 deletions(-) diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index ea3d9754..4835f897 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -142,9 +142,14 @@ The available configuration items are described below. **[STORED IN DATABASE]** 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. Be aware that the index is likely sufficient -to reconstruct the cleartext of the message itself, so please +set to ``true``, notmuch will try to decrypt the message and +index the cleartext. If ``auto``, it will try to index the +cleartext if a stashed session key is already known for the message, +but will not try to access your secret keys. Use ``false`` to +avoid decrypting even when a session key is already known. + +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. diff --git a/lib/index.cc b/lib/index.cc index 905366ae..af999bd3 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -548,7 +548,8 @@ _index_encrypted_mime_part (notmuch_message_t *message, } } #endif -clear = _notmuch_crypto_decrypt (message, crypto_ctx, encrypted_data, NULL, &err); +clear = _notmuch_crypto_decrypt (notmuch_indexopts_get_decrypt_policy (indexopts), +message, crypto_ctx, encrypted_data, NULL, &err); if (err) { _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", err->domain, err->code, err->message); diff --git a/lib/indexopts.c b/lib/indexopts.c index 78f53391..a04d1c1c 100644 --- a/lib/indexopts.c +++ b/lib/indexopts.c @@ -33,11 +33,14 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db) if (err) return ret; -if (decrypt_policy && - ((!(strcasecmp(decrypt_policy, "true"))) || -(!(strcasecmp(decrypt_policy, "yes"))) || -(!(strcasecmp(decrypt_policy, "1") - notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_TRUE); +if (decrypt_policy) { + if ((!(strcasecmp(decrypt_policy, "true"))) || + (!(strcasecmp(decrypt_policy, "yes"))) || + (!(strcasecmp(decrypt_policy, "1" + notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_TRUE); + else if (!strcasecmp(decrypt_policy, "auto")) + notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_AUTO); +} free (decrypt_policy); return ret; diff --git a/lib/notmuch.h b/lib/notmuch.h index 47633496..ff860e06 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -2241,6 +2241,7 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db); typedef enum { NOTMUCH_DECRYPT_FALSE, NOTMUCH_DECRYPT_TRUE, +NOTMUCH_DECRYPT_AUTO, } notmuch_decryption_policy_t; /** diff --git a/mime-node.c b/mime-node.c index c4de708b..49d668fe 100644 --- a/mime-node.c +++ b/mime-node.c @@ -205,7 +205,8 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, break; node->decrypt_attempted = true; - node->decrypted_child = _notmuch_crypto_decrypt (parent ? parent->envelope_file : NULL, + node->decrypted_child = _notmuch_crypto_decrypt (node->ctx->crypto->decrypt, +parent ? parent->envelope_file : NULL, cryptoctx, encrypteddata, &decrypt_result, &err); } if (! node->decrypted_child) { @@ -270,7 +271,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part) } #if (GMIME_MAJOR_VERSION < 3) -if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && (node->ctx->crypto->decrypt == NOTMUCH_DECRYPT_TRUE)) +if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && (node->ctx->crypto->decrypt != NOTMUCH_DECRYPT_FALSE)) || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) { GMimeContentType *content_type = g_mime_object_get_c
[PATCH v2 09/21] lib: convert notmuch decryption policy to an enum
Future patches in this series will introduce new policies; this merely readies the way for them. We also convert --try-decrypt to a keyword argument instead of a boolean. --- lib/index.cc | 2 +- lib/indexopts.c | 21 +++-- lib/notmuch.h | 14 -- mime-node.c | 4 ++-- notmuch-client.h | 9 + notmuch-reply.c | 6 +- notmuch-show.c| 10 +++--- notmuch.c | 13 - test/T357-index-decryption.sh | 12 ++-- util/crypto.h | 2 +- 10 files changed, 58 insertions(+), 35 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index ff14e408..905366ae 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -525,7 +525,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, notmuch_database_t * notmuch = NULL; GMimeObject *clear = NULL; -if (!indexopts || !notmuch_indexopts_get_decrypt_policy (indexopts)) +if (!indexopts || (notmuch_indexopts_get_decrypt_policy (indexopts) == NOTMUCH_DECRYPT_FALSE)) return; notmuch = _notmuch_message_database (message); diff --git a/lib/indexopts.c b/lib/indexopts.c index 0f65b97c..78f53391 100644 --- a/lib/indexopts.c +++ b/lib/indexopts.c @@ -26,25 +26,26 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db) notmuch_indexopts_t *ret = talloc_zero (db, notmuch_indexopts_t); if (!ret) return ret; +ret->crypto.decrypt = NOTMUCH_DECRYPT_FALSE; -char * decrypt; -notmuch_status_t err = notmuch_database_get_config (db, "index.decrypt", &decrypt); +char * decrypt_policy; +notmuch_status_t err = notmuch_database_get_config (db, "index.decrypt", &decrypt_policy); if (err) return ret; -if (decrypt && - ((!(strcasecmp(decrypt, "true"))) || -(!(strcasecmp(decrypt, "yes"))) || -(!(strcasecmp(decrypt, "1") - notmuch_indexopts_set_decrypt_policy (ret, true); +if (decrypt_policy && + ((!(strcasecmp(decrypt_policy, "true"))) || +(!(strcasecmp(decrypt_policy, "yes"))) || +(!(strcasecmp(decrypt_policy, "1") + notmuch_indexopts_set_decrypt_policy (ret, NOTMUCH_DECRYPT_TRUE); -free (decrypt); +free (decrypt_policy); return ret; } notmuch_status_t notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, - notmuch_bool_t decrypt_policy) + notmuch_decryption_policy_t decrypt_policy) { if (!indexopts) return NOTMUCH_STATUS_NULL_POINTER; @@ -52,7 +53,7 @@ notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, return NOTMUCH_STATUS_SUCCESS; } -notmuch_bool_t +notmuch_decryption_policy_t notmuch_indexopts_get_decrypt_policy (const notmuch_indexopts_t *indexopts) { if (!indexopts) diff --git a/lib/notmuch.h b/lib/notmuch.h index ef463090..47633496 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -2233,6 +2233,16 @@ notmuch_config_list_destroy (notmuch_config_list_t *config_list); notmuch_indexopts_t * notmuch_database_get_default_indexopts (notmuch_database_t *db); +/** + * Stating a policy about how to decrypt messages. + * + * See index.decrypt in notmuch-config(1) for more details. + */ +typedef enum { +NOTMUCH_DECRYPT_FALSE, +NOTMUCH_DECRYPT_TRUE, +} notmuch_decryption_policy_t; + /** * Specify whether to decrypt encrypted parts while indexing. * @@ -2245,7 +2255,7 @@ notmuch_database_get_default_indexopts (notmuch_database_t *db); */ notmuch_status_t notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, - notmuch_bool_t decrypt_policy); + notmuch_decryption_policy_t decrypt_policy); /** * Return whether to decrypt encrypted parts while indexing. @@ -2253,7 +2263,7 @@ notmuch_indexopts_set_decrypt_policy (notmuch_indexopts_t *indexopts, * * @since libnotmuch 5.1 (notmuch 0.26) */ -notmuch_bool_t +notmuch_decryption_policy_t notmuch_indexopts_get_decrypt_policy (const notmuch_indexopts_t *indexopts); /** diff --git a/mime-node.c b/mime-node.c index daaae9f8..c4de708b 100644 --- a/mime-node.c +++ b/mime-node.c @@ -270,7 +270,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part) } #if (GMIME_MAJOR_VERSION < 3) -if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt) +if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && (node->ctx->crypto->decrypt == NOTMUCH_DECRYPT_TRUE)) || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) { GMimeContentType *content_type = g_mime_object_get_content_type (part); const char *protocol = g_mime_content_type_get_parameter (content_type, "protocol"); @@ -286,7 +286,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part) #endif /* Handle P
[PATCH v2 14/21] cli/new, insert, reindex: update documentation for --decrypt=auto
we also include --decrypt=auto in the tab completion. --- completion/notmuch-completion.bash | 6 +++--- doc/man1/notmuch-insert.rst| 16 ++-- doc/man1/notmuch-new.rst | 10 +++--- doc/man1/notmuch-reindex.rst | 23 ++- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index f94dbeed..272131e6 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -288,7 +288,7 @@ _notmuch_insert() return ;; --decrypt) - COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) ) return ;; esac @@ -320,7 +320,7 @@ _notmuch_new() $split && case "${prev}" in --decrypt) - COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) ) return ;; esac @@ -442,7 +442,7 @@ _notmuch_reindex() $split && case "${prev}" in --decrypt) - COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true false auto" -- "${cur}" ) ) return ;; esac diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst index eb9ff11b..b22be863 100644 --- a/doc/man1/notmuch-insert.rst +++ b/doc/man1/notmuch-insert.rst @@ -51,14 +51,18 @@ Supported options for **insert** include ``--no-hooks`` Prevent hooks from being run. -``--decrypt=(true|false)`` +``--decrypt=(true|auto|false)`` -If true and the message is encrypted, try to decrypt the -message while indexing. If decryption is successful, index +If ``true`` and the message is encrypted, try to decrypt the +message while indexing. 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. Either way, the 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 +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 notmuch message index is adequately protected. DO NOT USE ``--decrypt=true`` without considering the security of your index. diff --git a/doc/man1/notmuch-new.rst b/doc/man1/notmuch-new.rst index 1df86f06..71df31d7 100644 --- a/doc/man1/notmuch-new.rst +++ b/doc/man1/notmuch-new.rst @@ -43,11 +43,15 @@ Supported options for **new** include ``--quiet`` Do not print progress or results. -``--decrypt=(true|false)`` +``--decrypt=(true|auto|false)`` -If true, when encountering an encrypted message, try to +If ``true``, when encountering an encrypted message, try to decrypt it while indexing. If decryption is successful, index -the cleartext itself. Be aware that the index is likely +the cleartext itself. 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. + +Be aware that the 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 ``--decrypt=true`` without diff --git a/doc/man1/notmuch-reindex.rst b/doc/man1/notmuch-reindex.rst index 782b0d7b..d87e9d85 100644 --- a/doc/man1/notmuch-reindex.rst +++ b/doc/man1/notmuch-reindex.rst @@ -21,15 +21,20 @@ messages using the supplied options. Supported options for **reindex** include -``--decrypt=(true|false)`` - -If true, when encountering an encrypted message, try to -decrypt it while reindexing. If decryption is successful, -index the cleartext itself. Be aware that the 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 ``--decrypt=true`` without -considering the security of your index. +``--decrypt=(true|auto|false)`` + +If ``true``, when encountering an encrypted message, try to +decrypt it while reindexing. 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 decrypti
[PATCH v2 15/21] crypto: record whether an actual decryption attempt happened
In our consolidation of _notmuch_crypto_decrypt, the callers lost track a little bit of whether any actual decryption was attempted. Now that we have the more-subtle "auto" policy, it's possible that _notmuch_crypto_decrypt could be called without having any actual decryption take place. This change lets the callers be a little bit smarter about whether or not any decryption was actually attempted. --- lib/index.cc | 17 - mime-node.c | 4 ++-- util/crypto.c | 7 ++- util/crypto.h | 3 ++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index af999bd3..3914012a 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -548,12 +548,19 @@ _index_encrypted_mime_part (notmuch_message_t *message, } } #endif -clear = _notmuch_crypto_decrypt (notmuch_indexopts_get_decrypt_policy (indexopts), +bool attempted = false; +clear = _notmuch_crypto_decrypt (&attempted, notmuch_indexopts_get_decrypt_policy (indexopts), message, crypto_ctx, encrypted_data, NULL, &err); -if (err) { - _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", - err->domain, err->code, err->message); - g_error_free(err); +if (!attempted) + return; +if (err || !clear) { + if (err) { + _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", + err->domain, err->code, err->message); + g_error_free(err); + } else { + _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (unknown error)\n"); + } /* Indicate that we failed to decrypt during indexing */ status = notmuch_message_add_property (message, "index.decryption", "failure"); if (status) diff --git a/mime-node.c b/mime-node.c index 49d668fe..11df082b 100644 --- a/mime-node.c +++ b/mime-node.c @@ -204,8 +204,8 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, if (parent->envelope_file) break; - node->decrypt_attempted = true; - node->decrypted_child = _notmuch_crypto_decrypt (node->ctx->crypto->decrypt, + node->decrypted_child = _notmuch_crypto_decrypt (&node->decrypt_attempted, + node->ctx->crypto->decrypt, parent ? parent->envelope_file : NULL, cryptoctx, encrypteddata, &decrypt_result, &err); } diff --git a/util/crypto.c b/util/crypto.c index bb587571..338f1d5d 100644 --- a/util/crypto.c +++ b/util/crypto.c @@ -140,7 +140,8 @@ void _notmuch_crypto_cleanup (unused(_notmuch_crypto_t *crypto)) #endif GMimeObject * -_notmuch_crypto_decrypt (notmuch_decryption_policy_t decrypt, +_notmuch_crypto_decrypt (bool *attempted, +notmuch_decryption_policy_t decrypt, notmuch_message_t *message, g_mime_3_unused(GMimeCryptoContext* crypto_ctx), GMimeMultipartEncrypted *part, @@ -162,6 +163,8 @@ _notmuch_crypto_decrypt (notmuch_decryption_policy_t decrypt, g_error_free (*err); *err = NULL; } + if (attempted) + *attempted = true; #if (GMIME_MAJOR_VERSION < 3) ret = g_mime_multipart_encrypted_decrypt_session (part, crypto_ctx, @@ -191,6 +194,8 @@ _notmuch_crypto_decrypt (notmuch_decryption_policy_t decrypt, if (decrypt == NOTMUCH_DECRYPT_AUTO) return ret; +if (attempted) + *attempted = true; #if (GMIME_MAJOR_VERSION < 3) ret = g_mime_multipart_encrypted_decrypt(part, crypto_ctx, decrypt_result, err); diff --git a/util/crypto.h b/util/crypto.h index dc95b4ca..c384601c 100644 --- a/util/crypto.h +++ b/util/crypto.h @@ -16,7 +16,8 @@ typedef struct _notmuch_crypto { } _notmuch_crypto_t; GMimeObject * -_notmuch_crypto_decrypt (notmuch_decryption_policy_t decrypt, +_notmuch_crypto_decrypt (bool *attempted, +notmuch_decryption_policy_t decrypt, notmuch_message_t *message, GMimeCryptoContext* crypto_ctx, GMimeMultipartEncrypted *part, -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
session keys, version 2
This is the second revision of the session keys series. the earlier version of this series can be found following id:20171025065203.24403-1-...@fifthhorseman.net. This version addresses the ideas and critiques raised on list about the first version. In particular: * ./configure now detects and sets a HAVE_GMIME_SESSION_KEYS #define to consolidate the version number checking in one place. * the library contains a built_with("session_key") marker. * the command line syntax for new, insert, and reindex is now --decrypt=, instead of --try-decrypt= * the configuration option is now index.decrypt, instead of index.try_decrypt. * in alignment with the shift to a "decryption policy" vocabulary, i've changed notmuch_indexopts_{set,get}_try_decrypt to notmuch_indexopts_{set,get}_decrypt_policy. I think this is OK because the API has not been released yet. The decryption policies remain the same: ++---+--+-+--+ || false | auto | nostash | true | ++===+==+=+==+ | Index cleartext using | | X |X| X | | stashed session keys | | | | | ++---+--+-+--+ | Index cleartext| | |X| X | | using secret keys | | | | | ++---+--+-+--+ | Stash session keys | | | | X | ++---+--+-+--+ | Delete stashed session | X | | | | | keys on reindex| | | | | ++---+--+-+--+ I believe this addresses all the major concerns raised about the earlier draft of this series, and i know that there are at least a few people other than myself currently using this series. Please let me know if you have any other feedback about this new revision! I'd love to try to land this in 0.26. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 13/21] cli/show, reply: document use of stashed session keys in notmuch-properties
The stashed session keys are stored internally as notmuch properties. So a user or developer who is reading about those properties might want to understand how they fit into the bigger picture. Note here that decrypting with a stored session key no longer needs -decrypt for "notmuch show" and "notmuch reply". --- doc/man7/notmuch-properties.rst | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/man7/notmuch-properties.rst b/doc/man7/notmuch-properties.rst index f27dd607..1bb7b1ca 100644 --- a/doc/man7/notmuch-properties.rst +++ b/doc/man7/notmuch-properties.rst @@ -77,9 +77,12 @@ of its normal activity. **session-key** When **notmuch-show(1)** or **nomtuch-reply** encounters a message -with an encrypted part and ``--decrypt`` is set, if notmuch finds a -``session-key`` property associated with the message, it will try -that stashed session key for decryption. +with an encrypted part, if notmuch finds a ``session-key`` +property associated with the message, it will try that stashed +session key for decryption. + +If you do not want to use any stashed session keys that might be +present, you should pass those programs ``--decrypt=false``. Using a stashed session key with "notmuch show" will speed up rendering of long encrypted threads. It also allows the user to -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 19/21] 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. --- completion/notmuch-completion.bash | 6 +++--- doc/man1/notmuch-config.rst| 17 - doc/man1/notmuch-insert.rst| 16 ++-- doc/man1/notmuch-new.rst | 7 --- doc/man1/notmuch-reindex.rst | 16 ++-- lib/indexopts.c| 2 ++ lib/notmuch.h | 1 + notmuch-reply.c| 2 +- notmuch-show.c | 3 ++- notmuch.c | 1 + test/T357-index-decryption.sh | 23 +++ util/crypto.c | 4 ++-- 12 files changed, 71 insertions(+), 27 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 272131e6..948c153b 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -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 diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index dabf269f..773fd9da 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -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``. diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst index 214f261b..1a3dfe98 100644 --- a/doc/man1/notmuch-insert.rst +++ b/doc/man1/notmuch-insert.rst @@ -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 +
[PATCH v2 18/21] crypto: actually stash session keys when decrypt=true
If you're going to store the cleartext index of an encrypted message, in most situations you might just as well store the session key. Doing this storage has efficiency and recoverability advantages. Combined with a schedule of regular OpenPGP subkey rotation and destruction, this can also offer security benefits, like "deletable e-mail", which is the store-and-forward analog to "forward secrecy". But wait, i hear you saying, i have a special need to store cleartext indexes but it's really bad for me to store session keys! Maybe (let's imagine) i get lots of e-mails with incriminating photos attached, and i want to be able to search for them by the text in the e-mail, but i don't want someone with access to the index to be actually able to see the photos themselves. Fret not, the next patch in this series will support your wacky uncommon use case. --- doc/man1/notmuch-config.rst | 10 ++ doc/man1/notmuch-insert.rst | 13 +++-- doc/man1/notmuch-new.rst| 21 +++-- doc/man1/notmuch-reindex.rst| 10 +- doc/man7/notmuch-properties.rst | 4 lib/index.cc| 18 +- test/T357-index-decryption.sh | 18 +- util/crypto.c | 16 +++- 8 files changed, 82 insertions(+), 28 deletions(-) diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index 1a9e08a3..dabf269f 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -143,10 +143,12 @@ The available configuration items are described below. **[STORED IN DATABASE]** 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. If ``auto``, it will try to index the -cleartext if a stashed session key is already known for the message, -but will not try to access your secret keys. Use ``false`` to -avoid decrypting even when a session key is already known. +index the cleartext, stashing a copy of any discovered session +keys for the message. If ``auto``, it will try to index the +cleartext if a stashed session key is already known for the message +(e.g. from a previous copy), but will not try to access your +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 diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst index b22be863..214f261b 100644 --- a/doc/man1/notmuch-insert.rst +++ b/doc/man1/notmuch-insert.rst @@ -54,12 +54,13 @@ Supported options for **insert** include ``--decrypt=(true|auto|false)`` If ``true`` and the message is encrypted, try to decrypt the -message while indexing. 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. Either way, the message is always -stored to disk in its original form (ciphertext). +message while indexing, storing 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. Either way, the +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 diff --git a/doc/man1/notmuch-new.rst b/doc/man1/notmuch-new.rst index 71df31d7..27676a19 100644 --- a/doc/man1/notmuch-new.rst +++ b/doc/man1/notmuch-new.rst @@ -46,16 +46,17 @@ Supported options for **new** include ``--decrypt=(true|auto|false)`` If ``true``, when encountering an encrypted message, try to -decrypt it while indexing. If decryption is successful, index -the cleartext itself. 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. - -Be aware that the 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 ``--decrypt=true`` without -considering the security of your index. +decrypt it while indexing, and store 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 +
[PATCH v2 07/21] indexing: Change from try_decrypt to decrypt
the command-line interface for indexing (reindex, new, insert) used --try-decrypt; and the configuration records used index.try_decrypt. But by comparison with "show" and "reply", there doesn't seem to be any reason for the "try" prefix. This changeset adjusts the command-line interface and the configuration interface. For the moment, i've left indexopts_{set,get}_try_decrypt alone. The subsequent changeset will address those. --- NEWS | 4 ++-- completion/notmuch-completion.bash | 12 ++-- doc/man1/notmuch-config.rst| 4 ++-- doc/man1/notmuch-insert.rst| 6 +++--- doc/man1/notmuch-new.rst | 6 +++--- doc/man1/notmuch-reindex.rst | 6 +++--- doc/man7/notmuch-properties.rst| 2 +- lib/indexopts.c| 14 +++--- notmuch-config.c | 2 +- notmuch.c | 4 ++-- test/T357-index-decryption.sh | 18 +- test/test-lib.sh | 2 +- 12 files changed, 40 insertions(+), 40 deletions(-) diff --git a/NEWS b/NEWS index 412c678d..0465b9e8 100644 --- a/NEWS +++ b/NEWS @@ -19,9 +19,9 @@ Indexing cleartext of encrypted e-mails It's now possible to include the cleartext of encrypted e-mails in the notmuch index. This makes it possible to search your encrypted e-mails with the same ease as searching cleartext. This can be done - on a per-message basis with the --try-decrypt argument to indexing + on a per-message basis with the --decrypt argument to indexing commands (new, insert, reindex), or by default by running "notmuch - config set index.try_decrypt true". + config set index.decrypt true". Note that the contents of the index are sufficient to roughly reconstruct the cleartext of the message itself, so please ensure diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 7aae4297..e462a82a 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -287,7 +287,7 @@ _notmuch_insert() sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) ) return ;; - --try-decrypt) + --decrypt) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; @@ -296,7 +296,7 @@ _notmuch_insert() ! $split && case "${cur}" in --*) - local options="--create-folder --folder= --keep --no-hooks --try-decrypt= ${_notmuch_shared_options}" + local options="--create-folder --folder= --keep --no-hooks --decrypt= ${_notmuch_shared_options}" compopt -o nospace COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) return @@ -319,7 +319,7 @@ _notmuch_new() $split && case "${prev}" in - --try-decrypt) + --decrypt) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; @@ -328,7 +328,7 @@ _notmuch_new() ! $split && case "${cur}" in -*) - local options="--no-hooks --try-decrypt= --quiet ${_notmuch_shared_options}" + local options="--no-hooks --decrypt= --quiet ${_notmuch_shared_options}" compopt -o nospace COMPREPLY=( $(compgen -W "${options}" -- ${cur}) ) ;; @@ -437,7 +437,7 @@ _notmuch_reindex() $split && case "${prev}" in - --try-decrypt) + --decrypt) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; @@ -446,7 +446,7 @@ _notmuch_reindex() ! $split && case "${cur}" in -*) - local options="--try-decrypt= ${_notmuch_shared_options}" + local options="--decrypt= ${_notmuch_shared_options}" compopt -o nospace COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ;; diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst index 6961737f..ea3d9754 100644 --- a/doc/man1/notmuch-config.rst +++ b/doc/man1/notmuch-config.rst @@ -138,7 +138,7 @@ The available configuration items are described below. Default: ``gpg``. -**index.try_decrypt** +**index.decrypt** **[STORED IN DATABASE]** When indexing an encrypted e-mail message, if this variable is @@ -146,7 +146,7 @@ The available configuration items are described below. the cleartext. Be aware that the 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.try_decrypt=true`` without considering the +DO NOT USE ``index.decrypt=true`` without considering the security of your index. Default: ``false``. diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst index c500b251..eb9ff11b 100644 --- a/doc/man1/notmuch-insert.rst +++ b/doc/man1/notmuch-insert.rs
[PATCH v2 04/21] crypto: use stashed session-key properties for decryption, if available
When doing any decryption, if the notmuch database knows of any session keys associated with the message in question, try them before defaulting to using default symmetric crypto. This changeset does the primary work in _notmuch_crypto_decrypt, which grows some new parameters to handle it. The primary advantage this patch offers is a significant speedup when rendering large encrypted threads ("notmuch show") if session keys happen to be cached. Additionally, it permits message composition without access to asymmetric secret keys ("notmuch reply"); and it permits recovering a cleartext index when reindexing after a "notmuch restore" for those messages that already have a session key stored. Note that we may try multiple decryptions here (e.g. if there are multiple session keys in the database), but we will ignore and throw away all the GMime errors except for those that come from last decryption attempt. Since we don't necessarily know at the time of the decryption that this *is* the last decryption attempt, we'll ask for the errors each time anyway. This does nothing if no session keys are stashed in the database, which is fine. Actually stashing session keys in the database will come as a subsequent patch. --- doc/man7/notmuch-properties.rst | 31 +++ lib/index.cc| 2 +- mime-node.c | 13 ++--- util/crypto.c | 39 ++- util/crypto.h | 3 ++- 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/doc/man7/notmuch-properties.rst b/doc/man7/notmuch-properties.rst index 68121359..49602b73 100644 --- a/doc/man7/notmuch-properties.rst +++ b/doc/man7/notmuch-properties.rst @@ -74,6 +74,35 @@ of its normal activity. **notmuch-config(1)**), then this property will not be set on that message. +**session-key** + +When **notmuch-show(1)** or **nomtuch-reply** encounters a message +with an encrypted part and ``--decrypt`` is set, if notmuch finds a +``session-key`` property associated with the message, it will try +that stashed session key for decryption. + +Using a stashed session key with "notmuch show" will speed up +rendering of long encrypted threads. It also allows the user to +destroy the secret part of any expired encryption-capable subkey +while still being able to read any retained messages for which +they have stashed the session key. This enables truly deletable +e-mail, since (once the session key and asymmetric subkey are both +destroyed) there are no keys left that can be used to decrypt any +copy of the original message previously stored by an adversary. + +However, access to the stashed session key for an encrypted message +permits full byte-for-byte reconstruction of the cleartext +message. This includes attachments, cryptographic signatures, and +other material that cannot be reconstructed from the index alone. + +The session key should be in the ASCII text form produced by +GnuPG. For OpenPGP, that consists of a decimal representation of +the hash algorithm used (identified by number from RFC 4880, +e.g. 9 means AES-256) followed by a colon, followed by a +hexidecimal representation of the algorithm-specific key. For +example, an AES-128 key might be stashed in a notmuch property as: +``session-key=7:14B16AF65536C28AF209828DFE34C9E0``. + SEE ALSO @@ -83,5 +112,7 @@ SEE ALSO **notmuch-insert(1)**, **notmuch-new(1)**, **notmuch-reindex(1)**, +**notmuch-reply(1)**, **notmuch-restore(1)**, +**notmuch-show(1)**, ***notmuch-search-terms(7)** diff --git a/lib/index.cc b/lib/index.cc index 19d03456..6eb60f30 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -548,7 +548,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, } } #endif -clear = _notmuch_crypto_decrypt (crypto_ctx, encrypted_data, NULL, &err); +clear = _notmuch_crypto_decrypt (message, crypto_ctx, encrypted_data, NULL, &err); if (err) { _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", err->domain, err->code, err->message); diff --git a/mime-node.c b/mime-node.c index ae3ebef6..daaae9f8 100644 --- a/mime-node.c +++ b/mime-node.c @@ -198,9 +198,16 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, GMimeDecryptResult *decrypt_result = NULL; GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part); -node->decrypt_attempted = true; -if (! node->decrypted_child) - node->decrypted_child = _notmuch_crypto_decrypt (cryptoctx, encrypteddata, &decrypt_result, &err); +if (! node->decrypted_child) { + mime_node_t *parent; + for (parent = node; parent; parent = parent->parent) + if (parent->envelope_file) + break; + + node->decrypt_attempted = true; + n
[PATCH v2 05/21] test/corpora: add an encrypted message for index decryption tests
--- test/corpora/README | 5 + test/corpora/crypto/simple-encrypted | 36 2 files changed, 41 insertions(+) create mode 100644 test/corpora/crypto/simple-encrypted diff --git a/test/corpora/README b/test/corpora/README index c9a35fed..05ea386d 100644 --- a/test/corpora/README +++ b/test/corpora/README @@ -12,3 +12,8 @@ broken html The html corpus contains html parts + +crypto + The crypto corpus contains encrypted messages for testing. + It should probably also contain signed messages in the future. + Please add them! diff --git a/test/corpora/crypto/simple-encrypted b/test/corpora/crypto/simple-encrypted new file mode 100644 index ..6869972d --- /dev/null +++ b/test/corpora/crypto/simple-encrypted @@ -0,0 +1,36 @@ +From: Daniel Kahn Gillmor +To: d...@fifthhorseman.net +Subject: encrypted message +Date: Mon, 22 Dec 2016 08:34:56 -0400 +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/encrypted; boundary="=-=-="; + protocol="application/pgp-encrypted" + +--=-=-= +Content-Type: application/pgp-encrypted + +Version: 1 + +--=-=-= +Content-Type: application/octet-stream + +-BEGIN PGP MESSAGE- + +hQIMAzt6p/AU5ptaAQ/+IDRx5dZWKjUz9qITP76w8OvtmTV9p871UoGWil1DSd3J +dHgf56rXDWS73dzJ5EigevxLVMD3Xv8QEJBgMWb6yC+uR8ZdJ8h7hlE2lYyEg3Ch +smqzcaYp2nKWw9JZQqubsMaeIgVu0exb4YE8g/qlUOL2mD64dXhnkJ68GGMmiEPJ ++d0H7fTMwstbxvKPKDmFJUztH43V2NSfxpeQUTi4iWmQtUGw6THYjjAWNFy7jVEE +ozloT9W3ER5cRaXyKE4GWMBlUAOB0YwwsVnBU2JGUtTBzNHxQAbeoKrG6myrzmnC +LhUNag0gMuNEbGR78XfWKpCbccEC1VLf9uUXze6yeuRXDuhfsvilKOH9MpaR9n+G +JuYVAAobDc5wGOt5VGMka50ToaALrNt3FrWqni/0jqwqshEVKM3Kqzq6cSjh1TPf +pfxE9aUDdvf+Nn16ZBGgyLox2NV4GkSQYq2ySzAk3XwLU80F0nCmtOV3EH+OMrv6 +sZI/Svwzaqzrs/w17cvpf0czXjE/N9V1MHdNtIkfb707WkO0l9/wtYvlrg/KyrU2 +FH5aecEO9VpMumgzBqP1MrrnzVlSM3kgRLIu06oshQYD+jjFn2YzvkwZ+pWoAxsQ +ninQxoF8Ck2D7s8uGzx+HSQQpRVBM5AGfVdEkmzW/sZrlz63ZGUFh0FYqLl30rfS +cQGqSoZz0ugTSxnTlg0nuzFmG7ylC1cx3dlSrnfv+l1azwLAr58ptoYZ0mO+D+Fy +bePpCGoFAPKi0cZ/4eFlLKL7uYPmGeEo5Ku2wXU/SXtPfl4vRxzvPXTJTvD06vIx +Dh1P0ChAJtxUjGGY6xkCHMY0 +=frmz +-END PGP MESSAGE- +--=-=-=-- -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 21/21] python: add decrypt_policy argument to Database.index_file()
We adopt a pythonic idiom here with an optional argument, rather than exposing the user to the C indexopts object directly. --- bindings/python/notmuch/database.py | 46 +++-- bindings/python/notmuch/globals.py | 5 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 1279804a..ef370839 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -28,6 +28,7 @@ from .globals import ( _str, NotmuchDatabaseP, NotmuchDirectoryP, +NotmuchIndexoptsP, NotmuchMessageP, NotmuchTagsP, ) @@ -72,6 +73,9 @@ class Database(object): MODE = Enum(['READ_ONLY', 'READ_WRITE']) """Constants: Mode in which to open the database""" +DECRYPTION_POLICY = Enum(['FALSE', 'TRUE', 'AUTO', 'NOSTASH']) +"""Constants: policies for decrypting messages during indexing""" + """notmuch_database_get_directory""" _get_directory = nmlib.notmuch_database_get_directory _get_directory.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchDirectoryP)] @@ -400,13 +404,25 @@ class Database(object): # return the Directory, init it with the absolute path return Directory(abs_dirpath, dir_p, self) +_get_default_indexopts = nmlib.notmuch_database_get_default_indexopts +_get_default_indexopts.argtypes = [NotmuchDatabaseP] +_get_default_indexopts.restype = NotmuchIndexoptsP + +_indexopts_set_decrypt_policy = nmlib.notmuch_indexopts_set_decrypt_policy +_indexopts_set_decrypt_policy.argtypes = [NotmuchIndexoptsP, c_uint] +_indexopts_set_decrypt_policy.restype = None + +_indexopts_destroy = nmlib.notmuch_indexopts_destroy +_indexopts_destroy.argtypes = [NotmuchIndexoptsP] +_indexopts_destroy.restype = None + _index_file = nmlib.notmuch_database_index_file _index_file.argtypes = [NotmuchDatabaseP, c_char_p, c_void_p, POINTER(NotmuchMessageP)] _index_file.restype = c_uint -def index_file(self, filename, sync_maildir_flags=False): +def index_file(self, filename, sync_maildir_flags=False, decrypt_policy=None): """Adds a new message to the database :param filename: should be a path relative to the path of the @@ -427,6 +443,23 @@ class Database(object): API. You might want to look into the underlying method :meth:`Message.maildir_flags_to_tags`. +:param decrypt_policy: If the message contains any encrypted +parts, and decrypt_policy is set to +:attr:`DECRYPTION_POLICY`.TRUE, notmuch will try to +decrypt the message and index the cleartext, stashing any +discovered session keys. If it is set to +:attr:`DECRYPTION_POLICY`.FALSE, it will never try to +decrypt during indexing. If it is set to +:attr:`DECRYPTION_POLICY`.AUTO, then it will try to use +any stashed session keys it knows about, but will not try +to access the user's secret keys. +:attr:`DECRYPTION_POLICY`.NOSTASH behaves the same as +:attr:`DECRYPTION_POLICY`.TRUE except that no session keys +are stashed in the database. If decrypt_policy is set to +None (the default), then the database itself will decide +whether to decrypt, based on the `index.decrypt` +configuration setting (see notmuch-config(1)). + :returns: On success, we return 1) a :class:`Message` object that can be used for things @@ -454,10 +487,19 @@ class Database(object): :attr:`STATUS`.READ_ONLY_DATABASE Database was opened in read-only mode so no message can be added. + """ self._assert_db_is_initialized() msg_p = NotmuchMessageP() -status = self._index_file(self._db, _str(filename), c_void_p(None), byref(msg_p)) +indexopts = c_void_p(None) +if decrypt_policy is not None: +indexopts = self._get_default_indexopts(self._db) +self._indexopts_set_decrypt_policy(indexopts, decrypt_policy) + +status = self._index_file(self._db, _str(filename), indexopts, byref(msg_p)) + +if indexopts: +self._indexopts_destroy(indexopts) if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: raise NotmuchError(status) diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index b1eec2cf..71426c84 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -88,3 +88,8 @@ NotmuchDirectoryP = POINTER(NotmuchDirectoryS) class NotmuchFilenamesS(Structure): pass NotmuchFilenamesP = POINTER(NotmuchFilenamesS) + + +class NotmuchIndexoptsS(Structure): +pass +NotmuchIndexoptsP = PO
[PATCH v2 06/21] crypto: Test restore of cleartext index from stashed session keys
If you've got a notmuch dump that includes stashed session keys for every decrypted message, and you've got your message archive, you should be able to get back to the same index that you had before. Here we add a simple test that give some flavor of how that works. --- test/T357-index-decryption.sh | 31 +++ 1 file changed, 31 insertions(+) diff --git a/test/T357-index-decryption.sh b/test/T357-index-decryption.sh index 22e716c6..11ea2074 100755 --- a/test/T357-index-decryption.sh +++ b/test/T357-index-decryption.sh @@ -156,6 +156,37 @@ test_expect_equal \ "$output" \ "$expected" +add_email_corpus crypto + +test_begin_subtest "indexing message fails when secret key not available" +notmuch reindex --try-decrypt id:simple-encryp...@crypto.notmuchmail.org +output=$(notmuch dump ) +expected='#notmuch-dump batch-tag:3 config,properties,tags ++encrypted +inbox +unread -- id:simple-encryp...@crypto.notmuchmail.org +#= simple-encryp...@crypto.notmuchmail.org index.decryption=failure' +test_expect_equal \ +"$output" \ +"$expected" + +test_begin_subtest "cannot find cleartext index" +output=$(notmuch search sekrit) +expected='' +test_expect_equal \ +"$output" \ +"$expected" + +test_begin_subtest "cleartext index recovery on reindexing with stashed session keys" +notmuch restore
[PATCH v2 17/21] cli/reindex: destroy stashed session keys when --decrypt=false
There are some situations where the user wants to get rid of the cleartext index of a message. For example, if they're indexing encrypted messages normally, but suddenly they run across a message that they really don't want any trace of in their index. In that case, the natural thing to do is: notmuch reindex --decrypt=false id:whate...@example.biz But of course, clearing the cleartext index without clearing the stashed session key is just silly. So we do the expected thing and also destroy any stashed session keys while we're destroying the index of the cleartext. Note that stashed session keys are stored in the xapian database, but xapian does not currently allow safe deletion (see https://trac.xapian.org/ticket/742). As a workaround, after removing session keys and cleartext material from the database, the user probably should do something like "notmuch compact" to try to purge whatever recoverable data is left in the xapian freelist. This problem really needs to be addressed within xapian, though, if we want it fixed right. --- doc/man1/notmuch-reindex.rst | 3 +++ lib/message.cc| 5 + test/T357-index-decryption.sh | 17 + 3 files changed, 25 insertions(+) diff --git a/doc/man1/notmuch-reindex.rst b/doc/man1/notmuch-reindex.rst index d87e9d85..e8174f39 100644 --- a/doc/man1/notmuch-reindex.rst +++ b/doc/man1/notmuch-reindex.rst @@ -30,6 +30,9 @@ Supported options for **reindex** include the user's secret keys. If decryption is successful, index the cleartext itself. +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 notmuch message index is adequately protected. DO NOT USE diff --git a/lib/message.cc b/lib/message.cc index 12743460..d5db89b6 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -2002,6 +2002,11 @@ notmuch_message_reindex (notmuch_message_t *message, ret = notmuch_message_remove_all_properties_with_prefix (message, "index."); if (ret) goto DONE; /* XXX TODO: distinguish from other error returns above? */ +if (indexopts && notmuch_indexopts_get_decrypt_policy (indexopts) == NOTMUCH_DECRYPT_FALSE) { + ret = notmuch_message_remove_all_properties (message, "session-key"); + if (ret) + goto DONE; +} /* re-add the filenames with the associated indexopts */ for (; notmuch_filenames_valid (orig_filenames); diff --git a/test/T357-index-decryption.sh b/test/T357-index-decryption.sh index b2717a7a..64317c64 100755 --- a/test/T357-index-decryption.sh +++ b/test/T357-index-decryption.sh @@ -218,6 +218,23 @@ test_expect_equal \ "$output" \ "$expected" +test_begin_subtest "purging stashed session keys should lose access to the cleartext" +notmuch reindex --decrypt=false id:simple-encryp...@crypto.notmuchmail.org +output=$(notmuch search sekrit) +expected='' +test_expect_equal \ +"$output" \ +"$expected" + +test_begin_subtest "and cleartext should be unrecoverable now that there are no stashed session keys" +notmuch dump +notmuch reindex --decrypt=true id:simple-encryp...@crypto.notmuchmail.org +output=$(notmuch search sekrit) +expected='' +test_expect_equal \ +"$output" \ +"$expected" + # TODO: test removal of a message from the message store between # indexing and reindexing. -- 2.15.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch