core: New context flag "ignore-mdc-error".
authorWerner Koch <wk@gnupg.org>
Thu, 31 May 2018 23:29:20 +0000 (01:29 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 31 May 2018 23:29:34 +0000 (01:29 +0200)
* 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>
NEWS
doc/gpgme.texi
src/context.h
src/decrypt-verify.c
src/decrypt.c
src/engine-gpg.c
src/gpgme.c
tests/run-decrypt.c

diff --git a/NEWS b/NEWS
index bc1330a..4eb3dbe 100644 (file)
--- 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.
index d877116..e3445a0 100644 (file)
@@ -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.
index c8e75ba..bdab687 100644 (file)
@@ -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;
 
index ce4a7a9..1bd81c3 100644 (file)
@@ -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);
 }
index f2278d8..8c95ebe 100644 (file)
@@ -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);
 }
index 43d49fe..802af08 100644 (file)
@@ -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");
index 82d6747..b03c7b8 100644 (file)
@@ -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;
 }
index 8ec0cb4..99a15c7 100644 (file)
@@ -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);
         }