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 gpgme_op_sign* to allow creating an encrypted and/or signed
archive. [T6342] 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: Handle error when trying to sign expired keys. [T6155]
* cpp, qt: Fix building with C++11. [T6141] * 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_get_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'.
gpgme_set_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_ENCRYPT_ARCHIVE NEW.
GPGME_SIG_MODE_ARCHIVE NEW. GPGME_SIG_MODE_ARCHIVE NEW.
cpp: GpgGenCardKeyInteractor::Curve 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 the session key for decryption. The format of that session key is
specific to GnuPG and can be retrieved during a decrypt operation when specific to GnuPG and can be retrieved during a decrypt operation when
the context flag "export-session-key" is enabled. Please be aware that 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 using this feature with GnuPG < 2.1.16 or when decrypting an archive
many platforms via ps(1). will leak the session key on many platforms via ps(1).
@item "auto-key-retrieve" @item "auto-key-retrieve"
Setting the @var{value} to "1" asks the backend to automatically 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 data object @var{cipher} and stores it into the data object
@var{plain}. @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 The function returns the error code @code{GPG_ERR_NO_ERROR} if the
ciphertext could be decrypted successfully, @code{GPG_ERR_INV_VALUE} ciphertext could be decrypted successfully, @code{GPG_ERR_INV_VALUE}
if @var{ctx}, @var{cipher} or @var{plain} is not a valid pointer, 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 The @code{GPGME_DECRYPT_VERIFY} symbol specifies that this function
shall exactly act as @code{gpgme_op_decrypt_verify}. 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 @item GPGME_DECRYPT_UNWRAP
@since{1.8.0} @since{1.8.0}

View File

@ -310,7 +310,8 @@ add_gpg_arg (engine_gpg_t gpg, const char *arg)
} }
static gpgme_error_t 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); return _add_arg (gpg, arg, value, strlen (value), front, NULL, 1);
} }
@ -1829,6 +1830,14 @@ gpg_decrypt (void *engine,
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err; 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"); err = add_arg (gpg, "--decrypt");
if (!err && (flags & GPGME_DECRYPT_UNWRAP)) if (!err && (flags & GPGME_DECRYPT_UNWRAP))
@ -1840,17 +1849,17 @@ gpg_decrypt (void *engine,
} }
if (!err && export_session_key) 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) 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) 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 (!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); gpgme_data_release (gpg->override_session_key);
TRACE (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n", TRACE (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n",
@ -1880,13 +1889,30 @@ gpg_decrypt (void *engine,
else else
{ {
/* Using that option may leak the session key via ps(1). */ /* Using that option may leak the session key via ps(1). */
err = add_arg (gpg, "--override-session-key"); err = add_gpg_arg_with_value (gpg, "--override-session-key=",
if (!err) override_session_key, 0);
err = add_arg (gpg, override_session_key);
} }
} }
/* Tell the gpg object about the data. */ /* 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) if (!err)
err = add_arg (gpg, "--output"); err = add_arg (gpg, "--output");
if (!err) if (!err)
@ -1899,6 +1925,7 @@ gpg_decrypt (void *engine,
err = add_arg (gpg, "--"); err = add_arg (gpg, "--");
if (!err) if (!err)
err = add_data (gpg, ciph, -1, 0); err = add_data (gpg, ciph, -1, 0);
}
if (!err) if (!err)
err = start (gpg); err = start (gpg);

View File

@ -1426,6 +1426,7 @@ gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx);
typedef enum typedef enum
{ {
GPGME_DECRYPT_VERIFY = 1, GPGME_DECRYPT_VERIFY = 1,
GPGME_DECRYPT_ARCHIVE = 2,
GPGME_DECRYPT_UNWRAP = 128 GPGME_DECRYPT_UNWRAP = 128
} }
gpgme_decrypt_flags_t; gpgme_decrypt_flags_t;

View File

@ -91,6 +91,8 @@ show_usage (int ex)
" --unwrap remove only the encryption layer\n" " --unwrap remove only the encryption layer\n"
" --large-buffers use large I/O buffer\n" " --large-buffers use large I/O buffer\n"
" --sensitive mark data objects as sensitive\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" " --diagnostics print diagnostics\n"
, stderr); , stderr);
exit (ex); exit (ex);
@ -113,6 +115,7 @@ main (int argc, char **argv)
int export_session_key = 0; int export_session_key = 0;
const char *override_session_key = NULL; const char *override_session_key = NULL;
const char *request_origin = NULL; const char *request_origin = NULL;
const char *directory = NULL;
int no_symkey_cache = 0; int no_symkey_cache = 0;
int ignore_mdc_error = 0; int ignore_mdc_error = 0;
int raw_output = 0; int raw_output = 0;
@ -205,6 +208,19 @@ main (int argc, char **argv)
raw_output = 1; raw_output = 1;
argc--; argv++; 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)) else if (!strncmp (*argv, "--", 2))
show_usage (1); show_usage (1);
@ -302,6 +318,16 @@ main (int argc, char **argv)
gpgme_strerror (err)); gpgme_strerror (err));
exit (1); 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) if (large_buffers)
{ {
err = gpgme_data_set_flag (out, "io-buffer-size", "1000000"); err = gpgme_data_set_flag (out, "io-buffer-size", "1000000");