Patch-Source: https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=patch;h=2f872fa68c6576724b9dabee9fb0844266f55d0d
https://dev.gnupg.org/rG2f872fa68c6576724b9dabee9fb0844266f55d0d
--
From 2f872fa68c6576724b9dabee9fb0844266f55d0d Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Wed, 24 May 2023 10:36:04 +0900
Subject: [PATCH] gpg: Report BEGIN_* status before examining the input.

* common/miscellaneous.c (is_openpgp_compressed_packet)
(is_file_compressed): Moved to ...
* common/iobuf.c: ... in this file.
(is_file_compressed): Change the argument to INP, the iobuf.
* common/util.h (is_file_compressed): Remove.
* common/iobuf.h (is_file_compressed): Add.
* g10/cipher-aead.c (write_header): Don't call write_status_printf
here.
(cipher_filter_aead): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/cipher-cfb.c (write_header): Don't call write_status_printf
here.
(cipher_filter_cfb): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/encrypt.c (encrypt_simple): Use new is_file_compressed function,
after call of iobuf_push_filter.
(encrypt_crypt): Likewise.
* g10/sign.c (sign_file): Likewise.

--

GnuPG-bug-id: 6481
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
---
 common/iobuf.c         | 120 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/iobuf.h         |   3 ++
 common/miscellaneous.c | 106 -------------------------------------------
 common/util.h          |   2 -
 g10/cipher-aead.c      |   7 ++-
 g10/cipher-cfb.c       |   9 ++--
 g10/encrypt.c          | 103 ++++++++++++++++--------------------------
 g10/sign.c             |  13 +-----
 8 files changed, 174 insertions(+), 189 deletions(-)

diff --git a/common/iobuf.c b/common/iobuf.c
index 62cde27f9..e088812a6 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -3057,3 +3057,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
 	}
     }
 }
+
+
+/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
+ * packet.  LEN should be at least 6.  */
+static int
+is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
+{
+  int c, ctb, pkttype;
+  int lenbytes;
+
+  ctb = *buf++; len--;
+  if (!(ctb & 0x80))
+    return 0; /* Invalid packet.  */
+
+  if ((ctb & 0x40)) /* New style (OpenPGP) CTB.  */
+    {
+      pkttype = (ctb & 0x3f);
+      if (!len)
+        return 0; /* Expected first length octet missing.  */
+      c = *buf++; len--;
+      if (c < 192)
+        ;
+      else if (c < 224)
+        {
+          if (!len)
+            return 0; /* Expected second length octet missing. */
+        }
+      else if (c == 255)
+        {
+          if (len < 4)
+            return 0; /* Expected length octets missing */
+        }
+    }
+  else /* Old style CTB.  */
+    {
+      pkttype = (ctb>>2)&0xf;
+      lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+      if (len < lenbytes)
+        return 0; /* Not enough length bytes.  */
+    }
+
+  return (pkttype == 8);
+}
+
+
+/*
+ * Check if the file is compressed, by peeking the iobuf.  You need to
+ * pass the iobuf with INP.  Returns true if the buffer seems to be
+ * compressed.
+ */
+int
+is_file_compressed (iobuf_t inp)
+{
+  int i;
+  char buf[32];
+  int buflen;
+
+  struct magic_compress_s
+  {
+    byte len;
+    byte extchk;
+    byte magic[5];
+  } magic[] =
+      {
+       { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
+       { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
+       { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
+       { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
+       { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
+       { 5, 2, { 0x89, 'P','N','G', 0x0d} }  /* Likely PNG */
+  };
+
+  if (!inp)
+    return 0;
+
+  for ( ; inp->chain; inp = inp->chain )
+    ;
+
+  buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf);
+  if (buflen < 0)
+    {
+      buflen = 0;
+      log_debug ("peeking at input failed\n");
+    }
+
+  if ( buflen < 6 )
+    {
+      return 0;  /* Too short to check - assume uncompressed.  */
+    }
+
+  for ( i = 0; i < DIM (magic); i++ )
+    {
+      if (!memcmp( buf, magic[i].magic, magic[i].len))
+        {
+          switch (magic[i].extchk)
+            {
+            case 0:
+              return 1; /* Is compressed.  */
+            case 1:
+              if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
+                return 1; /* JFIF: this likely a compressed JPEG.  */
+              break;
+            case 2:
+              if (buflen > 8
+                  && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
+                return 1; /* This is a PNG.  */
+              break;
+            default:
+              break;
+            }
+        }
+    }
+
+  if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
+    {
+      return 1; /* Already compressed.  */
+    }
+
+  return 0;  /* Not detected as compressed.  */
+}
diff --git a/common/iobuf.h b/common/iobuf.h
index c132c2f3c..ad416fe86 100644
--- a/common/iobuf.h
+++ b/common/iobuf.h
@@ -629,6 +629,9 @@ void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
    from the following filter (which may or may not return EOF).  */
 void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
 
+/* Check if the file is compressed, by peeking the iobuf.  */
+int is_file_compressed (iobuf_t inp);
+
 #define iobuf_where(a)	"[don't know]"
 
 /* Each time a filter is allocated (via iobuf_alloc()), a
diff --git a/common/miscellaneous.c b/common/miscellaneous.c
index f19cc539d..1a090b1f5 100644
--- a/common/miscellaneous.c
+++ b/common/miscellaneous.c
@@ -415,112 +415,6 @@ decode_c_string (const char *src)
 }
 
 
-/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
- * packet.  LEN should be at least 6.  */
-static int
-is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
-{
-  int c, ctb, pkttype;
-  int lenbytes;
-
-  ctb = *buf++; len--;
-  if (!(ctb & 0x80))
-    return 0; /* Invalid packet.  */
-
-  if ((ctb & 0x40)) /* New style (OpenPGP) CTB.  */
-    {
-      pkttype = (ctb & 0x3f);
-      if (!len)
-        return 0; /* Expected first length octet missing.  */
-      c = *buf++; len--;
-      if (c < 192)
-        ;
-      else if (c < 224)
-        {
-          if (!len)
-            return 0; /* Expected second length octet missing. */
-        }
-      else if (c == 255)
-        {
-          if (len < 4)
-            return 0; /* Expected length octets missing */
-        }
-    }
-  else /* Old style CTB.  */
-    {
-      pkttype = (ctb>>2)&0xf;
-      lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
-      if (len < lenbytes)
-        return 0; /* Not enough length bytes.  */
-    }
-
-  return (pkttype == 8);
-}
-
-
-
-/*
- * Check if the file is compressed.  You need to pass the first bytes
- * of the file as (BUF,BUFLEN).  Returns true if the buffer seems to
- * be compressed.
- */
-int
-is_file_compressed (const byte *buf, unsigned int buflen)
-{
-  int i;
-
-  struct magic_compress_s
-  {
-    byte len;
-    byte extchk;
-    byte magic[5];
-  } magic[] =
-      {
-       { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
-       { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
-       { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
-       { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
-       { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
-       { 5, 2, { 0x89, 'P','N','G', 0x0d} }  /* Likely PNG */
-  };
-
-  if ( buflen < 6 )
-    {
-      return 0;  /* Too short to check - assume uncompressed.  */
-    }
-
-  for ( i = 0; i < DIM (magic); i++ )
-    {
-      if (!memcmp( buf, magic[i].magic, magic[i].len))
-        {
-          switch (magic[i].extchk)
-            {
-            case 0:
-              return 1; /* Is compressed.  */
-            case 1:
-              if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
-                return 1; /* JFIF: this likely a compressed JPEG.  */
-              break;
-            case 2:
-              if (buflen > 8
-                  && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
-                return 1; /* This is a PNG.  */
-              break;
-            default:
-              break;
-            }
-        }
-    }
-
-  if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
-    {
-      return 1; /* Already compressed.  */
-    }
-
-  return 0;  /* Not detected as compressed.  */
-}
-
-
 /* Try match against each substring of multistr, delimited by | */
 int
 match_multistr (const char *multistr,const char *match)
diff --git a/common/util.h b/common/util.h
index aa24e39e6..6b948510e 100644
--- a/common/util.h
+++ b/common/util.h
@@ -360,8 +360,6 @@ char *try_make_printable_string (const void *p, size_t n, int delim);
 char *make_printable_string (const void *p, size_t n, int delim);
 char *decode_c_string (const char *src);
 
-int is_file_compressed (const byte *buf, unsigned int buflen);
-
 int match_multistr (const char *multistr,const char *match);
 
 int gnupg_compare_version (const char *a, const char *b);
diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
index 640d8432f..0c07e65de 100644
--- a/g10/cipher-aead.c
+++ b/g10/cipher-aead.c
@@ -174,8 +174,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
     log_debug ("aead packet: len=%lu extralen=%d\n",
                (unsigned long)ed.len, ed.extralen);
 
-  write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
-                       cfx->dek->algo, ed.aead_algo);
   print_cipher_algo_note (cfx->dek->algo);
 
   if (build_packet( a, &pkt))
@@ -488,6 +486,11 @@ cipher_filter_aead (void *opaque, int control,
     {
       mem2str (buf, "cipher_filter_aead", *ret_len);
     }
+  else if (control == IOBUFCTRL_INIT)
+    {
+      write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
+                           cfx->dek->algo, cfx->dek->use_aead);
+    }
 
   return rc;
 }
diff --git a/g10/cipher-cfb.c b/g10/cipher-cfb.c
index 3ba8eb738..29bf2477c 100644
--- a/g10/cipher-cfb.c
+++ b/g10/cipher-cfb.c
@@ -72,9 +72,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
       log_info (_("Hint: Do not use option %s\n"), "--rfc2440");
     }
 
-  write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d",
-                       ed.mdc_method, cfx->dek->algo);
-
   init_packet (&pkt);
   pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
   pkt.pkt.encrypted = &ed;
@@ -182,6 +179,12 @@ cipher_filter_cfb (void *opaque, int control,
     {
       mem2str (buf, "cipher_filter_cfb", *ret_len);
     }
+  else if (control == IOBUFCTRL_INIT)
+    {
+      write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d",
+                           cfx->dek->use_mdc ? DIGEST_ALGO_SHA1 : 0,
+                           cfx->dek->algo);
+    }
 
   return rc;
 }
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 687b4344e..a524326bb 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -410,8 +410,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   text_filter_context_t tfx;
   progress_filter_context_t *pfx;
   int do_compress = !!default_compress_algo();
-  char peekbuf[32];
-  int  peekbuflen;
 
   if (!gnupg_rng_is_compliant (opt.compliance))
     {
@@ -448,14 +446,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
       return rc;
     }
 
-  peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
-  if (peekbuflen < 0)
-    {
-      peekbuflen = 0;
-      if (DBG_FILTER)
-        log_debug ("peeking at input failed\n");
-    }
-
   handle_progress (pfx, inp, filename);
 
   if (opt.textmode)
@@ -517,17 +507,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
                  /**/             : "CFB");
     }
 
-  if (do_compress
-      && cfx.dek
-      && (cfx.dek->use_mdc || cfx.dek->use_aead)
-      && !opt.explicit_compress_option
-      && is_file_compressed (peekbuf, peekbuflen))
-    {
-      if (opt.verbose)
-        log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
-      do_compress = 0;
-    }
-
   if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out )))
     {
       iobuf_cancel (inp);
@@ -598,6 +577,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   else
     filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
 
+  /* Register the cipher filter. */
+  if (mode)
+    iobuf_push_filter (out,
+                       cfx.dek->use_aead? cipher_filter_aead
+                       /**/             : cipher_filter_cfb,
+                       &cfx );
+
+  if (do_compress
+      && cfx.dek
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
+      && !opt.explicit_compress_option
+      && is_file_compressed (inp))
+    {
+      if (opt.verbose)
+        log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
+      do_compress = 0;
+    }
+
   if (!opt.no_literal)
     {
       /* Note that PT has been initialized above in !no_literal mode.  */
@@ -617,13 +614,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
       pkt.pkt.generic = NULL;
     }
 
-  /* Register the cipher filter. */
-  if (mode)
-    iobuf_push_filter (out,
-                       cfx.dek->use_aead? cipher_filter_aead
-                       /**/             : cipher_filter_cfb,
-                       &cfx );
-
   /* Register the compress filter. */
   if ( do_compress )
     {
@@ -783,7 +773,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   PKT_plaintext *pt = NULL;
   DEK *symkey_dek = NULL;
   STRING2KEY *symkey_s2k = NULL;
-  int rc = 0, rc2 = 0;
+  int rc = 0;
   u32 filesize;
   cipher_filter_context_t cfx;
   armor_filter_context_t *afx = NULL;
@@ -792,8 +782,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   progress_filter_context_t *pfx;
   PK_LIST pk_list;
   int do_compress;
-  char peekbuf[32];
-  int  peekbuflen;
 
   if (filefd != -1 && filename)
     return gpg_error (GPG_ERR_INV_ARG);  /* Both given.  */
@@ -866,14 +854,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   if (opt.verbose)
     log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp));
 
-  peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
-  if (peekbuflen < 0)
-    {
-      peekbuflen = 0;
-      if (DBG_FILTER)
-        log_debug ("peeking at input failed\n");
-    }
-
   handle_progress (pfx, inp, filename);
 
   if (opt.textmode)
@@ -900,25 +880,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   if (!cfx.dek->use_aead)
     cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);
 
-  /* Only do the is-file-already-compressed check if we are using a
-   * MDC or AEAD.  This forces compressed files to be re-compressed if
-   * we do not have a MDC to give some protection against chosen
-   * ciphertext attacks. */
-  if (do_compress
-      && (cfx.dek->use_mdc || cfx.dek->use_aead)
-      && !opt.explicit_compress_option
-      && is_file_compressed (peekbuf, peekbuflen))
-    {
-      if (opt.verbose)
-        log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
-      do_compress = 0;
-    }
-  if (rc2)
-    {
-      rc = rc2;
-      goto leave;
-    }
-
   make_session_key (cfx.dek);
   if (DBG_CRYPTO)
     log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");
@@ -960,6 +921,26 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   else
     filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
 
+  /* Register the cipher filter. */
+  iobuf_push_filter (out,
+                     cfx.dek->use_aead? cipher_filter_aead
+                     /**/             : cipher_filter_cfb,
+                     &cfx);
+
+  /* Only do the is-file-already-compressed check if we are using a
+   * MDC or AEAD.  This forces compressed files to be re-compressed if
+   * we do not have a MDC to give some protection against chosen
+   * ciphertext attacks. */
+  if (do_compress
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
+      && !opt.explicit_compress_option
+      && is_file_compressed (inp))
+    {
+      if (opt.verbose)
+        log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
+      do_compress = 0;
+    }
+
   if (!opt.no_literal)
     {
       pt->timestamp = make_timestamp();
@@ -974,12 +955,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   else
     cfx.datalen = filesize && !do_compress ? filesize : 0;
 
-  /* Register the cipher filter. */
-  iobuf_push_filter (out,
-                     cfx.dek->use_aead? cipher_filter_aead
-                     /**/             : cipher_filter_cfb,
-                     &cfx);
-
   /* Register the compress filter. */
   if (do_compress)
     {
diff --git a/g10/sign.c b/g10/sign.c
index b5e9d422d..fcb1bb749 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1035,9 +1035,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
   int multifile = 0;
   u32 duration=0;
   pt_extra_hash_data_t extrahash = NULL;
-  char peekbuf[32];
-  int  peekbuflen = 0;
-
 
   pfx = new_progress_context ();
   afx = new_armor_context ();
@@ -1096,14 +1093,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
           goto leave;
 	}
 
-      peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
-      if (peekbuflen < 0)
-        {
-          peekbuflen = 0;
-          if (DBG_FILTER)
-            log_debug ("peeking at input failed\n");
-        }
-
       handle_progress (pfx, inp, fname);
     }
 
@@ -1261,7 +1250,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
       int compr_algo = opt.compress_algo;
 
       if (!opt.explicit_compress_option
-          && is_file_compressed (peekbuf, peekbuflen))
+          && is_file_compressed (inp))
         {
           if (opt.verbose)
             log_info(_("'%s' already compressed\n"), fname? fname: "[stdin]");
-- 
2.11.0

