core: Support usage of gpgtar for decrypting an encrypted archive

* src/gpgme.h.in (GPGME_DECRYPT_ARCHIVE): New decryption flag.
* src/engine-gpg.c (gpg_decrypt): Set use_gpgtar engine flag if
GPGME_DECRYPT_ARCHIVE flag is set. Check for new enough gpg and
incompatible flags. Use add_gpg_arg_with_value for gpg-only options
with a value and add_gpg_arg for gpg-only options without a value.
Set extra options for gpgtar and pass input data to stdin when using
gpgtar.

* tests/run-decrypt.c (show_usage): New options --archive and
--directory.
(main): Parse new options. Decrypt with gpgtar if --archive is given.
Set file name of output data to value of --directory option.
--

GnuPG-bug-id: 6342
This commit is contained in:
Ingo Klöcker 2023-01-24 11:05:52 +01:00
parent 419adf41af
commit 95ea3bf831
No known key found for this signature in database
GPG Key ID: F5A5D1692277A1E9
5 changed files with 93 additions and 22 deletions

4
NEWS
View File

@ -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.

View File

@ -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}

View File

@ -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,13 +1889,30 @@ 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 (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)
@ -1899,6 +1925,7 @@ gpg_decrypt (void *engine,
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, ciph, -1, 0);
}
if (!err)
err = start (gpg);

View File

@ -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;

View File

@ -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");