diff --git a/NEWS b/NEWS index 3ccb371f..824faeb7 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,9 @@ Noteworthy changes in version 1.18.1 (unreleased) gpgme_op_sign* to allow creating an encrypted and/or signed archive. [T6342] + * Extended gpgme_op_decrypt* and gpgme_op_decrypt_verify* to allow + extracting an encrypted and/or signed archive. [T6342] + * cpp: Handle error when trying to sign expired keys. [T6155] * cpp, qt: Fix building with C++11. [T6141] @@ -30,6 +33,7 @@ Noteworthy changes in version 1.18.1 (unreleased) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_get_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'. gpgme_set_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'. + GPGME_DECRYPT_ARCHIVE NEW. GPGME_ENCRYPT_ARCHIVE NEW. GPGME_SIG_MODE_ARCHIVE NEW. cpp: GpgGenCardKeyInteractor::Curve NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index b8b90bb1..184b1afe 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3172,8 +3172,8 @@ 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. Please be aware that -using this feature with GnuPG < 2.1.16 will leak the session key on -many platforms via ps(1). +using this feature with GnuPG < 2.1.16 or when decrypting an archive +will leak the session key on many platforms via ps(1). @item "auto-key-retrieve" Setting the @var{value} to "1" asks the backend to automatically @@ -5589,6 +5589,12 @@ The function @code{gpgme_op_decrypt} decrypts the ciphertext in the data object @var{cipher} and stores it into the data object @var{plain}. +If the flag @code(GPGME_DECRYPT_ARCHIVE) is set, then an encrypted +archive in the data object @var{cipher} is decrypted and extracted. +The content of the archive is extracted into a directory named +@code{GPGARCH_n_} (where @code{n} is a number) or into the directory +set with @code{gpgme_data_set_file_name} for the data object @var{plain}. + The function returns the error code @code{GPG_ERR_NO_ERROR} if the ciphertext could be decrypted successfully, @code{GPG_ERR_INV_VALUE} if @var{ctx}, @var{cipher} or @var{plain} is not a valid pointer, @@ -5632,6 +5638,13 @@ multiple of the following bit values: The @code{GPGME_DECRYPT_VERIFY} symbol specifies that this function shall exactly act as @code{gpgme_op_decrypt_verify}. +@item GPGME_DECRYPT_ARCHIVE +@since{1.19.0} + +The @code{GPGME_DECRYPT_ARCHIVE} symbol specifies that the input is an +encrypted archive that shall be decrypted and extracted. This feature +is currently only supported for the OpenPGP crypto engine. + @item GPGME_DECRYPT_UNWRAP @since{1.8.0} diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 06eb3e18..86422112 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -310,7 +310,8 @@ add_gpg_arg (engine_gpg_t gpg, const char *arg) } static gpgme_error_t -add_gpg_arg_with_value (engine_gpg_t gpg, const char *arg, const char *value, int front) +add_gpg_arg_with_value (engine_gpg_t gpg, const char *arg, const char *value, + int front) { return _add_arg (gpg, arg, value, strlen (value), front, NULL, 1); } @@ -1829,6 +1830,14 @@ gpg_decrypt (void *engine, engine_gpg_t gpg = engine; gpgme_error_t err; + gpg->flags.use_gpgtar = !!(flags & GPGME_DECRYPT_ARCHIVE); + + if (gpg->flags.use_gpgtar && !have_gpg_version (gpg, "2.3.5")) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + if (gpg->flags.use_gpgtar && (flags & GPGME_DECRYPT_UNWRAP)) + return gpg_error (GPG_ERR_INV_VALUE); + err = add_arg (gpg, "--decrypt"); if (!err && (flags & GPGME_DECRYPT_UNWRAP)) @@ -1840,17 +1849,17 @@ gpg_decrypt (void *engine, } if (!err && export_session_key) - err = add_arg (gpg, "--show-session-key"); + err = add_gpg_arg (gpg, "--show-session-key"); if (!err && auto_key_retrieve) - err = add_arg (gpg, "--auto-key-retrieve"); + err = add_gpg_arg (gpg, "--auto-key-retrieve"); if (!err && gpg->flags.auto_key_import) - err = add_arg (gpg, "--auto-key-import"); + err = add_gpg_arg (gpg, "--auto-key-import"); if (!err && override_session_key && *override_session_key) { - if (have_gpg_version (gpg, "2.1.16")) + if (have_gpg_version (gpg, "2.1.16") && !gpg->flags.use_gpgtar) { gpgme_data_release (gpg->override_session_key); TRACE (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n", @@ -1880,25 +1889,43 @@ gpg_decrypt (void *engine, else { /* Using that option may leak the session key via ps(1). */ - err = add_arg (gpg, "--override-session-key"); - if (!err) - err = add_arg (gpg, override_session_key); + err = add_gpg_arg_with_value (gpg, "--override-session-key=", + override_session_key, 0); } } /* Tell the gpg object about the data. */ - if (!err) - err = add_arg (gpg, "--output"); - if (!err) - err = add_arg (gpg, "-"); - if (!err) - err = add_data (gpg, plain, 1, 1); - if (!err) - err = add_input_size_hint (gpg, ciph); - if (!err) - err = add_arg (gpg, "--"); - if (!err) - err = add_data (gpg, ciph, -1, 0); + if (gpg->flags.use_gpgtar) + { + const char *file_name = gpgme_data_get_file_name (plain); + if (!err && file_name) + { + err = add_arg (gpg, "--directory"); + if (!err) + err = add_arg (gpg, file_name); + } + if (!err) + err = add_input_size_hint (gpg, ciph); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, ciph, 0, 0); + } + else + { + if (!err) + err = add_arg (gpg, "--output"); + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_data (gpg, plain, 1, 1); + if (!err) + err = add_input_size_hint (gpg, ciph); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, ciph, -1, 0); + } if (!err) err = start (gpg); diff --git a/src/gpgme.h.in b/src/gpgme.h.in index fabba257..b498cd3b 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1426,6 +1426,7 @@ gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx); typedef enum { GPGME_DECRYPT_VERIFY = 1, + GPGME_DECRYPT_ARCHIVE = 2, GPGME_DECRYPT_UNWRAP = 128 } gpgme_decrypt_flags_t; diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index cf719925..ee49ead6 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -91,6 +91,8 @@ show_usage (int ex) " --unwrap remove only the encryption layer\n" " --large-buffers use large I/O buffer\n" " --sensitive mark data objects as sensitive\n" + " --archive extract files from an encrypted archive\n" + " --directory DIR extract the files into the directory DIR\n" " --diagnostics print diagnostics\n" , stderr); exit (ex); @@ -113,6 +115,7 @@ main (int argc, char **argv) int export_session_key = 0; const char *override_session_key = NULL; const char *request_origin = NULL; + const char *directory = NULL; int no_symkey_cache = 0; int ignore_mdc_error = 0; int raw_output = 0; @@ -205,6 +208,19 @@ main (int argc, char **argv) raw_output = 1; argc--; argv++; } + else if (!strcmp (*argv, "--archive")) + { + flags |= GPGME_DECRYPT_ARCHIVE; + argc--; argv++; + } + else if (!strcmp (*argv, "--directory")) + { + argc--; argv++; + if (!argc) + show_usage (1); + directory = *argv; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -302,6 +318,16 @@ main (int argc, char **argv) gpgme_strerror (err)); exit (1); } + if (directory && (flags & GPGME_DECRYPT_ARCHIVE)) + { + err = gpgme_data_set_file_name (out, directory); + if (err) + { + fprintf (stderr, PGM ": error setting file name (out): %s\n", + gpgme_strerror (err)); + exit (1); + } + } if (large_buffers) { err = gpgme_data_set_flag (out, "io-buffer-size", "1000000");