[gmime-devel] [PATCH 2/6] Default to using "gpg"

2016-12-01 Thread Daniel Kahn Gillmor
There is no reason to require a full path to the gpg executable.  We
should be able to leave it as the default.
---
 gmime/gmime-gpg-context.c | 10 +-
 tests/test-pgp.c  |  4 ++--
 tests/test-pgpmime.c  |  4 ++--
 tests/test-smime.c|  2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/gmime/gmime-gpg-context.c b/gmime/gmime-gpg-context.c
index 0a05ed2..2ca280a 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -763,7 +763,7 @@ gpg_ctx_op_start (struct _GpgCtx *gpg)
}

/* run gpg */
-   execvp (gpg->ctx->path, argv);
+   execvp (gpg->ctx->path ? gpg->ctx->path : "gpg", argv);
_exit (255);
} else if (gpg->pid < 0) {
g_strfreev (strv);
@@ -2190,7 +2190,7 @@ gpg_export_keys (GMimeCryptoContext *context, GPtrArray 
*keys, GMimeStream *ostr
 /**
  * g_mime_gpg_context_new:
  * @request_passwd: a #GMimePasswordRequestFunc
- * @path: path to gpg binary
+ * @path: path to gpg binary, or NULL for the default
  *
  * Creates a new gpg crypto context object.
  *
@@ -2203,10 +2203,10 @@ g_mime_gpg_context_new (GMimePasswordRequestFunc 
request_passwd, const char *pat
GMimeCryptoContext *crypto;
GMimeGpgContext *ctx;

-   g_return_val_if_fail (path != NULL, NULL);
-   
ctx = g_object_newv (GMIME_TYPE_GPG_CONTEXT, 0, NULL);
-   ctx->path = g_strdup (path);
+   if (path) {
+   ctx->path = g_strdup (path);
+   }

crypto = (GMimeCryptoContext *) ctx;
crypto->request_passwd = request_passwd;
diff --git a/tests/test-pgp.c b/tests/test-pgp.c
index bfdae74..3e7a2a4 100644
--- a/tests/test-pgp.c
+++ b/tests/test-pgp.c
@@ -289,7 +289,7 @@ int main (int argc, char **argv)
if (system ("/bin/mkdir ./tmp") != 0)
return EXIT_FAILURE;
setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("/usr/bin/gpg --list-keys > /dev/null 2>&1") != 0)
+   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
@@ -304,7 +304,7 @@ int main (int argc, char **argv)

testsuite_start ("GnuPG crypto context");

-   ctx = g_mime_gpg_context_new (request_passwd, "/usr/bin/gpg");
+   ctx = g_mime_gpg_context_new (request_passwd, NULL);
g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) ctx, TRUE);

testsuite_check ("GMimeGpgContext::import");
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index 546df1b..b5a8b21 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -425,7 +425,7 @@ int main (int argc, char *argv[])
if (system ("/bin/mkdir ./tmp") != 0)
return EXIT_FAILURE;
setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("/usr/bin/gpg --list-keys > /dev/null 2>&1") != 0)
+   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
@@ -440,7 +440,7 @@ int main (int argc, char *argv[])

testsuite_start ("PGP/MIME implementation");

-   ctx = g_mime_gpg_context_new (request_passwd, "/usr/bin/gpg");
+   ctx = g_mime_gpg_context_new (request_passwd, NULL);
g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) ctx, TRUE);

testsuite_check ("GMimeGpgContext::import");
diff --git a/tests/test-smime.c b/tests/test-smime.c
index f4549c7..f05e03a 100644
--- a/tests/test-smime.c
+++ b/tests/test-smime.c
@@ -426,7 +426,7 @@ int main (int argc, char *argv[])
if (system ("/bin/mkdir ./tmp") != 0)
return EXIT_FAILURE;
g_setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("/usr/bin/gpg --list-keys > /dev/null 2>&1") != 0)
+   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
-- 
2.10.2

___
gmime-devel-list mailing list
gmime-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gmime-devel-list


[gmime-devel] [PATCH 3/6] consolidate setup of GnuPG homedir for test suites

2016-12-01 Thread Daniel Kahn Gillmor
three different test suites all set up and tear down the GnuPG homedir
in the same way.  By consolidating that code in testsuite.c we can
improve it in a single place.
---
 tests/test-pgp.c | 10 ++
 tests/test-pgpmime.c | 10 ++
 tests/test-smime.c   | 10 ++
 tests/testsuite.c| 21 +
 tests/testsuite.h|  3 +++
 5 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/tests/test-pgp.c b/tests/test-pgp.c
index 3e7a2a4..8fc755c 100644
--- a/tests/test-pgp.c
+++ b/tests/test-pgp.c
@@ -283,13 +283,7 @@ int main (int argc, char **argv)

testsuite_init (argc, argv);

-   /* reset .gnupg config directory */
-   if (system ("/bin/rm -rf ./tmp") != 0)
-   return EXIT_FAILURE;
-   if (system ("/bin/mkdir ./tmp") != 0)
-   return EXIT_FAILURE;
-   setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
+   if (testsuite_setup_gpghome ())
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
@@ -404,7 +398,7 @@ int main (int argc, char **argv)

g_mime_shutdown ();

-   if (system ("/bin/rm -rf ./tmp") != 0)
+   if (testsuite_destroy_gpghome ())
return EXIT_FAILURE;

return testsuite_exit ();
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index b5a8b21..4cead27 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -419,13 +419,7 @@ int main (int argc, char *argv[])

testsuite_init (argc, argv);

-   /* reset .gnupg config directory */
-   if (system ("/bin/rm -rf ./tmp") != 0)
-   return EXIT_FAILURE;
-   if (system ("/bin/mkdir ./tmp") != 0)
-   return EXIT_FAILURE;
-   setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
+   if (testsuite_setup_gpghome ())
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
@@ -489,7 +483,7 @@ int main (int argc, char *argv[])

g_mime_shutdown ();

-   if (system ("/bin/rm -rf ./tmp") != 0)
+   if (testsuite_destroy_gpghome ())
return EXIT_FAILURE;

return testsuite_exit ();
diff --git a/tests/test-smime.c b/tests/test-smime.c
index f05e03a..f35fbb7 100644
--- a/tests/test-smime.c
+++ b/tests/test-smime.c
@@ -420,13 +420,7 @@ int main (int argc, char *argv[])

testsuite_init (argc, argv);

-   /* reset .gnupg config directory */
-   if (system ("/bin/rm -rf ./tmp") != 0)
-   return EXIT_FAILURE;
-   if (system ("/bin/mkdir ./tmp") != 0)
-   return EXIT_FAILURE;
-   g_setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
-   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
+   if (testsuite_setup_gpghome ())
return EXIT_FAILURE;

for (i = 1; i < argc; i++) {
@@ -490,7 +484,7 @@ int main (int argc, char *argv[])

g_mime_shutdown ();

-   if (system ("/bin/rm -rf ./tmp") != 0)
+   if (testsuite_destroy_gpghome ())
return EXIT_FAILURE;

return testsuite_exit ();
diff --git a/tests/testsuite.c b/tests/testsuite.c
index 2b72301..acd36a5 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -346,6 +346,27 @@ g_throw (Exception *ex)
longjmp (env->env, 1);
 }
 
+int
+testsuite_setup_gpghome ()
+{
+   /* reset .gnupg config directory */
+   if (system ("/bin/rm -rf ./tmp") != 0)
+   return EXIT_FAILURE;
+   if (system ("/bin/mkdir ./tmp") != 0)
+   return EXIT_FAILURE;
+   g_setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
+   if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
+   return EXIT_FAILURE;
+   return EXIT_SUCCESS;
+}
+
+int
+testsuite_destroy_gpghome ()
+{
+   if (system ("/bin/rm -rf ./tmp") != 0)
+   return EXIT_FAILURE;
+   return EXIT_SUCCESS;
+}
 
 #ifdef BUILD
 int main (int argc, char **argv)
diff --git a/tests/testsuite.h b/tests/testsuite.h
index ece9014..6c92a5a 100644
--- a/tests/testsuite.h
+++ b/tests/testsuite.h
@@ -45,6 +45,9 @@ void testsuite_check_passed (void);
 
 int testsuite_total_errors (void);
 
+/* for those parts of the test suite that use GnuPG */
+int testsuite_setup_gpghome (void);
+int testsuite_destroy_gpghome (void);
 
 /*#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
 #define G_GNUC_NORETURN __attribute__((noreturn))
-- 
2.10.2

___
gmime-devel-list mailing list
gmime-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gmime-devel-list


[gmime-devel] [PATCH 4/6] avoid trying to interact with the user session during test suites

2016-12-01 Thread Daniel Kahn Gillmor
---
 tests/testsuite.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/tests/testsuite.c b/tests/testsuite.c
index acd36a5..9422e93 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -355,6 +355,11 @@ testsuite_setup_gpghome ()
if (system ("/bin/mkdir ./tmp") != 0)
return EXIT_FAILURE;
g_setenv ("GNUPGHOME", "./tmp/.gnupg", 1);
+   /* disable the usual mechanisms gpg-agent uses for pinentry */
+   g_unsetenv ("DISPLAY");
+   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
+   g_unsetenv ("GPG_TTY");
+
if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
-- 
2.10.2

___
gmime-devel-list mailing list
gmime-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gmime-devel-list


[gmime-devel] [PATCH 5/6] Use pinentry-mode loopback in test suite when using "modern" GnuPG

2016-12-01 Thread Daniel Kahn Gillmor
The "Modern" GnuPG suite (2.1.x or higher) defaults to relying on the
gpg-agent for secret key material access, which can prompt the user
for a passphrase.  The test suite uses callbacks to supply the
passphrase, so in these modern versions it should use "pinentry-mode
loopback".

Many users of GMime are likely to avoid using the passphrase callback
and instead to rely on permission from the cryptographic agent
directly.  We do not currently test these scenarios, though we could
do so with a fake pinentry.  If we do that, then those scenarios
should *not* use the loopback pinentry-mode, and we'd need to adjust
this setup.

In the longer term, the right way to resolve all of this would be to
use gpgme directly, instead of having our own wrapper that invokes gpg
manually.
---
 tests/testsuite.c | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/tests/testsuite.c b/tests/testsuite.c
index 9422e93..84079d1 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -27,6 +27,10 @@
 #ifdef ENABLE_THREADS
 #include 
 #endif
+#include 
+#include 
+#include 
+#include 
 
 #include "testsuite.h"
 
@@ -346,9 +350,38 @@ g_throw (Exception *ex)
longjmp (env->env, 1);
 }
 
+static int
+is_gpg_modern()
+{
+   const char vheader[] = "gpg (GnuPG) ";
+   FILE *vpipe;
+   char *vstring;
+   size_t vlen;
+   int ret;
+
+   if ((vpipe = popen ("gpg --version", "r")) == NULL)
+   return 0;
+   vlen = 0;
+   vstring = NULL;
+   if (getline (, , vpipe) == -1)
+   return 0;
+   if (strncmp (vstring, vheader, sizeof (vheader) - 1))
+   return 0;
+   ret = (vstring[sizeof (vheader) - 1] > '2') ||
+   (vstring[sizeof (vheader) - 1] == '2' &&
+vstring[sizeof (vheader)] == '.' &&
+vstring[sizeof (vheader) + 1] >= '1');
+   free (vstring);
+   pclose (vpipe);
+   return ret;
+}
+
 int
 testsuite_setup_gpghome ()
 {
+   int gpgconf;
+   const char directive[] = "pinentry-mode loopback\n";
+   
/* reset .gnupg config directory */
if (system ("/bin/rm -rf ./tmp") != 0)
return EXIT_FAILURE;
@@ -362,6 +395,16 @@ testsuite_setup_gpghome ()
 
if (system ("gpg --list-keys > /dev/null 2>&1") != 0)
return EXIT_FAILURE;
+   
+   if (is_gpg_modern()) {
+   if ((gpgconf = open ("./tmp/.gnupg/gpg.conf", O_WRONLY | 
O_CREAT | O_TRUNC, 0400)) == -1)
+   return EXIT_FAILURE;
+   if (write (gpgconf, directive, sizeof(directive) - 1) != 
sizeof(directive) - 1)
+   return EXIT_FAILURE;
+   if (close (gpgconf) != 0)
+   return EXIT_FAILURE;
+   }
+   
return EXIT_SUCCESS;
 }
 
-- 
2.10.2

___
gmime-devel-list mailing list
gmime-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gmime-devel-list


[gmime-devel] [PATCH 1/6] Ship extra data for tests.

2016-12-01 Thread Daniel Kahn Gillmor
Running "make check" from the tarball currently doesn't run as many of
the tests as it should, because the data files for the tests aren't
shipped.

This patch includes those files in the generated upstream tarball.
---
 tests/Makefile.am | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 93e4150..d0c0be9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -112,7 +112,9 @@ test_smime_DEPENDENCIES = $(DEPS)
 test_smime_LDADD = $(LDADDS)
 endif
 
-EXTRA_DIST = test1.eml test2.eml test3.eml
+EXTRA_DIST = test1.eml test2.eml test3.eml $(wildcard  \
+ data/pgp*/gmime.gpg.* data/mbox/*put/substring.mbox   \
+ empty*.msg message-partial.* rfc2060.msg)
 
 VERBOSITY=-v
 
-- 
2.10.2

___
gmime-devel-list mailing list
gmime-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gmime-devel-list


[gmime-devel] [PATCH 6/6] Support extraction of session keys during decryption.

2016-12-01 Thread Daniel Kahn Gillmor
Some message stores can be optimized by caching session keys of
encrypted messages, rather than incurring asymmetric crypto operations
on each subsequent decryption.

This patch allows gmime to perform extraction of session keys during
message decryption to support that use case.

See the discussion starting here for more detail on the API/design
choices:
https://mail.gnome.org/archives/gmime-devel-list/2016-July/msg5.html
---
 gmime/gmime-crypto-context.c | 41 
 gmime/gmime-crypto-context.h |  4 
 gmime/gmime-gpg-context.c| 50 +++-
 gmime/gmime-gpg-context.h|  4 
 tests/test-pgp.c |  5 +
 tests/test-pgpmime.c |  9 +++-
 6 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/gmime/gmime-crypto-context.c b/gmime/gmime-crypto-context.c
index 5269440..90fa390 100644
--- a/gmime/gmime-crypto-context.c
+++ b/gmime/gmime-crypto-context.c
@@ -573,6 +573,7 @@ g_mime_decrypt_result_init (GMimeDecryptResult *result, 
GMimeDecryptResultClass
result->mdc = GMIME_DIGEST_ALGO_DEFAULT;
result->recipients = NULL;
result->signatures = NULL;
+   result->session_key = NULL;
 }
 
 static void
@@ -586,6 +587,8 @@ g_mime_decrypt_result_finalize (GObject *object)
if (result->signatures)
g_object_unref (result->signatures);

+   g_free (result->session_key);
+   
G_OBJECT_CLASS (result_parent_class)->finalize (object);
 }
 
@@ -755,3 +758,41 @@ g_mime_decryption_result_get_mdc (GMimeDecryptResult 
*result)

return result->mdc;
 }
+
+
+/**
+ * g_mime_decrypt_result_set_session_key:
+ * @result: a #GMimeDecryptResult
+ * @session_key: a pointer to a null-terminated string representing the 
session key
+ *
+ * Set the session_key to be returned by this decryption result.
+ **/
+void
+g_mime_decrypt_result_set_session_key (GMimeDecryptResult *result, const char 
*session_key)
+{
+   g_return_if_fail (GMIME_IS_DECRYPT_RESULT (result));
+
+   g_free (result->session_key);
+   result->session_key = g_strdup(session_key);
+}
+
+
+/**
+ * g_mime_decrypt_result_get_session_key:
+ * @result: a #GMimeDecryptResult
+ *
+ * Get the session_key used for this decryption, if the underlying
+ * crypto context is capable of and (configured to) retrieve session
+ * keys during decryption.  See, for example,
+ * g_mime_gpg_context_set_retrieve_session_key().
+ *
+ * Returns: the session_key digest algorithm used, or NULL if no
+ * session key was requested or found.
+ **/
+const char*
+g_mime_decryption_result_get_session_key (GMimeDecryptResult *result)
+{
+   g_return_val_if_fail (GMIME_IS_DECRYPT_RESULT (result), 
GMIME_DIGEST_ALGO_DEFAULT);
+   
+   return result->session_key;
+}
diff --git a/gmime/gmime-crypto-context.h b/gmime/gmime-crypto-context.h
index cd38760..72573ed 100644
--- a/gmime/gmime-crypto-context.h
+++ b/gmime/gmime-crypto-context.h
@@ -206,6 +206,7 @@ struct _GMimeDecryptResult {
GMimeSignatureList *signatures;
GMimeCipherAlgo cipher;
GMimeDigestAlgo mdc;
+   char *session_key;
 };
 
 struct _GMimeDecryptResultClass {
@@ -229,6 +230,9 @@ GMimeCipherAlgo g_mime_decrypt_result_get_cipher 
(GMimeDecryptResult *result);
 void g_mime_decrypt_result_set_mdc (GMimeDecryptResult *result, 
GMimeDigestAlgo mdc);
 GMimeDigestAlgo g_mime_decrypt_result_get_mdc (GMimeDecryptResult *result);
 
+void g_mime_decrypt_result_set_session_key (GMimeDecryptResult *result, const 
char *session_key);
+const char *g_mime_decrypt_result_get_session_key (GMimeDecryptResult *result);
+
 G_END_DECLS
 
 #endif /* __GMIME_CRYPTO_CONTEXT_H__ */
diff --git a/gmime/gmime-gpg-context.c b/gmime/gmime-gpg-context.c
index 2ca280a..6f7d374 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -172,6 +172,7 @@ g_mime_gpg_context_init (GMimeGpgContext *ctx, 
GMimeGpgContextClass *klass)
ctx->always_trust = FALSE;
ctx->use_agent = FALSE;
ctx->path = NULL;
+   ctx->retrieve_session_key = FALSE;
 }
 
 static void
@@ -311,6 +312,7 @@ struct _GpgCtx {
GMimeStream *diagnostics;

GMimeCertificateList *encrypted_to;  /* full list of encrypted-to 
recipients */
+   char *session_key;
GMimeSignatureList *signatures;
GMimeSignature *signature;

@@ -375,6 +377,7 @@ gpg_ctx_new (GMimeGpgContext *ctx)
gpg->need_id = NULL;

gpg->encrypted_to = NULL;
+   gpg->session_key = NULL;
gpg->signatures = NULL;
gpg->signature = NULL;

@@ -555,6 +558,8 @@ gpg_ctx_free (struct _GpgCtx *gpg)
if (gpg->encrypted_to)
g_object_unref (gpg->encrypted_to);

+   g_free (gpg->session_key);
+   
if (gpg->signatures)
g_object_unref (gpg->signatures);

@@ -691,6 +696,9 @@ gpg_ctx_get_argv (struct _GpgCtx *gpg, int