* 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 <wk@gnupg.org>
* Interface changes relative to the 1.11.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc.
* 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.
cpp: DecryptionResult::sessionKey NEW.
cpp: DecryptionResult::symkeyAlgo NEW.
cpp: Data::rewind NEW.
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
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"
effect.
@item "no-symkey-cache"
decryption. This cache is based on the message specific salt value.
Requires at least GnuPG 2.2.7 to have an effect.
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.
@end table
This function returns @code{0} on success.
/* Do not use the symmtric encryption passphrase cache. */
unsigned int no_symkey_cache : 1;
/* 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;
/* Flags for keylist mode. */
gpgme_keylist_mode_t keylist_mode;
err = decrypt_verify_start (ctx, 1, GPGME_DECRYPT_VERIFY, cipher, plain);
if (!err)
err = _gpgme_wait_one (ctx);
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);
}
return TRACE_ERR (err);
}
err = _gpgme_decrypt_start (ctx, 1, flags, cipher, plain);
if (!err)
err = _gpgme_wait_one (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);
}
return TRACE_ERR (err);
}
TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", 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)
err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
opd = hook;
if (err || !opd)
return opd->pkdecrypt_failed;
else if (opd->failed && opd->any_no_seckey)
return gpg_error (GPG_ERR_NO_SECKEY);
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);
return gpg_error (GPG_ERR_DECRYPT_FAILED);
else if (!opd->okay)
return gpg_error (GPG_ERR_NO_DATA);
err = _gpgme_decrypt_start (ctx, 1, 0, cipher, plain);
if (!err)
err = _gpgme_wait_one (ctx);
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);
}
return TRACE_ERR (err);
}
struct {
unsigned int no_symkey_cache : 1;
unsigned int offline : 1;
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. */
} flags;
/* NULL or the data object fed to --override_session_key-fd. */
gpg->flags.no_symkey_cache = (ctx->no_symkey_cache
&& have_gpg_version (gpg, "2.2.7"));
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.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23"));
+ gpg->flags.ignore_mdc_error = !!ctx->ignore_mdc_error;
+
+ 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");
if (gpg->flags.offline)
{
argv[argc] = strdup ("--disable-dirmngr");
{
ctx->no_symkey_cache = abool;
}
{
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);
else
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
{
return ctx->no_symkey_cache? "1":"";
}
{
return ctx->no_symkey_cache? "1":"";
}
+ else if (!strcmp (name, "ignore-mdc-error"))
+ {
+ return ctx->ignore_mdc_error? "1":"";
+ }
" --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"
" --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);
" --unwrap remove only the encryption layer\n"
, stderr);
exit (ex);
const char *override_session_key = NULL;
const char *request_origin = NULL;
int no_symkey_cache = 0;
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)
int raw_output = 0;
if (argc)
no_symkey_cache = 1;
argc--; 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;
else if (!strcmp (*argv, "--unwrap"))
{
flags |= GPGME_DECRYPT_UNWRAP;
err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
if (err)
{
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);
}
gpgme_strerror (err));
exit (1);
}