[gmime] Added support for retrieving gpg session keys



commit 8b854830e0fa06b968a40f2ab4e4267bd0cc4f97
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Fri Dec 2 19:19:33 2016 -0500

    Added support for retrieving gpg session keys
    
    2016-12-02  Jeffrey Stedfast  <fejj gnome org>
    
        * gmime/gmime-gpg-context.c (gpg_ctx_free): Free the session_key.
        (gpg_ctx_get_argv): Pass --show-session-key to gpg if requested.
        (gpg_ctx_parse_status): Decode the session-key sent by gpg.
        (gpg_decrypt): Set the session_key on the decrypt result.
        (g_mime_gpg_context_get_retrieve_session_key): Added.
        (g_mime_gpg_context_set_retrieve_session_key): Added.
    
        * gmime/gmime-crypto-context.c (g_mime_decrypt_result_set_session_key): Added.
        (g_mime_decryption_result_get_session_key): Added.
    
        Thanks to Daniel Kahn Gillmor for this patch.

 ChangeLog                    |   14 +++++++++++
 gmime/gmime-crypto-context.c |   50 +++++++++++++++++++++++++++++++++++++++
 gmime/gmime-crypto-context.h |    4 +++
 gmime/gmime-gpg-context.c    |   53 +++++++++++++++++++++++++++++++++++++++++-
 gmime/gmime-gpg-context.h    |    4 +++
 tests/test-pgp.c             |    5 ++++
 tests/test-pgpmime.c         |    9 ++++++-
 7 files changed, 137 insertions(+), 2 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 0efb23c..3f05a1d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2016-12-02  Jeffrey Stedfast  <fejj gnome org>
 
+       * gmime/gmime-gpg-context.c (gpg_ctx_free): Free the session_key.
+       (gpg_ctx_get_argv): Pass --show-session-key to gpg if requested.
+       (gpg_ctx_parse_status): Decode the session-key sent by gpg.
+       (gpg_decrypt): Set the session_key on the decrypt result.
+       (g_mime_gpg_context_get_retrieve_session_key): Added.
+       (g_mime_gpg_context_set_retrieve_session_key): Added.
+
+       * gmime/gmime-crypto-context.c (g_mime_decrypt_result_set_session_key): Added.
+       (g_mime_decryption_result_get_session_key): Added.
+
+       Thanks to Daniel Kahn Gillmor for this patch.
+
+2016-12-02  Jeffrey Stedfast  <fejj gnome org>
+
        * gmime/gmime-gpg-context.c (g_mime_gpg_context_new): Allow NULL for the gpg path
        in order to use the default gpg path (i.e. "gpg").
 
diff --git a/gmime/gmime-crypto-context.c b/gmime/gmime-crypto-context.c
index 5269440..3b4171c 100644
--- a/gmime/gmime-crypto-context.c
+++ b/gmime/gmime-crypto-context.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#include <string.h>
+
 #include "gmime-crypto-context.h"
 #include "gmime-error.h"
 
@@ -573,6 +575,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 +589,11 @@ g_mime_decrypt_result_finalize (GObject *object)
        if (result->signatures)
                g_object_unref (result->signatures);
        
+       if (result->session_key) {
+               memset (result->session_key, 0, strlen (result->session_key));
+               g_free (result->session_key);
+       }
+       
        G_OBJECT_CLASS (result_parent_class)->finalize (object);
 }
 
@@ -755,3 +763,45 @@ 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));
+       
+       if (result->session_key) {
+               memset (result->session_key, 0, strlen (result->session_key));
+               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 afc1d52..74f8a4e 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -168,6 +168,7 @@ g_mime_gpg_context_class_init (GMimeGpgContextClass *klass)
 static void
 g_mime_gpg_context_init (GMimeGpgContext *ctx, GMimeGpgContextClass *klass)
 {
+       ctx->retrieve_session_key = FALSE;
        ctx->auto_key_retrieve = FALSE;
        ctx->always_trust = FALSE;
        ctx->use_agent = FALSE;
@@ -313,6 +314,7 @@ struct _GpgCtx {
        GMimeCertificateList *encrypted_to;  /* full list of encrypted-to recipients */
        GMimeSignatureList *signatures;
        GMimeSignature *signature;
+       char *session_key;
        
        int exit_status;
        
@@ -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,11 @@ gpg_ctx_free (struct _GpgCtx *gpg)
        if (gpg->encrypted_to)
                g_object_unref (gpg->encrypted_to);
        
+       if (gpg->session_key) {
+               memset (gpg->session_key, 0, strlen (gpg->session_key));
+               g_free (gpg->session_key);
+       }
+       
        if (gpg->signatures)
                g_object_unref (gpg->signatures);
        
@@ -691,6 +699,9 @@ gpg_ctx_get_argv (struct _GpgCtx *gpg, int status_fd, int secret_fd, char ***str
                if (gpg->use_agent)
                        g_ptr_array_add (args, "--use-agent");
                
+               if (gpg->ctx->retrieve_session_key)
+                       g_ptr_array_add (args, "--show-session-key");
+               
                g_ptr_array_add (args, "--decrypt");
                g_ptr_array_add (args, "--output");
                g_ptr_array_add (args, "-");
@@ -1326,6 +1337,8 @@ gpg_ctx_parse_status (struct _GpgCtx *gpg, GError **err)
                                /* nothing to do... we'll grab the MDC used in DECRYPTION_INFO */
                        } else if (!strncmp (status, "BADMDC", 6)) {
                                /* nothing to do, this will only be sent after DECRYPTION_FAILED */
+                       } else if (!strncmp (status, "SESSION_KEY", 11)) {
+                               status = next_token (status, &gpg->session_key);
                        } else {
                                gpg_ctx_parse_signer_info (gpg, status);
                        }
@@ -2059,10 +2072,12 @@ gpg_decrypt (GMimeCryptoContext *context, GMimeStream *istream,
        result = g_mime_decrypt_result_new ();
        result->recipients = gpg->encrypted_to;
        result->signatures = gpg->signatures;
+       result->session_key = gpg->session_key;
        result->cipher = gpg->cipher;
        result->mdc = gpg->digest;
        gpg->encrypted_to = NULL;
        gpg->signatures = NULL;
+       gpg->session_key = NULL;
        
        gpg_ctx_free (gpg);
        
@@ -2305,7 +2320,7 @@ g_mime_gpg_context_get_use_agent (GMimeGpgContext *ctx)
 /**
  * g_mime_gpg_context_set_use_agent:
  * @ctx: a #GMimeGpgContext
- * @use_agent: always trust flag
+ * @use_agent: use agent flag
  *
  * Sets the @use_agent flag on the gpg context, which indicates that
  * GnuPG should attempt to use gpg-agent for credentials.
@@ -2317,3 +2332,39 @@ g_mime_gpg_context_set_use_agent (GMimeGpgContext *ctx, gboolean use_agent)
        
        ctx->use_agent = use_agent;
 }
+
+/**
+ * g_mime_gpg_context_get_retrieve_session_key:
+ * @ctx: a #GMimeGpgContext
+ *
+ * Gets the retrieve_session_key flag on the gpg context.
+ *
+ * Returns: the retrieve_session_key flag on the gpg context, which
+ * indicates that GnuPG should attempt to retrieve the session key for
+ * any encrypted message.
+ **/
+gboolean
+g_mime_gpg_context_get_retrieve_session_key (GMimeGpgContext *ctx)
+{
+       g_return_val_if_fail (GMIME_IS_GPG_CONTEXT (ctx), FALSE);
+       
+       return ctx->retrieve_session_key;
+}
+
+
+/**
+ * g_mime_gpg_context_set_retrieve_session_key:
+ * @ctx: a #GMimeGpgContext
+ * @retrieve_session_key: retrieve session key flag
+ *
+ * Sets the @retrieve_session_key flag on the gpg context, which
+ * indicates that GnuPG should attempt to retrieve the session key for
+ * any encrypted message.
+ **/
+void
+g_mime_gpg_context_set_retrieve_session_key (GMimeGpgContext *ctx, gboolean retrieve_session_key)
+{
+       g_return_if_fail (GMIME_IS_GPG_CONTEXT (ctx));
+       
+       ctx->retrieve_session_key = retrieve_session_key;
+}
diff --git a/gmime/gmime-gpg-context.h b/gmime/gmime-gpg-context.h
index a088e90..4f17fe0 100644
--- a/gmime/gmime-gpg-context.h
+++ b/gmime/gmime-gpg-context.h
@@ -51,6 +51,7 @@ struct _GMimeGpgContext {
        gboolean always_trust;
        gboolean use_agent;
        char *path;
+       gboolean retrieve_session_key;
 };
 
 struct _GMimeGpgContextClass {
@@ -73,6 +74,9 @@ void g_mime_gpg_context_set_always_trust (GMimeGpgContext *ctx, gboolean always_
 gboolean g_mime_gpg_context_get_use_agent (GMimeGpgContext *ctx);
 void g_mime_gpg_context_set_use_agent (GMimeGpgContext *ctx, gboolean use_agent);
 
+gboolean g_mime_gpg_context_get_retrieve_session_key (GMimeGpgContext *ctx);
+void g_mime_gpg_context_set_retrieve_session_key (GMimeGpgContext *ctx, gboolean retrieve_session_key);
+
 G_END_DECLS
 
 #endif /* __GMIME_GPG_CONTEXT_H__ */
diff --git a/tests/test-pgp.c b/tests/test-pgp.c
index 928f7f1..81a4b9d 100644
--- a/tests/test-pgp.c
+++ b/tests/test-pgp.c
@@ -163,6 +163,11 @@ test_decrypt (GMimeCryptoContext *ctx, gboolean sign, GMimeStream *cleartext, GM
                        ex = exception_new ("unexpected signature");
        }
        
+       /* Did not ask for session_key -- it should not be present.
+          We test asking for session_key over in test-pgpmime.c */
+       if (ex == NULL && result->session_key)
+               ex = exception_new ("got session_key when not requested");
+       
        g_object_unref (result);
        
        if (ex != NULL) {
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index cdb83e4..27e6b6b 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -351,9 +351,15 @@ test_multipart_encrypted (GMimeCryptoContext *ctx, gboolean sign)
                throw (ex);
        }
        
+       if (!result->session_key) {
+               ex = exception_new ("No session key returned!");
+               g_object_unref (cleartext);
+               throw (ex);
+       }
+       
        if (result->signatures)
                v(print_verify_results (result->signatures));
-       
+
        if (sign) {
                if (!result->signatures || get_sig_status (result->signatures) != GMIME_SIGNATURE_STATUS_GOOD)
                        ex = exception_new ("signature status expected to be GOOD");
@@ -436,6 +442,7 @@ int main (int argc, char *argv[])
        
        ctx = g_mime_gpg_context_new (request_passwd, NULL);
        g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) ctx, TRUE);
+       g_mime_gpg_context_set_retrieve_session_key ((GMimeGpgContext *) ctx, TRUE);
        
        testsuite_check ("GMimeGpgContext::import");
        try {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]