From 662604c5bcb4e03d3c9ecc670d4f320a2418ebb3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 1 Jun 2018 01:29:20 +0200 Subject: [PATCH] core: New context flag "ignore-mdc-error". * src/context.h (gpgme_context): Add field ignore_mdc_error. * src/gpgme.c (gpgme_set_ctx_flag, gpgme_get_ctx_flag): Set/get it. * src/engine-gpg.c (engine_gpg): Add flags.ignore_mdc_error. (gpg_set_engine_flags): Set it. (build_argv): Pass option to gpg. * src/decrypt.c (_gpgme_decrypt_status_handler): Take care of flag. (gpgme_op_decrypt_result): Clear flag. (gpgme_op_decrypt): Clear flag. * src/decrypt-verify.c (gpgme_op_decrypt_verify): Clear flag (gpgme_op_decrypt_ext): Clear flag. * tests/run-decrypt.c (show_usage): Add option --ignore-mdc-error. Signed-off-by: Werner Koch --- NEWS | 1 + doc/gpgme.texi | 11 ++++++++++- src/context.h | 4 ++++ src/decrypt-verify.c | 2 ++ src/decrypt.c | 6 +++++- src/engine-gpg.c | 17 ++++++++++++++++- src/gpgme.c | 8 ++++++++ tests/run-decrypt.c | 20 +++++++++++++++++++- 8 files changed, 65 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index bc1330ad..4eb3dbeb 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ Noteworthy changes in version 1.11.2 (unreleased) * Interface changes relative to the 1.11.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc. + gpgme_set_ctx_flag EXTENDED: New flag 'ignore-mdc-error'. cpp: DecryptionResult::sessionKey NEW. cpp: DecryptionResult::symkeyAlgo NEW. cpp: Data::rewind NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index d8771167..e3445a0e 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3078,7 +3078,7 @@ the time when you verified the signature. The string given in @var{value} is passed to the GnuPG engines to request restrictions based on the origin of the request. Valid values are documented in the GnuPG manual and the gpg man page under the -option ``--request-origin''. Requires at least GnuPG 2.2.6 to have an +option @option{--request-origin}. Requires at least GnuPG 2.2.6 to have an effect. @item "no-symkey-cache" @@ -3086,6 +3086,15 @@ For OpenPGP disable the passphrase cache used for symmetrical en- and decryption. This cache is based on the message specific salt value. Requires at least GnuPG 2.2.7 to have an effect. +@item "ignore-mdc-error" +This flag passes the option @option{--ignore-mdc-error} to gpg. This +can be used to force decryption of a message which failed due to a +missing integrity check. This flag must be used with great caution +and only if it is a known non-corrupted old message and the decryption +result of the former try had the decryption result flag +@code{legacy_cipher_nomdc} set. For failsafe reasons this flag is +reset after each operation. + @end table This function returns @code{0} on success. diff --git a/src/context.h b/src/context.h index c8e75ba0..bdab6878 100644 --- a/src/context.h +++ b/src/context.h @@ -124,6 +124,10 @@ struct gpgme_context /* Do not use the symmtric encryption passphrase cache. */ unsigned int no_symkey_cache : 1; + /* Pass --ignore-mdc-error to gpg. Note that this flag is reset + * after the operation. */ + unsigned int ignore_mdc_error : 1; + /* Flags for keylist mode. */ gpgme_keylist_mode_t keylist_mode; diff --git a/src/decrypt-verify.c b/src/decrypt-verify.c index ce4a7a9b..1bd81c31 100644 --- a/src/decrypt-verify.c +++ b/src/decrypt-verify.c @@ -127,6 +127,7 @@ gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher, err = decrypt_verify_start (ctx, 1, GPGME_DECRYPT_VERIFY, cipher, plain); if (!err) err = _gpgme_wait_one (ctx); + ctx->ignore_mdc_error = 0; /* Always reset. */ return TRACE_ERR (err); } @@ -177,5 +178,6 @@ gpgme_op_decrypt_ext (gpgme_ctx_t ctx, err = _gpgme_decrypt_start (ctx, 1, flags, cipher, plain); if (!err) err = _gpgme_wait_one (ctx); + ctx->ignore_mdc_error = 0; /* Always reset. */ return TRACE_ERR (err); } diff --git a/src/decrypt.c b/src/decrypt.c index f2278d8d..8c95ebed 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -97,6 +97,8 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx) TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx); + ctx->ignore_mdc_error = 0; /* Always reset this flag. */ + err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL); opd = hook; if (err || !opd) @@ -362,7 +364,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, return opd->pkdecrypt_failed; else if (opd->failed && opd->any_no_seckey) return gpg_error (GPG_ERR_NO_SECKEY); - else if (opd->failed || opd->not_integrity_protected) + else if (opd->failed || (opd->not_integrity_protected + && !ctx->ignore_mdc_error)) return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); @@ -564,5 +567,6 @@ gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain) err = _gpgme_decrypt_start (ctx, 1, 0, cipher, plain); if (!err) err = _gpgme_wait_one (ctx); + ctx->ignore_mdc_error = 0; /* Always reset. */ return TRACE_ERR (err); } diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 43d49fe6..802af08d 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -144,6 +144,7 @@ struct engine_gpg struct { unsigned int no_symkey_cache : 1; unsigned int offline : 1; + unsigned int ignore_mdc_error : 1; } flags; /* NULL or the data object fed to --override_session_key-fd. */ @@ -646,9 +647,10 @@ gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx) gpg->flags.no_symkey_cache = (ctx->no_symkey_cache && have_gpg_version (gpg, "2.2.7")); - gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23")); + gpg->flags.ignore_mdc_error = !!ctx->ignore_mdc_error; + } @@ -955,6 +957,19 @@ build_argv (engine_gpg_t gpg, const char *pgmname) argc++; } + if (gpg->flags.ignore_mdc_error) + { + argv[argc] = strdup ("--ignore-mdc-error"); + if (!argv[argc]) + { + int saved_err = gpg_error_from_syserror (); + free (fd_data_map); + free_argv (argv); + return saved_err; + } + argc++; + } + if (gpg->flags.offline) { argv[argc] = strdup ("--disable-dirmngr"); diff --git a/src/gpgme.c b/src/gpgme.c index 82d67478..b03c7b87 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -542,6 +542,10 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) { ctx->no_symkey_cache = abool; } + else if (!strcmp (name, "ignore-mdc-error")) + { + ctx->ignore_mdc_error = abool; + } else err = gpg_error (GPG_ERR_UNKNOWN_NAME); @@ -591,6 +595,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name) { return ctx->no_symkey_cache? "1":""; } + else if (!strcmp (name, "ignore-mdc-error")) + { + return ctx->ignore_mdc_error? "1":""; + } else return NULL; } diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index 8ec0cb4f..99a15c7e 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -86,6 +86,7 @@ show_usage (int ex) " --override-session-key STRING use STRING as session key\n" " --request-origin STRING use STRING as request origin\n" " --no-symkey-cache disable the use of that cache\n" + " --ignore-mdc-error allow decryption of legacy data\n" " --unwrap remove only the encryption layer\n" , stderr); exit (ex); @@ -109,6 +110,7 @@ main (int argc, char **argv) const char *override_session_key = NULL; const char *request_origin = NULL; int no_symkey_cache = 0; + int ignore_mdc_error = 0; int raw_output = 0; if (argc) @@ -170,6 +172,11 @@ main (int argc, char **argv) no_symkey_cache = 1; argc--; argv++; } + else if (!strcmp (*argv, "--ignore-mdc-error")) + { + ignore_mdc_error = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--unwrap")) { flags |= GPGME_DECRYPT_UNWRAP; @@ -241,7 +248,18 @@ main (int argc, char **argv) err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1"); if (err) { - fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n", + fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n", + gpgme_strerror (err)); + exit (1); + } + } + + if (ignore_mdc_error) + { + err = gpgme_set_ctx_flag (ctx, "ignore-mdc-error", "1"); + if (err) + { + fprintf (stderr, PGM ": error setting ignore-mdc-error: %s\n", gpgme_strerror (err)); exit (1); }