[git] GPGME - branch, master, updated. gpgme-1.6.0-183-gcf37a57

by Werner Koch cvs at cvs.gnupg.org
Thu Jun 23 10:17:06 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  cf37a57d28c43ec36277e84ca44458b7287b940b (commit)
       via  f8b8027ae63c957557ed6bdc7e5a30ef1bdd8e77 (commit)
       via  bb8cf6236582fc9eb6564046599989af52779a26 (commit)
      from  5905e8bbd809c1408edad4fa4eb0527fa51cbea3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit cf37a57d28c43ec36277e84ca44458b7287b940b
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 23 10:14:57 2016 +0200

    core: Add closer inspection of "PGP MESSAGE".
    
    * src/data-identify.c (inspect_pgp_message): New.
    (basic_detection): Un-const arg DATA. Call inspect_pgp_message.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/data-identify.c b/src/data-identify.c
index ae31117..1cfccd7 100644
--- a/src/data-identify.c
+++ b/src/data-identify.c
@@ -271,12 +271,36 @@ pgp_binary_detection (const void *image_arg, size_t imagelen)
 }
 
 
+/* This is probably an armored "PGP MESSAGE" which can encode
+ * different PGP data types.  STRING is modified after a call to this
+ * fucntion. */
+static gpgme_data_type_t
+inspect_pgp_message (char *string)
+{
+  struct b64state state;
+  size_t nbytes;
+
+  if (_gpgme_b64dec_start (&state, ""))
+    return GPGME_DATA_TYPE_INVALID; /* oops */
+
+  if (_gpgme_b64dec_proc (&state, string, strlen (string), &nbytes))
+    {
+      _gpgme_b64dec_finish (&state);
+      return GPGME_DATA_TYPE_UNKNOWN; /* bad encoding etc. */
+    }
+  _gpgme_b64dec_finish (&state);
+  string[nbytes] = 0; /* Better append a Nul. */
+
+  return pgp_binary_detection (string, nbytes);
+}
+
+
 /* Note that DATA may be binary but a final nul is required so that
    string operations will find a terminator.
 
    Returns: GPGME_DATA_TYPE_xxxx */
 static gpgme_data_type_t
-basic_detection (const char *data, size_t datalen)
+basic_detection (char *data, size_t datalen)
 {
   tlvinfo_t ti;
   const char *s;
@@ -430,7 +454,8 @@ basic_detection (const char *data, size_t datalen)
                 return GPGME_DATA_TYPE_PGP_KEY;
               if (!strncmp (s+15, "ARMORED FILE", 12))
                 return GPGME_DATA_TYPE_UNKNOWN;
-              return GPGME_DATA_TYPE_PGP_OTHER; /* PGP MESSAGE */
+
+              return inspect_pgp_message (data);
             }
           if (!strncmp (s+11, "CERTIFICATE", 11))
             return GPGME_DATA_TYPE_X509_CERT;

commit f8b8027ae63c957557ed6bdc7e5a30ef1bdd8e77
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jun 23 09:48:54 2016 +0200

    core: Add a base 64 decoder.
    
    * src/b64dec.c: New. Taken from gnupg.  Prefix function names with
    _gpgme_ and change to use standard C malloc functions.
    * src/util.h.h (struct b64state): New.
    * src/Makefile.am (main_sources): Add file.
    
    --
    
    The file b64dec.c has been taken from gnupg commit
    e430ff6ad0b7dcfcebd92b825dd5168205447ff3
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/Makefile.am b/src/Makefile.am
index 951fc00..6691540 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,7 +74,7 @@ endif
 # right linking order with libtool, as the non-installed version has
 # unresolved symbols to the thread module.
 main_sources =								\
-	util.h conversion.c get-env.c context.h ops.h		        \
+	util.h conversion.c b64dec.c get-env.c context.h ops.h		\
 	parsetlv.c parsetlv.h                                           \
 	data.h data.c data-fd.c data-stream.c data-mem.c data-user.c	\
 	data-compat.c data-identify.c					\
diff --git a/src/b64dec.c b/src/b64dec.c
new file mode 100644
index 0000000..7965a30
--- /dev/null
+++ b/src/b64dec.c
@@ -0,0 +1,251 @@
+/* b64dec.c - Simple Base64 decoder.
+ * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "util.h"
+
+
+/* The reverse base-64 list used for base-64 decoding. */
+static unsigned char const asctobin[128] =
+  {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+    0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+    0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+    0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+    0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+    0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+  };
+
+enum decoder_states
+  {
+    s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
+    s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+    s_waitendtitle, s_waitend
+  };
+
+
+
+/* Initialize the context for the base64 decoder.  If TITLE is NULL a
+   plain base64 decoding is done.  If it is the empty string the
+   decoder will skip everything until a "-----BEGIN " line has been
+   seen, decoding ends at a "----END " line.  */
+gpg_error_t
+_gpgme_b64dec_start (struct b64state *state, const char *title)
+{
+  memset (state, 0, sizeof *state);
+  if (title)
+    {
+      state->title = strdup (title);
+      if (!state->title)
+        state->lasterr = gpg_error_from_syserror ();
+      else
+        state->idx = s_init;
+    }
+  else
+    state->idx = s_b64_0;
+  return state->lasterr;
+}
+
+
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Stores the
+   new length of the buffer at R_NBYTES. */
+gpg_error_t
+_gpgme_b64dec_proc (struct b64state *state, void *buffer, size_t length,
+                    size_t *r_nbytes)
+{
+  enum decoder_states ds = state->idx;
+  unsigned char val = state->radbuf[0];
+  int pos = state->quad_count;
+  char *d, *s;
+
+  if (state->lasterr)
+    return state->lasterr;
+
+  if (state->stop_seen)
+    {
+      *r_nbytes = 0;
+      state->lasterr = gpg_error (GPG_ERR_EOF);
+      free (state->title);
+      state->title = NULL;
+      return state->lasterr;
+    }
+
+  for (s=d=buffer; length && !state->stop_seen; length--, s++)
+    {
+    again:
+      switch (ds)
+        {
+        case s_idle:
+          if (*s == '\n')
+            {
+              ds = s_lfseen;
+              pos = 0;
+            }
+          break;
+        case s_init:
+          ds = s_lfseen;
+        case s_lfseen:
+          if (*s != "-----BEGIN "[pos])
+            {
+              ds = s_idle;
+              goto again;
+            }
+          else if (pos == 10)
+            {
+              pos = 0;
+              ds = s_beginseen;
+            }
+          else
+            pos++;
+          break;
+        case s_beginseen:
+          if (*s != "PGP "[pos])
+            ds = s_begin; /* Not a PGP armor.  */
+          else if (pos == 3)
+            ds = s_waitheader;
+          else
+            pos++;
+          break;
+        case s_waitheader:
+          if (*s == '\n')
+            ds = s_waitblank;
+          break;
+        case s_waitblank:
+          if (*s == '\n')
+            ds = s_b64_0; /* blank line found.  */
+          else if (*s == ' ' || *s == '\r' || *s == '\t')
+            ; /* Ignore spaces. */
+          else
+            {
+              /* Armor header line.  Note that we don't care that our
+               * FSM accepts a header prefixed with spaces.  */
+              ds = s_waitheader; /* Wait for next header.  */
+            }
+          break;
+        case s_begin:
+          if (*s == '\n')
+            ds = s_b64_0;
+          break;
+        case s_b64_0:
+        case s_b64_1:
+        case s_b64_2:
+        case s_b64_3:
+          {
+            int c;
+
+            if (*s == '-' && state->title)
+              {
+                /* Not a valid Base64 character: assume end
+                   header.  */
+                ds = s_waitend;
+              }
+            else if (*s == '=')
+              {
+                /* Pad character: stop */
+                if (ds == s_b64_1)
+                  *d++ = val;
+                ds = state->title? s_waitendtitle : s_waitend;
+              }
+            else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+              ; /* Skip white spaces. */
+            else if ( (*s & 0x80)
+                      || (c = asctobin[*(unsigned char *)s]) == 255)
+              {
+                /* Skip invalid encodings.  */
+                state->invalid_encoding = 1;
+              }
+            else if (ds == s_b64_0)
+              {
+                val = c << 2;
+                ds = s_b64_1;
+              }
+            else if (ds == s_b64_1)
+              {
+                val |= (c>>4)&3;
+                *d++ = val;
+                val = (c<<4)&0xf0;
+                ds = s_b64_2;
+              }
+            else if (ds == s_b64_2)
+              {
+                val |= (c>>2)&15;
+                *d++ = val;
+                val = (c<<6)&0xc0;
+                ds = s_b64_3;
+              }
+            else
+              {
+                val |= c&0x3f;
+                *d++ = val;
+                ds = s_b64_0;
+              }
+          }
+          break;
+        case s_waitendtitle:
+          if (*s == '-')
+            ds = s_waitend;
+          break;
+        case s_waitend:
+          if ( *s == '\n')
+            state->stop_seen = 1;
+          break;
+        default:
+          assert (!"invalid state");
+        }
+    }
+
+
+  state->idx = ds;
+  state->radbuf[0] = val;
+  state->quad_count = pos;
+  *r_nbytes = (d -(char*) buffer);
+  return 0;
+}
+
+
+/* This function needs to be called before releasing the decoder
+   state.  It may return an error code in case an encoding error has
+   been found during decoding. */
+gpg_error_t
+_gpgme_b64dec_finish (struct b64state *state)
+{
+  if (state->lasterr)
+    return state->lasterr;
+
+  free (state->title);
+  state->title = NULL;
+  return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
+}
diff --git a/src/util.h b/src/util.h
index 9c62f57..5a0f790 100644
--- a/src/util.h
+++ b/src/util.h
@@ -147,6 +147,26 @@ gpgme_error_t _gpgme_map_gnupg_error (char *err);
 int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol);
 
 

+/*-- b64dec.c --*/
+
+struct b64state
+{
+  int idx;
+  int quad_count;
+  char *title;
+  unsigned char radbuf[4];
+  int stop_seen:1;
+  int invalid_encoding:1;
+  gpg_error_t lasterr;
+};
+
+gpg_error_t _gpgme_b64dec_start (struct b64state *state, const char *title);
+gpg_error_t _gpgme_b64dec_proc (struct b64state *state,
+                                void *buffer, size_t length, size_t *r_nbytes);
+gpg_error_t _gpgme_b64dec_finish (struct b64state *state);
+
+
+

 /* Retrieve the environment variable NAME and return a copy of it in a
    malloc()'ed buffer in *VALUE.  If the environment variable is not
    set, return NULL in *VALUE.  */

commit bb8cf6236582fc9eb6564046599989af52779a26
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jun 22 18:43:26 2016 +0200

    core: Detect compressed signed OpenPGP data.
    
    * src/data-identify.c (next_openpgp_packet): Allow partial encoding.
    (pgp_binary_detection): Handle compressed packets.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/data-identify.c b/src/data-identify.c
index f7107e0..ae31117 100644
--- a/src/data-identify.c
+++ b/src/data-identify.c
@@ -1,5 +1,5 @@
 /* data-identify.c - Try to identify the data
-   Copyright (C) 2013 g10 Code GmbH
+   Copyright (C) 2013, 2016 g10 Code GmbH
 
    This file is part of GPGME.
 
@@ -122,9 +122,11 @@ next_openpgp_packet (unsigned char const **bufptr, size_t *buflen,
           pktlen = buf32_to_ulong (buf);
           buf += 4;
           len -= 4;
-      }
-      else /* Partial length encoding is not allowed for key packets. */
-        return gpg_error (GPG_ERR_UNEXPECTED);
+        }
+      else /* Partial length encoding. */
+        {
+          pktlen = 0;
+        }
     }
   else /* Old style CTB.  */
     {
@@ -133,8 +135,6 @@ next_openpgp_packet (unsigned char const **bufptr, size_t *buflen,
       pktlen = 0;
       pkttype = (ctb>>2)&0xf;
       lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
-      if (!lenbytes) /* Not allowed in key packets.  */
-        return gpg_error (GPG_ERR_UNEXPECTED);
       if (len < lenbytes)
         return gpg_error (GPG_ERR_INV_PACKET); /* Not enough length bytes.  */
       for (; lenbytes; lenbytes--)
@@ -213,6 +213,10 @@ pgp_binary_detection (const void *image_arg, size_t imagelen)
       else if (err)
         break;
 
+      /* Skip all leading marker packets.  */
+      if (!anypacket && pkttype == PKT_MARKER)
+        continue;
+
       if (pkttype == PKT_SIGNATURE)
         {
           if (!anypacket)
@@ -220,7 +224,6 @@ pgp_binary_detection (const void *image_arg, size_t imagelen)
         }
       else
         allsignatures = 0;
-      anypacket = 1;
 
       switch (pkttype)
         {
@@ -247,12 +250,18 @@ pgp_binary_detection (const void *image_arg, size_t imagelen)
         case PKT_SYMKEY_ENC:
           return GPGME_DATA_TYPE_PGP_ENCRYPTED;
 
-        case PKT_MARKER:
-          break;  /* Skip this packet.  */
+        case PKT_COMPRESSED:
+          /* If this is the first packet we assume that that a signed
+           * packet follows.  We do not want to uncompress it here due
+           * to the need of a lot of code and the potentail DoS. */
+          if (!anypacket)
+            return GPGME_DATA_TYPE_PGP_SIGNED;
+          return GPGME_DATA_TYPE_PGP_OTHER;
 
         default:
           return GPGME_DATA_TYPE_PGP_OTHER;
         }
+      anypacket = 1;
     }
 
   if (allsignatures)

-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am     |   2 +-
 src/b64dec.c        | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/data-identify.c |  56 +++++++++---
 src/util.h          |  20 +++++
 4 files changed, 317 insertions(+), 12 deletions(-)
 create mode 100644 src/b64dec.c


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list