From 7659d42468b604db2936b021425683f407eba4a7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 15 Nov 2016 10:29:48 +0100 Subject: [PATCH] core: Implement context flag "override-session-key". * 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 --- doc/gpgme.texi | 66 +++++++++++++++++-------------------------- src/context.h | 3 ++ src/decrypt-verify.c | 4 ++- src/decrypt.c | 6 ++-- src/engine-backend.h | 6 ++-- src/engine-gpg.c | 10 ++++++- src/engine-gpgsm.c | 5 +++- src/engine-uiserver.c | 18 ++++++++---- src/engine.c | 13 ++++++--- src/engine.h | 7 +++-- src/gpgme.c | 46 ++++++++++++++---------------- src/gpgme.def | 4 +-- src/gpgme.h.in | 7 ----- src/libgpgme.vers | 3 -- tests/run-decrypt.c | 27 +++++++++++++++++- 15 files changed, 128 insertions(+), 97 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index e47979c5..eb06c20a 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -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. +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. -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. @end table @end deftp diff --git a/src/context.h b/src/context.h index 94935c80..d915b994 100644 --- a/src/context.h +++ b/src/context.h @@ -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; diff --git a/src/decrypt-verify.c b/src/decrypt-verify.c index 00d256a9..e0aa8ea9 100644 --- a/src/decrypt-verify.c +++ b/src/decrypt-verify.c @@ -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); } diff --git a/src/decrypt.c b/src/decrypt.c index 49c735ca..43717c0d 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -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); } diff --git a/src/engine-backend.h b/src/engine-backend.h index 144b1561..cfc624d4 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -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 */); diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 0e43c248..21ed5bc3 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -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"); diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 2ff353b9..d1be049e 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -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); diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index 26f0d18b..ee7b1d2d 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -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); } diff --git a/src/engine.c b/src/engine.c index b43f683e..d542b25c 100644 --- a/src/engine.c +++ b/src/engine.c @@ -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); } diff --git a/src/engine.h b/src/engine.h index 512ac19a..29d2f259 100644 --- a/src/engine.h +++ b/src/engine.h @@ -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, diff --git a/src/gpgme.c b/src/gpgme.c index 32abc282..1a10fd91 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -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 diff --git a/src/gpgme.def b/src/gpgme.def index cd0d0848..0d3ce74f 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -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 diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 43e07b06..7cfe8f65 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -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 diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 362909ae..a55cd10a 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -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; }; diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index 6d38aeea..65624d09 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -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)