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) 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) 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 @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 @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 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 If the flag @code{GPGME_ENCRYPT_ARCHIVE} is set, then an encrypted
archive is created from the files and directories given as NUL-separated 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 encrypted into an archive. This feature is currently only supported
for the OpenPGP crypto engine and requires GnuPG 2.4.1. 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 @end table
If @code{GPG_ERR_UNUSABLE_PUBKEY} is returned, some recipients in 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; engine_gpg_t gpg = engine;
gpgme_error_t err = 0; gpgme_error_t err = 0;
const char *file_name = NULL;
gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE); gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE);
if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg)) if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg))
return gpg_error (GPG_ERR_NOT_SUPPORTED); 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)) if (gpg->flags.use_gpgtar && (flags & GPGME_ENCRYPT_WRAP))
return gpg_error (GPG_ERR_INV_VALUE); 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); err = add_data (gpg, ciph, 1, 1);
} }
} }
if (!err)
file_name = gpgme_data_get_file_name (plain);
if (gpg->flags.use_gpgtar) if (gpg->flags.use_gpgtar)
{ {
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name) if (!err && file_name)
{ {
err = add_arg (gpg, "--directory"); err = add_arg (gpg, "--directory");
@ -2411,9 +2416,17 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
if (!err) if (!err)
err = add_data (gpg, plain, 0, 0); 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 else
{ {
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name) if (!err && file_name)
err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0); err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0);
if (!err) if (!err)
@ -2440,12 +2453,16 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
{ {
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err = 0; gpgme_error_t err = 0;
const char *file_name = NULL;
gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE); gpg->flags.use_gpgtar = !!(flags & GPGME_ENCRYPT_ARCHIVE);
if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg)) if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg))
return gpg_error (GPG_ERR_NOT_SUPPORTED); 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) if (recp || recpstring)
err = add_arg (gpg, "--encrypt"); 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); err = add_data (gpg, ciph, 1, 1);
} }
} }
if (!err)
file_name = gpgme_data_get_file_name (plain);
if (gpg->flags.use_gpgtar) if (gpg->flags.use_gpgtar)
{ {
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name) if (!err && file_name)
{ {
err = add_arg (gpg, "--directory"); err = add_arg (gpg, "--directory");
@ -2531,9 +2549,17 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err) if (!err)
err = add_data (gpg, plain, 0, 0); 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 else
{ {
const char *file_name = gpgme_data_get_file_name (plain);
if (!err && file_name) if (!err && file_name)
err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0); err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0);
if (!err) if (!err)

View File

@ -1536,7 +1536,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
if (!recp && !recpstring) /* Symmetric only */ if (!recp && !recpstring) /* Symmetric only */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED); 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); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)) 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 else
return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL); 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); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if (flags & GPGME_ENCRYPT_PREPARE) if (flags & GPGME_ENCRYPT_PREPARE)

View File

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

View File

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