core: Implement context flag "override-session-key".
authorWerner Koch <wk@gnupg.org>
Tue, 15 Nov 2016 09:29:48 +0000 (10:29 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 15 Nov 2016 09:34:13 +0000 (10:34 +0100)
* src/gpgme.c (gpgme_set_ctx_flag): Add flags "export-session-key" and
"override-session-key".
(gpgme_get_ctx_flag): Ditto.
(gpgme_set_export_session_keys): Remove.
(gpgme_get_export_session_keys): Remove.
* src/gpgme.def, src/libgpgme.vers: Remove them.
* src/context.h (struct gpgme_context): Add field
override_session_key.
* src/decrypt-verify.c (decrypt_verify_start): Pass
override_session_key value to the engine.
* src/decrypt.c (decrypt_start): Ditto.
* src/engine.c (_gpgme_engine_op_decrypt): Ditto.
(_gpgme_engine_op_decrypt_verify): Ditto.
* src/engine-backend.h (struct engine_ops): Extend DECRYPT and
DECRYPT_VERIFY_START with override_session_key.
* src/engine-uiserver.c (_uiserver_decrypt): Add stub arg
override_session_key.
(uiserver_decrypt): Ditto.
(uiserver_decrypt_verify): Ditto.
* src/engine-gpgsm.c (gpgsm_decrypt): Ditto.
* src/engine-gpg.c (gpg_decrypt): Add arg override_session_key and set
corresponding gpg option.

* tests/run-decrypt.c (print_result): Print the session key if
available.
(main): Add options --export-session-key and --override-session-key.

--

To keep the number of context manipulation functions at bay, this
patches removes the just added gpgme_set_export_session_keys and
gpgme_get_export_session_keys by flags for the generic context
function.

The patch also implements the --override-session-key feature.

GnuPG-bug-id: 2754
Signed-off-by: Werner Koch <wk@gnupg.org>
15 files changed:
doc/gpgme.texi
src/context.h
src/decrypt-verify.c
src/decrypt.c
src/engine-backend.h
src/engine-gpg.c
src/engine-gpgsm.c
src/engine-uiserver.c
src/engine.c
src/engine.h
src/gpgme.c
src/gpgme.def
src/gpgme.h.in
src/libgpgme.vers
tests/run-decrypt.c

index e47979c..eb06c20 100644 (file)
@@ -191,7 +191,6 @@ Context Attributes
 * Text Mode::                     Choosing canonical text mode.
 * Offline Mode::                  Choosing offline mode.
 * Included Certificates::         Including a number of certificates.
-* Exporting Session Keys::        Requesting session keys upon decryption.
 * Key Listing Mode::              Selecting key listing mode.
 * Passphrase Callback::           Getting the passphrase from the user.
 * Progress Meter Callback::       Being informed about the progress.
@@ -2314,10 +2313,12 @@ The function @code{gpgme_release} destroys the context with the handle
 The detailed result of an operation is returned in operation-specific
 structures such as @code{gpgme_decrypt_result_t}.  The corresponding
 retrieval functions such as @code{gpgme_op_decrypt_result} provide
-static access to the results after an operation completes.  The
-following interfaces make it possible to detach a result structure
-from its associated context and give it a lifetime beyond that of the
-current operation or context.
+static access to the results after an operation completes.  Those
+structures shall be considered read-only and an application must not
+allocated such a strucure on its own.  The following interfaces make
+it possible to detach a result structure from its associated context
+and give it a lifetime beyond that of the current operation or
+context.
 
 @deftypefun void gpgme_result_ref (@w{void *@var{result}})
 The function @code{gpgme_result_ref} acquires an additional reference
@@ -2352,7 +2353,6 @@ started.  In fact, these references are accessed through the
 * Offline Mode::                  Choosing offline mode.
 * Pinentry Mode::                 Choosing the pinentry mode.
 * Included Certificates::         Including a number of certificates.
-* Exporting Session Keys::        Requesting session keys upon decryption.
 * Key Listing Mode::              Selecting key listing mode.
 * Passphrase Callback::           Getting the passphrase from the user.
 * Progress Meter Callback::       Being informed about the progress.
@@ -2643,29 +2643,6 @@ certificates to include into an S/MIME signed message.
 @end deftypefun
 
 
-@node Exporting Session Keys
-@subsection Exporting Session Keys
-@cindex context, exporting session keys
-@cindex Exporting Session Keys
-@cindex exporting session keys
-
-@deftypefun void gpgme_set_export_session_keys (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{yes}})
-The function @code{gpgme_set_export_session_keys} specifies whether
-the context should try to export the symmetric session key when
-decrypting data.  By default, session keys are not exported.
-
-Session keys are not exported if @var{yes} is zero, and
-enabled otherwise.
-@end deftypefun
-
-@deftypefun int gpgme_get_export_session_keys (@w{gpgme_ctx_t @var{ctx}})
-The function @code{gpgme_get_export_session_keys} returns @code{1} if
-the context will try to export the symmetric session key when
-decrypting, and @code{0} if not, or if @var{ctx} is not a valid
-pointer.
-@end deftypefun
-
-
 @node Key Listing Mode
 @subsection Key Listing Mode
 @cindex key listing mode
@@ -2923,6 +2900,18 @@ format.  For example the non breaking space characters ("~") will not
 be removed from the @code{description} field of the
 @code{gpgme_tofu_info_t} object.
 
+@item "export-session-key"
+Using a @var{value} of "1" specifies that the context should try to
+export the symmetric session key when decrypting data.  By default, or
+when using an empty string or "0" for @var{value}, session keys are
+not exported.
+
+@item "override-session-key"
+The string given in @var{value} is passed to the GnuPG engine to override
+the session key for decryption.  The format of that session key is
+specific to GnuPG and can be retrieved during a decrypt operation when
+the context flag "export-session-key" is enabled.
+
 @end table
 
 This function returns @code{0} on success.
@@ -4798,8 +4787,10 @@ secret key for this recipient is not available, and 0 otherwise.
 This is a pointer to a structure used to store the result of a
 @code{gpgme_op_decrypt} operation.  After successfully decrypting
 data, you can retrieve the pointer to the result with
-@code{gpgme_op_decrypt_result}.  The structure contains the following
-members:
+@code{gpgme_op_decrypt_result}.  As with all result structures, it
+this structure shall be considered read-only and an application must
+not allocated such a strucure on its own.  The structure contains the
+following members:
 
 @table @code
 @item char *unsupported_algorithm
@@ -4817,17 +4808,12 @@ This is the filename of the original plaintext message file if it is
 known, otherwise this is a null pointer.
 
 @item char *session_key
-A textual representation (null-terminated string) of the session key
+A textual representation (nul-terminated string) of the session key
 used in symmetric encryption of the message, if the context has been
-set to export session keys (see @code{gpgme_get_export_session_keys}
-and @code{gpgme_set_export_session_keys}), and a session key was
-available for the most recent decryption operation.  Otherwise, this
-is a null pointer.
-
-You should never access this member of a
-@code{gpgme_op_decrypt_result_t} without first ensuring that
-@code{gpgme_get_export_session_keys} returns non-zero for the
-reporting context.
+set to export session keys (see @code{gpgme_set_ctx_flag,
+"export-session-key"}), and a session key was available for the most
+recent decryption operation.  Otherwise, this is a null pointer.
+
 @end table
 @end deftp
 
index 94935c8..d915b99 100644 (file)
@@ -135,6 +135,9 @@ struct gpgme_context
   /* The sender's addr-spec or NULL.  */
   char *sender;
 
+  /* The gpg specific override session key or NULL. */
+  char *override_session_key;
+
   /* The locale for the pinentry.  */
   char *lc_ctype;
   char *lc_messages;
index 00d256a..e0aa8ea 100644 (file)
@@ -77,7 +77,9 @@ decrypt_verify_start (gpgme_ctx_t ctx, int synchronous,
   _gpgme_engine_set_status_handler (ctx->engine,
                                    decrypt_verify_status_handler, ctx);
 
-  return _gpgme_engine_op_decrypt_verify (ctx->engine, cipher, plain, ctx->export_session_keys);
+  return _gpgme_engine_op_decrypt_verify (ctx->engine, cipher, plain,
+                                          ctx->export_session_keys,
+                                          ctx->override_session_key);
 }
 
 
index 49c735c..43717c0 100644 (file)
@@ -360,7 +360,7 @@ _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
 
 static gpgme_error_t
 decrypt_start (gpgme_ctx_t ctx, int synchronous,
-                     gpgme_data_t cipher, gpgme_data_t plain)
+               gpgme_data_t cipher, gpgme_data_t plain)
 {
   gpgme_error_t err;
 
@@ -390,7 +390,9 @@ decrypt_start (gpgme_ctx_t ctx, int synchronous,
 
   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
 
-  return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain, ctx->export_session_keys);
+  return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain,
+                                   ctx->export_session_keys,
+                                   ctx->override_session_key);
 }
 
 
index 144b156..cfc624d 100644 (file)
@@ -62,9 +62,11 @@ struct engine_ops
   gpgme_error_t (*set_locale) (void *engine, int category, const char *value);
   gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol);
   gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph,
-                           gpgme_data_t plain, int export_session_key);
+                           gpgme_data_t plain, int export_session_key,
+                            const char *override_session_key);
   gpgme_error_t (*decrypt_verify) (void *engine, gpgme_data_t ciph,
-                                  gpgme_data_t plain, int export_session_key);
+                                  gpgme_data_t plain, int export_session_key,
+                                   const char *override_session_key);
   gpgme_error_t (*delete) (void *engine, gpgme_key_t key, int allow_secret);
   gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key,
                         gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */);
index 0e43c24..21ed5bc 100644 (file)
@@ -1550,7 +1550,8 @@ add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
 
 
 static gpgme_error_t
-gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key)
+gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
+             int export_session_key, const char *override_session_key)
 {
   engine_gpg_t gpg = engine;
   gpgme_error_t err;
@@ -1560,6 +1561,13 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain, int export_ses
   if (!err && export_session_key)
     err = add_arg (gpg, "--show-session-key");
 
+  if (!err && override_session_key && *override_session_key)
+    {
+      err = add_arg (gpg, "--override-session-key");
+      if (!err)
+        err = add_arg (gpg, override_session_key);
+    }
+
   /* Tell the gpg object about the data.  */
   if (!err)
     err = add_arg (gpg, "--output");
index 2ff353b..d1be049 100644 (file)
@@ -1120,13 +1120,16 @@ gpgsm_reset (void *engine)
 
 
 static gpgme_error_t
-gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key)
+gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
+               int export_session_key, const char *override_session_key)
 {
   engine_gpgsm_t gpgsm = engine;
   gpgme_error_t err;
+
   /* gpgsm is not capable of exporting session keys right now, so we
    * will ignore this if requested. */
   (void)export_session_key;
+  (void)override_session_key;
 
   if (!gpgsm)
     return gpg_error (GPG_ERR_INV_VALUE);
index 26f0d18..ee7b1d2 100644 (file)
@@ -961,13 +961,16 @@ uiserver_reset (void *engine)
 static gpgme_error_t
 _uiserver_decrypt (void *engine, int verify,
                   gpgme_data_t ciph, gpgme_data_t plain,
-                   int export_session_key)
+                   int export_session_key, const char *override_session_key)
 {
   engine_uiserver_t uiserver = engine;
   gpgme_error_t err;
   const char *protocol;
   char *cmd;
 
+  (void)override_session_key; /* Fixme: We need to see now to add this
+                               * to the UI server protocol  */
+
   if (!uiserver)
     return gpg_error (GPG_ERR_INV_VALUE);
   if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
@@ -1008,16 +1011,21 @@ _uiserver_decrypt (void *engine, int verify,
 
 
 static gpgme_error_t
-uiserver_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key)
+uiserver_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
+                  int export_session_key, const char *override_session_key)
 {
-  return _uiserver_decrypt (engine, 0, ciph, plain, export_session_key);
+  return _uiserver_decrypt (engine, 0, ciph, plain,
+                            export_session_key, override_session_key);
 }
 
 
 static gpgme_error_t
-uiserver_decrypt_verify (void *engine, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key)
+uiserver_decrypt_verify (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
+                         int export_session_key,
+                         const char *override_session_key)
 {
-  return _uiserver_decrypt (engine, 1, ciph, plain, export_session_key);
+  return _uiserver_decrypt (engine, 1, ciph, plain,
+                            export_session_key, override_session_key);
 }
 
 
index b43f683..d542b25 100644 (file)
@@ -653,7 +653,8 @@ _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol)
 
 gpgme_error_t
 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
-                         gpgme_data_t plain, int export_session_key)
+                         gpgme_data_t plain, int export_session_key,
+                          const char *override_session_key)
 {
   if (!engine)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -661,13 +662,15 @@ _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
   if (!engine->ops->decrypt)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  return (*engine->ops->decrypt) (engine->engine, ciph, plain, export_session_key);
+  return (*engine->ops->decrypt) (engine->engine, ciph, plain,
+                                  export_session_key, override_session_key);
 }
 
 
 gpgme_error_t
 _gpgme_engine_op_decrypt_verify (engine_t engine, gpgme_data_t ciph,
-                                gpgme_data_t plain, int export_session_key)
+                                gpgme_data_t plain, int export_session_key,
+                                 const char *override_session_key)
 {
   if (!engine)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -675,7 +678,9 @@ _gpgme_engine_op_decrypt_verify (engine_t engine, gpgme_data_t ciph,
   if (!engine->ops->decrypt_verify)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  return (*engine->ops->decrypt_verify) (engine->engine, ciph, plain, export_session_key);
+  return (*engine->ops->decrypt_verify) (engine->engine, ciph, plain,
+                                         export_session_key,
+                                         override_session_key);
 }
 
 
index 512ac19..29d2f25 100644 (file)
@@ -84,11 +84,14 @@ _gpgme_engine_set_colon_line_handler (engine_t engine,
                                      void *fnc_value);
 gpgme_error_t _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
                                        gpgme_data_t plain,
-                                        int export_session_key);
+                                        int export_session_key,
+                                        const char *override_session_key);
 gpgme_error_t _gpgme_engine_op_decrypt_verify (engine_t engine,
                                               gpgme_data_t ciph,
                                               gpgme_data_t plain,
-                                               int export_session_key);
+                                               int export_session_key,
+                                               const char *override_session_key
+                                               );
 gpgme_error_t _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
                                       int allow_secret);
 gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type,
index 32abc28..1a10fd9 100644 (file)
@@ -247,6 +247,7 @@ gpgme_release (gpgme_ctx_t ctx)
   free (ctx->signers);
   free (ctx->lc_ctype);
   free (ctx->lc_messages);
+  free (ctx->override_session_key);
   _gpgme_engine_info_release (ctx->engine_info);
   ctx->engine_info = NULL;
   DESTROY_LOCK (ctx->lock);
@@ -515,6 +516,17 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
     {
       ctx->raw_description = abool;
     }
+  else if (!strcmp (name, "export-session-key"))
+    {
+      ctx->export_session_keys = abool;
+    }
+  else if (!strcmp (name, "override-session-key"))
+    {
+      free (ctx->override_session_key);
+      ctx->override_session_key = strdup (value);
+      if (!ctx->override_session_key)
+        err = gpg_error_from_syserror ();
+    }
   else
     err = gpg_error (GPG_ERR_UNKNOWN_NAME);
 
@@ -526,7 +538,7 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
  * of valid names.  If the NAME is unknown NULL is returned.  For a
  * boolean flag an empty string is returned for False and the string
  * "1" for True; thus either atoi or a simple string test can be
- * used. */
+ * used.  */
 const char *
 gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name)
 {
@@ -540,35 +552,19 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name)
     {
       return ctx->raw_description? "1":"";
     }
+  else if (!strcmp (name, "export-session-key"))
+    {
+      return ctx->export_session_keys? "1":"";
+    }
+  else if (!strcmp (name, "override-session-key"))
+    {
+      return ctx->override_session_key? ctx->override_session_key : "";
+    }
   else
     return NULL;
 }
 
 
-/* Enable or disable the exporting session keys upon decryption.  */
-void
-gpgme_set_export_session_keys (gpgme_ctx_t ctx, int export_session_keys)
-{
-  TRACE2 (DEBUG_CTX, "gpgme_set_export_session_keys", ctx, "export_session_keys=%i (%s)",
-         export_session_keys, export_session_keys ? "yes" : "no");
-
-  if (!ctx)
-    return;
-
-  ctx->export_session_keys = !!export_session_keys;
-}
-
-
-/* Return whether this context will export session keys upon decryption.  */
-int
-gpgme_get_export_session_keys (gpgme_ctx_t ctx)
-{
-  TRACE2 (DEBUG_CTX, "gpgme_get_export_session_keys", ctx, "ctx->export_session_keys=%i (%s)",
-         ctx->export_session_keys, ctx->export_session_keys ? "yes" : "no");
-  return ctx->export_session_keys;
-}
-
-
 /* Enable or disable the use of the special textmode.  Textmode is for
   example used for the RFC2015 signatures; note that the updated RFC
   3156 mandates that the MUA does some preparations so that textmode
index cd0d084..0d3ce74 100644 (file)
@@ -252,8 +252,6 @@ EXPORTS
     gpgme_op_query_swdb                   @189
     gpgme_op_query_swdb_result            @190
 
-    gpgme_set_export_session_keys         @191
-    gpgme_get_export_session_keys         @192
-    gpgme_get_ctx_flag                    @193
+    gpgme_get_ctx_flag                    @191
 ; END
 
index 43e07b0..7cfe8f6 100644 (file)
@@ -1040,13 +1040,6 @@ void gpgme_set_offline (gpgme_ctx_t ctx, int yes);
 /* Return non-zero if offline mode is set in CTX.  */
 int gpgme_get_offline (gpgme_ctx_t ctx);
 
-/* If YES is non-zero, try to return session keys during decryption,
-   do not otherwise.  */
-void gpgme_set_export_session_keys (gpgme_ctx_t ctx, int yes);
-
-/* Return non-zero if export_session_keys is set in CTX.  */
-int gpgme_get_export_session_keys (gpgme_ctx_t ctx);
-
 /* Use whatever the default of the backend crypto engine is.  */
 #define GPGME_INCLUDE_CERTS_DEFAULT    -256
 
index 362909a..a55cd10 100644 (file)
@@ -126,9 +126,6 @@ GPGME_1.1 {
 
     gpgme_op_query_swdb;
     gpgme_op_query_swdb_result;
-
-    gpgme_set_export_session_keys;
-    gpgme_get_export_session_keys;
 };
 
 
index 6d38aee..65624d0 100644 (file)
@@ -51,9 +51,13 @@ print_result (gpgme_decrypt_result_t result)
 {
   gpgme_recipient_t recp;
   int count = 0;
+
   printf ("Original file name: %s\n", nonnull(result->file_name));
   printf ("Wrong key usage: %i\n", result->wrong_key_usage);
-  printf ("Unsupported algorithm: %s\n ", nonnull(result->unsupported_algorithm));
+  printf ("Unsupported algorithm: %s\n",
+          nonnull(result->unsupported_algorithm));
+  if (result->session_key)
+    printf ("Session key: %s\n", result->session_key);
 
   for (recp = result->recipients; recp->next; recp = recp->next)
     {
@@ -74,6 +78,8 @@ show_usage (int ex)
          "  --status         print status lines from the backend\n"
          "  --openpgp        use the OpenPGP protocol (default)\n"
          "  --cms            use the CMS protocol\n"
+         "  --export-session-key            show the session key\n"
+         "  --override-session-key STRING   use STRING as session key\n"
          , stderr);
   exit (ex);
 }
@@ -91,6 +97,8 @@ main (int argc, char **argv)
   gpgme_data_t out = NULL;
   gpgme_decrypt_result_t result;
   int print_status = 0;
+  int export_session_key = 0;
+  const char *override_session_key = NULL;
 
   if (argc)
     { argc--; argv++; }
@@ -125,6 +133,19 @@ main (int argc, char **argv)
           protocol = GPGME_PROTOCOL_CMS;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--export-session-key"))
+        {
+          export_session_key = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--override-session-key"))
+        {
+          argc--; argv++;
+          if (!argc)
+            show_usage (1);
+          override_session_key = *argv;
+          argc--; argv++;
+        }
       else if (!strncmp (*argv, "--", 2))
         show_usage (1);
 
@@ -152,6 +173,10 @@ main (int argc, char **argv)
       gpgme_set_status_cb (ctx, status_cb, NULL);
       gpgme_set_ctx_flag (ctx, "full-status", "1");
     }
+  if (export_session_key)
+    gpgme_set_ctx_flag (ctx, "export-session-key", "1");
+  if (override_session_key)
+    gpgme_set_ctx_flag (ctx, "override-session-key", override_session_key);
 
   err = gpgme_data_new_from_stream (&in, fp_in);
   if (err)