diff --git a/NEWS b/NEWS index 81bd564a..e9e2ed28 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +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] + * Extended gpgme_op_encrypt*, gpgme_op_encrypt_sign*, and gpgme_op_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. + GPGME_SIG_MODE_FILE NEW. Noteworthy changes in version 1.23.2 (2023-11-28) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 0ec70a55..e7a568a3 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -6366,6 +6366,16 @@ A signed archive is created from the given files and directories. This feature is currently only supported for the OpenPGP crypto engine and requires GnuPG 2.4.1. +@item GPGME_SIG_MODE_FILE +@since{1.24.0} + +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 flag can be +combined with @code{GPGME_SIG_MODE_NORMAL}, @code{GPGME_SIG_MODE_DETACH}, +and @code{GPGME_SIG_MODE_CLEAR}, but not with @code{GPGME_SIG_MODE_ARCHIVE}. +This feature is currently only supported for the OpenPGP crypto engine. + @end table @end deftp @@ -6379,7 +6389,12 @@ if that is not set, by the encoding specified for @var{sig}), the text mode attributes set for the context @var{ctx} and the requested signature mode @var{mode}. -If signature mode @code{GPGME_SIG_MODE_ARCHIVE} is requested, then a +If the signature mode flag @code{GPGME_SIG_MODE_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 signature mode @code{GPGME_SIG_MODE_ARCHIVE} is requested then a signed archive is created from the files and directories given as NUL-separated list in the data object @var{plain}. The paths of the files and directories have to be given as paths relative to the current working diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 123760be..cc249e7b 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -3615,25 +3615,32 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, { engine_gpg_t gpg = engine; gpgme_error_t err; - const char *output = NULL; + const char *file_name = NULL; + unsigned int mode = flags & (GPGME_SIG_MODE_NORMAL + |GPGME_SIG_MODE_DETACH + |GPGME_SIG_MODE_CLEAR + |GPGME_SIG_MODE_ARCHIVE); (void)include_certs; - if ((flags != GPGME_SIG_MODE_NORMAL) && (flags != GPGME_SIG_MODE_DETACH) - && (flags != GPGME_SIG_MODE_CLEAR) && (flags != GPGME_SIG_MODE_ARCHIVE)) + if ((mode != GPGME_SIG_MODE_NORMAL) && (mode != GPGME_SIG_MODE_DETACH) + && (mode != GPGME_SIG_MODE_CLEAR) && (mode != GPGME_SIG_MODE_ARCHIVE)) return gpg_error (GPG_ERR_INV_VALUE); - gpg->flags.use_gpgtar = !!(flags & GPGME_SIG_MODE_ARCHIVE); + gpg->flags.use_gpgtar = !!(mode == GPGME_SIG_MODE_ARCHIVE); if (gpg->flags.use_gpgtar && !have_usable_gpgtar (gpg)) return gpg_error (GPG_ERR_NOT_SUPPORTED); - if (flags & GPGME_SIG_MODE_CLEAR) + if (gpg->flags.use_gpgtar && (flags & GPGME_SIG_MODE_FILE)) + return gpg_error (GPG_ERR_INV_VALUE); + + if (mode == GPGME_SIG_MODE_CLEAR) err = add_arg (gpg, "--clearsign"); else { err = add_arg (gpg, "--sign"); - if (!err && (flags & GPGME_SIG_MODE_DETACH)) + if (!err && (mode == GPGME_SIG_MODE_DETACH)) err = add_arg (gpg, "--detach"); if (!err && use_armor) err = add_gpg_arg (gpg, "--armor"); @@ -3656,21 +3663,25 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (!err) err = append_args_from_sig_notations (gpg, ctx, NOTATION_FLAG_SIG); + if (!err) + err = add_arg (gpg, "--output"); if (!err) { - output = gpgme_data_get_file_name (out); + const char *output = gpgme_data_get_file_name (out); if (output) + err = add_arg (gpg, output); + else { - err = add_arg (gpg, "--output"); + err = add_arg (gpg, "-"); if (!err) - err = add_arg (gpg, output); + err = add_data (gpg, out, 1, 1); } } - + if (!err) + file_name = gpgme_data_get_file_name (in); /* Tell the gpg object about the data. */ if (gpg->flags.use_gpgtar) { - const char *file_name = gpgme_data_get_file_name (in); if (!err && file_name) { err = add_arg (gpg, "--directory"); @@ -3689,9 +3700,17 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (!err) err = add_data (gpg, in, 0, 0); } + else if (flags & GPGME_SIG_MODE_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 (in); if (!err && file_name) err = add_gpg_arg_with_value (gpg, "--set-filename=", file_name, 0); if (!err) @@ -3702,9 +3721,6 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, err = add_data (gpg, in, -1, 0); } - if (!err && !output) - err = add_data (gpg, out, 1, 1); - if (!err) err = start (gpg); diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 014507d4..fa89ae3f 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -2128,7 +2128,9 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - if (flags & (GPGME_SIG_MODE_CLEAR | GPGME_SIG_MODE_ARCHIVE)) + if (flags & (GPGME_SIG_MODE_CLEAR + | GPGME_SIG_MODE_ARCHIVE + | GPGME_SIG_MODE_FILE)) return gpg_error (GPG_ERR_INV_VALUE); /* FIXME: This does not work as RESET does not reset it so we can't diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index a116feb9..3e9836af 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1237,7 +1237,9 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out, else return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL); - if (flags & (GPGME_SIG_MODE_CLEAR | GPGME_SIG_MODE_ARCHIVE)) + if (flags & (GPGME_SIG_MODE_CLEAR + | GPGME_SIG_MODE_ARCHIVE + | GPGME_SIG_MODE_FILE)) return gpg_error (GPG_ERR_INV_VALUE); if (gpgrt_asprintf (&cmd, "SIGN%s%s", protocol, diff --git a/src/gpgme.h.in b/src/gpgme.h.in index ccc7b026..c8eba0a5 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -309,7 +309,8 @@ typedef enum GPGME_SIG_MODE_NORMAL = 0, GPGME_SIG_MODE_DETACH = 1, GPGME_SIG_MODE_CLEAR = 2, - GPGME_SIG_MODE_ARCHIVE = 4 + GPGME_SIG_MODE_ARCHIVE = 4, + GPGME_SIG_MODE_FILE = 8 } gpgme_sig_mode_t; diff --git a/src/sign.c b/src/sign.c index 1563c1dd..56b2d5fb 100644 --- a/src/sign.c +++ b/src/sign.c @@ -450,7 +450,8 @@ sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain, if (flags & ~(GPGME_SIG_MODE_DETACH |GPGME_SIG_MODE_CLEAR - |GPGME_SIG_MODE_ARCHIVE)) + |GPGME_SIG_MODE_ARCHIVE + |GPGME_SIG_MODE_FILE)) return gpg_error (GPG_ERR_INV_VALUE); if (!plain) diff --git a/tests/run-sign.c b/tests/run-sign.c index 07482dd5..c04fa819 100644 --- a/tests/run-sign.c +++ b/tests/run-sign.c @@ -87,6 +87,8 @@ show_usage (int ex) " --sender MBOX use MBOX as sender address\n" " --include-key-block use this option with gpg\n" " --clear create a clear text signature\n" + " --detach create a detached signature\n" + " --direct-file-io pass FILE instead of stream with content of FILE to backend\n" " --archive create a signed archive with the given file or directory\n" " --directory DIR switch to directory DIR before creating the archive\n" " --output FILE write output to FILE instead of stdout\n" @@ -113,6 +115,7 @@ main (int argc, char **argv) int use_loopback = 0; int include_key_block = 0; int diagnostics = 0; + int direct_file_io = 0; const char *sender = NULL; const char *s; @@ -185,6 +188,16 @@ main (int argc, char **argv) sigmode = GPGME_SIG_MODE_CLEAR; argc--; argv++; } + else if (!strcmp (*argv, "--detach")) + { + sigmode = GPGME_SIG_MODE_DETACH; + argc--; argv++; + } + else if (!strcmp (*argv, "--direct-file-io")) + { + direct_file_io = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--archive")) { sigmode = GPGME_SIG_MODE_ARCHIVE; @@ -269,7 +282,15 @@ main (int argc, char **argv) } } - if (sigmode == GPGME_SIG_MODE_ARCHIVE) + if (direct_file_io) + { + sigmode |= GPGME_SIG_MODE_FILE; + err = gpgme_data_new (&in); + fail_if_err (err); + err = gpgme_data_set_file_name (in, *argv); + fail_if_err (err); + } + else if (sigmode == GPGME_SIG_MODE_ARCHIVE) { const char *path = *argv; err = gpgme_data_new_from_mem (&in, path, strlen (path), 0);