core: Support direct encryption of file with gpg

* src/gpgme.h.in (GPGME_ENCRYPT_FILE): New encryption flag.
* src/engine-gpg.c (gpg_encrypt, gpg_encrypt_sign): Check for
incompatible flags. Pass filename instead of fd to gpg when new flag is
set.
* src/engine-gpgsm.c (gpgsm_encrypt): Return error if new flag is set.
* src/engine-uiserver.c (uiserver_encrypt): Ditto.

* tests/run-encrypt.c (show_usage): New option --direct-file-io.
(main): Parse new option. Make gpg read the input file itself if the
option is given.
--

With this change the gpgme_op_encrypt* and gpgme_op_encrypt_sign*
functions gain the possibility to make gpg read the data to (sign and)
encrypt directly from a file instead of from an input FD to which it is
written by gpgme.

GnuPG-bug-id: 6550
This commit is contained in:
Ingo Klöcker 2023-12-14 10:59:47 +01:00
parent b35bcf0040
commit 0221d7f28a
No known key found for this signature in database
GPG Key ID: F5A5D1692277A1E9
7 changed files with 73 additions and 8 deletions

7
NEWS
View File

@ -1,6 +1,13 @@
Noteworthy changes in version 1.23.3 (unrelease)
-------------------------------------------------
* Extended gpgme_op_encrypt* and gpgme_op_encrypt_sign* to allow reading
the input data directly from a file. [T6550]
* Interface changes relative to the 1.23.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_ENCRYPT_FILE NEW.
Noteworthy changes in version 1.23.2 (2023-11-28)
-------------------------------------------------

View File

@ -6557,7 +6557,14 @@ file set with @code{gpgme_data_set_file_name} for the data object
@var{cipher}. The type of the ciphertext created is determined by the
@acronym{ASCII} armor (or, if that is not set, by the encoding specified
for @var{cipher}) and the text mode attributes set for the context
@var{ctx}.
@var{ctx}. If a filename has been set with @code{gpgme_data_set_file_name}
for the data object @var{plain} then this filename is stored in the
ciphertext.
If the flag @code{GPGME_ENCRYPT_FILE} is set and a filename has been set
with @code{gpgme_data_set_file_name} for the data object @var{plain},
then this filename is passed to gpg, so that gpg reads the plaintext
directly from this file instead of from the data object @var{plain}.
If the flag @code{GPGME_ENCRYPT_ARCHIVE} is set, then an encrypted
archive is created from the files and directories given as NUL-separated
@ -6653,6 +6660,15 @@ NUL-separated list of file paths and directory paths that shall be
encrypted into an archive. This feature is currently only supported
for the OpenPGP crypto engine and requires GnuPG 2.4.1.
@item GPGME_ENCRYPT_FILE
@since{1.24.0}
The @code{GPGME_ENCRYPT_FILE} symbol specifies that the filename set
with @code{gpgme_data_set_file_name} for the data object @var{plain}
is passed to gpg, so that gpg reads the plaintext directly from this
file instead of from the data object @var{plain}. This feature is
currently only supported for the OpenPGP crypto engine.
@end table
If @code{GPG_ERR_UNUSABLE_PUBKEY} is returned, some recipients in

View File

@ -2317,12 +2317,16 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
{
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
const char *file_name = NULL;
gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE);
if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (gpg->flags.use_gpgtar && (flags & GPGME_ENCRYPT_FILE))
return gpg_error (GPG_ERR_INV_VALUE);
if (gpg->flags.use_gpgtar && (flags & GPGME_ENCRYPT_WRAP))
return gpg_error (GPG_ERR_INV_VALUE);
@ -2390,9 +2394,10 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
err = add_data (gpg, ciph, 1, 1);
}
}
if (!err)
file_name = gpgme_data_get_file_name (plain);
if (gpg->flags.use_gpgtar)
{
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name)
{
err = add_arg (gpg, "--directory");
@ -2411,9 +2416,17 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
if (!err)
err = add_data (gpg, plain, 0, 0);
}
else if (flags & GPGME_ENCRYPT_FILE)
{
if (!err)
err = add_arg (gpg, "--");
if (!err && (!file_name || !*file_name))
err = gpg_error (GPG_ERR_INV_VALUE);
if (!err)
err = add_arg (gpg, file_name);
}
else
{
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name)
err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0);
if (!err)
@ -2440,12 +2453,16 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
{
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
const char *file_name = NULL;
gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE);
if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (gpg->flags.use_gpgtar && (flags & GPGME_ENCRYPT_FILE))
return gpg_error (GPG_ERR_INV_VALUE);
if (recp || recpstring)
err = add_arg (gpg, "--encrypt");
@ -2510,9 +2527,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
err = add_data (gpg, ciph, 1, 1);
}
}
if (!err)
file_name = gpgme_data_get_file_name (plain);
if (gpg->flags.use_gpgtar)
{
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name)
{
err = add_arg (gpg, "--directory");
@ -2531,9 +2549,17 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err)
err = add_data (gpg, plain, 0, 0);
}
else if (flags & GPGME_ENCRYPT_FILE)
{
if (!err)
err = add_arg (gpg, "--");
if (!err && (!file_name || !*file_name))
err = gpg_error (GPG_ERR_INV_VALUE);
if (!err)
err = add_arg (gpg, file_name);
}
else
{
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name)
err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0);
if (!err)

View File

@ -1536,7 +1536,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
if (!recp && !recpstring) /* Symmetric only */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if (flags & GPGME_ENCRYPT_ARCHIVE)
if (flags & (GPGME_ENCRYPT_ARCHIVE | GPGME_ENCRYPT_FILE))
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))

View File

@ -1145,7 +1145,7 @@ uiserver_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
else
return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
if (flags & GPGME_ENCRYPT_ARCHIVE)
if (flags & (GPGME_ENCRYPT_ARCHIVE | GPGME_ENCRYPT_FILE))
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if (flags & GPGME_ENCRYPT_PREPARE)

View File

@ -1326,7 +1326,8 @@ typedef enum
GPGME_ENCRYPT_THROW_KEYIDS = 64,
GPGME_ENCRYPT_WRAP = 128,
GPGME_ENCRYPT_WANT_ADDRESS = 256,
GPGME_ENCRYPT_ARCHIVE = 512
GPGME_ENCRYPT_ARCHIVE = 512,
GPGME_ENCRYPT_FILE = 1024
}
gpgme_encrypt_flags_t;

View File

@ -151,6 +151,7 @@ show_usage (int ex)
" --no-symkey-cache disable the use of that cache\n"
" --wrap assume input is valid OpenPGP message\n"
" --symmetric encrypt symmetric (OpenPGP only)\n"
" --direct-file-io pass FILE instead of stream with content of FILE to backend\n"
" --archive encrypt given file or directory into an archive\n"
" --directory DIR switch to directory DIR before encrypting into an archive\n"
" --output FILE write output to FILE instead of stdout\n"
@ -186,6 +187,7 @@ main (int argc, char **argv)
int no_symkey_cache = 0;
int diagnostics = 0;
int sign = 0;
int direct_file_io = 0;
if (argc)
{ argc--; argv++; }
@ -289,6 +291,11 @@ main (int argc, char **argv)
no_symkey_cache = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--direct-file-io"))
{
direct_file_io = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--archive"))
{
flags |= GPGME_ENCRYPT_ARCHIVE;
@ -378,6 +385,14 @@ main (int argc, char **argv)
fail_if_err (err);
}
}
else if (direct_file_io)
{
flags |= GPGME_ENCRYPT_FILE;
err = gpgme_data_new (&in);
fail_if_err (err);
err = gpgme_data_set_file_name (in, *argv);
fail_if_err (err);
}
else
{
err = gpgme_data_new_from_file (&in, *argv, 1);