[git] GPGME - branch, master, updated. gpgme-1.6.0-180-g5905e8b

by Werner Koch cvs at cvs.gnupg.org
Tue Jun 21 16:23:07 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  5905e8bbd809c1408edad4fa4eb0527fa51cbea3 (commit)
       via  32d4bbf5e3e5f88e4a6852d72a35ee30df9d5279 (commit)
      from  8997d88bf97d1784706becbf8e9dc74e4656e311 (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 5905e8bbd809c1408edad4fa4eb0527fa51cbea3
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jun 21 16:17:26 2016 +0200

    tests: Add new test tool run-identify.
    
    * src/gpgme-tool.c (gt_identify): Add new strings.
    * tests/run-identify.c: New.
    * tests/Makefile.am (noinst_PROGRAMS): Add run-identify.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c
index 557ed64..ccda973 100644
--- a/src/gpgme-tool.c
+++ b/src/gpgme-tool.c
@@ -1683,6 +1683,8 @@ gt_identify (gpgme_tool_t gt, gpgme_data_t data)
     case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
     case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
     case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
+    case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
+    case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
     case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 22c07d2..bfd8e36 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -32,7 +32,7 @@ LDADD = ../src/libgpgme.la @GPG_ERROR_LIBS@
 noinst_HEADERS = run-support.h
 
 noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
-		  run-verify run-encrypt
+		  run-verify run-encrypt run-identify
 
 
 if RUN_GPG_TESTS
diff --git a/tests/run-identify.c b/tests/run-identify.c
new file mode 100644
index 0000000..d5ce55f
--- /dev/null
+++ b/tests/run-identify.c
@@ -0,0 +1,129 @@
+/* run-identify  - Helper to run the identify command
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME 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.
+ *
+ * GPGME 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
+ * Lesser 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/>.
+ */
+
+/* We need to include config.h so that we know whether we are building
+   with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#define PGM "run-identify"
+
+#include "run-support.h"
+
+
+static int verbose;
+
+
+static const char *
+data_type_to_string (gpgme_data_type_t dt)
+{
+  const char *s = "[?]";
+
+  switch (dt)
+    {
+    case GPGME_DATA_TYPE_INVALID      : s = "invalid"; break;
+    case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
+    case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
+    case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
+    case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
+    case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
+    case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
+    case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
+    case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
+    case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
+    case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
+    case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
+    }
+  return s;
+}
+
+
+static int
+show_usage (int ex)
+{
+  fputs ("usage: " PGM " [options] FILENAMEs\n\n"
+         "Options:\n"
+         "  --verbose        run in verbose mode\n"
+         , stderr);
+  exit (ex);
+}
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  gpgme_error_t err;
+  int anyerr = 0;
+  gpgme_data_t data;
+  gpgme_data_type_t dt;
+
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        show_usage (0);
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        show_usage (1);
+
+    }
+
+  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+  for (; argc; argc--, argv++)
+    {
+      if (verbose)
+        printf ("reading file `%s'\n", *argv);
+      err = gpgme_data_new_from_file (&data, *argv, 1);
+      if (err)
+        {
+          fprintf (stderr, PGM ": error reading '%s': %s\n",
+                   *argv, gpg_strerror (err));
+          anyerr = 1;
+        }
+      else
+        {
+          dt = gpgme_data_identify (data, 0);
+          if (dt == GPGME_DATA_TYPE_INVALID)
+            anyerr = 1;
+          printf ("%s: %s\n", *argv, data_type_to_string (dt));
+          gpgme_data_release (data);
+        }
+    }
+
+  return anyerr;
+}

commit 32d4bbf5e3e5f88e4a6852d72a35ee30df9d5279
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jun 21 16:14:02 2016 +0200

    core: Enhance gpgme_data_identify to detect binary PGP messages.
    
    * src/gpgme.h.in (GPGME_DATA_TYPE_PGP_ENCRYPTED): New.
    (GPGME_DATA_TYPE_PGP_SIGNATURE): New.
    * src/data-identify.c: Add enum for OpenPGP packet types.
    (buf32_to_ulong): New.
    (next_openpgp_packet): New.  Based on the gnupg/kbx/keybox-openpgp.c
    implementation and relicensed to LGPL by g10 Code.
    (pgp_binary_detection): New.
    (basic_detection): Call pgp_binary_detection instead of returning
    unknown.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 7b939e7..32f3c84 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,8 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_STATUS_TOFU_STATS        NEW.
  GPGME_STATUS_TOFU_STATS_LONG   NEW.
  GPGME_STATUS_NOTATION_FLAGS    NEW.
+ GPGME_DATA_TYPE_PGP_ENCRYPTED  NEW.
+ GPGME_DATA_TYPE_PGP_SIGNATURE  NEW.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
diff --git a/src/data-identify.c b/src/data-identify.c
index 9600633..f7107e0 100644
--- a/src/data-identify.c
+++ b/src/data-identify.c
@@ -29,10 +29,238 @@
 #include "util.h"
 #include "parsetlv.h"
 
+
 /* The size of the sample data we take for detection.  */
 #define SAMPLE_SIZE 2048
 
 
+/* OpenPGP packet types.  */
+enum
+  {
+    PKT_NONE	      = 0,
+    PKT_PUBKEY_ENC    = 1,  /* Public key encrypted packet. */
+    PKT_SIGNATURE     = 2,  /* Secret key encrypted packet. */
+    PKT_SYMKEY_ENC    = 3,  /* Session key packet. */
+    PKT_ONEPASS_SIG   = 4,  /* One pass sig packet. */
+    PKT_SECRET_KEY    = 5,  /* Secret key. */
+    PKT_PUBLIC_KEY    = 6,  /* Public key. */
+    PKT_SECRET_SUBKEY = 7,  /* Secret subkey. */
+    PKT_COMPRESSED    = 8,  /* Compressed data packet. */
+    PKT_ENCRYPTED     = 9,  /* Conventional encrypted data. */
+    PKT_MARKER	      = 10, /* Marker packet. */
+    PKT_PLAINTEXT     = 11, /* Literal data packet. */
+    PKT_RING_TRUST    = 12, /* Keyring trust packet. */
+    PKT_USER_ID	      = 13, /* User id packet. */
+    PKT_PUBLIC_SUBKEY = 14, /* Public subkey. */
+    PKT_OLD_COMMENT   = 16, /* Comment packet from an OpenPGP draft. */
+    PKT_ATTRIBUTE     = 17, /* PGP's attribute packet. */
+    PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
+    PKT_MDC 	      = 19, /* Manipulation detection code packet. */
+  };
+
+
+static inline unsigned long
+buf32_to_ulong (const void *buffer)
+{
+  const unsigned char *p = buffer;
+
+  return (((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+
+/* Parse the next openpgp packet.  This function assumes a valid
+ * OpenPGP packet at the address pointed to by BUFPTR which has a
+ * maximum length as stored at BUFLEN.  Return the header information
+ * of that packet and advance the pointer stored at BUFPTR to the next
+ * packet; also adjust the length stored at BUFLEN to match the
+ * remaining bytes. If there are no more packets, store NULL at
+ * BUFPTR.  Return an non-zero error code on failure or the following
+ * data on success:
+ *
+ *  R_PKTTYPE = The packet type.
+ *  R_NTOTAL  = The total number of bytes of this packet
+ *
+ * If GPG_ERR_TRUNCATED is returned, a packet type is anyway stored at
+ * R_PKTTYPE but R_NOTAL won't have a usable value,
+ */
+static gpg_error_t
+next_openpgp_packet (unsigned char const **bufptr, size_t *buflen,
+                     int *r_pkttype, size_t *r_ntotal)
+{
+  const unsigned char *buf = *bufptr;
+  size_t len = *buflen;
+  int c, ctb, pkttype;
+  unsigned long pktlen;
+
+  if (!len)
+    return gpg_error (GPG_ERR_NO_DATA);
+
+  ctb = *buf++; len--;
+  if ( !(ctb & 0x80) )
+    return gpg_error (GPG_ERR_INV_PACKET); /* Invalid CTB. */
+
+  if ((ctb & 0x40))  /* New style (OpenPGP) CTB.  */
+    {
+      pkttype = (ctb & 0x3f);
+      if (!len)
+        return gpg_error (GPG_ERR_INV_PACKET); /* No 1st length byte. */
+      c = *buf++; len--;
+      if ( c < 192 )
+        pktlen = c;
+      else if ( c < 224 )
+        {
+          pktlen = (c - 192) * 256;
+          if (!len)
+            return gpg_error (GPG_ERR_INV_PACKET); /* No 2nd length byte. */
+          c = *buf++; len--;
+          pktlen += c + 192;
+        }
+      else if (c == 255)
+        {
+          if (len < 4)
+            return gpg_error (GPG_ERR_INV_PACKET); /* No length bytes. */
+          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 /* Old style CTB.  */
+    {
+      int lenbytes;
+
+      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--)
+        {
+          pktlen <<= 8;
+          pktlen |= *buf++; len--;
+	}
+    }
+
+  /* Do some basic sanity check.  */
+  switch (pkttype)
+    {
+    case PKT_PUBKEY_ENC:
+    case PKT_SIGNATURE:
+    case PKT_SYMKEY_ENC:
+    case PKT_ONEPASS_SIG:
+    case PKT_SECRET_KEY:
+    case PKT_PUBLIC_KEY:
+    case PKT_SECRET_SUBKEY:
+    case PKT_COMPRESSED:
+    case PKT_ENCRYPTED:
+    case PKT_MARKER:
+    case PKT_PLAINTEXT:
+    case PKT_RING_TRUST:
+    case PKT_USER_ID:
+    case PKT_PUBLIC_SUBKEY:
+    case PKT_OLD_COMMENT:
+    case PKT_ATTRIBUTE:
+    case PKT_ENCRYPTED_MDC:
+    case PKT_MDC:
+      break; /* Okay these are allowed packets. */
+    default:
+      return gpg_error (GPG_ERR_UNEXPECTED);
+    }
+
+  if (pktlen > len)
+    {
+      /* Packet length header too long.  This is possible because we
+       * may have only a truncated image.  */
+      *r_pkttype = pkttype;
+      *r_ntotal = 0;
+      *bufptr = NULL;
+      return gpg_error (GPG_ERR_TRUNCATED);
+    }
+
+  *r_pkttype = pkttype;
+  *r_ntotal = (buf - *bufptr) + pktlen;
+
+  *bufptr = buf + pktlen;
+  *buflen = len - pktlen;
+  if (!*buflen)
+    *bufptr = NULL;
+
+  return 0;
+}
+
+
+/* Detection of PGP binary data.  This function parses an OpenPGP
+ * message.  This parser is robust enough to work on a truncated
+ * version.  Returns a GPGME_DATA_TYPE_.  */
+static gpgme_data_type_t
+pgp_binary_detection (const void *image_arg, size_t imagelen)
+{
+  gpg_error_t err = 0;
+  const unsigned char *image = image_arg;
+  size_t n;
+  int pkttype;
+  int anypacket = 0;
+  int allsignatures = 0;
+
+  while (!err && image)
+    {
+      err = next_openpgp_packet (&image, &imagelen, &pkttype, &n);
+      if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
+        ;
+      else if (err)
+        break;
+
+      if (pkttype == PKT_SIGNATURE)
+        {
+          if (!anypacket)
+            allsignatures = 1;
+        }
+      else
+        allsignatures = 0;
+      anypacket = 1;
+
+      switch (pkttype)
+        {
+        case PKT_SIGNATURE:
+          break;  /* We decide later.  */
+
+        case PKT_PLAINTEXT:
+          /* Old style signature format: {sig}+,plaintext */
+          if (allsignatures)
+            return GPGME_DATA_TYPE_PGP_SIGNED;
+          break;
+
+        case PKT_ONEPASS_SIG:
+          return GPGME_DATA_TYPE_PGP_SIGNED;
+
+        case PKT_SECRET_KEY:
+        case PKT_PUBLIC_KEY:
+          return GPGME_DATA_TYPE_PGP_KEY;
+
+        case PKT_SECRET_SUBKEY:
+        case PKT_PUBLIC_SUBKEY:
+          return GPGME_DATA_TYPE_PGP_OTHER;
+        case PKT_PUBKEY_ENC:
+        case PKT_SYMKEY_ENC:
+          return GPGME_DATA_TYPE_PGP_ENCRYPTED;
+
+        case PKT_MARKER:
+          break;  /* Skip this packet.  */
+
+        default:
+          return GPGME_DATA_TYPE_PGP_OTHER;
+        }
+    }
+
+  if (allsignatures)
+    return  GPGME_DATA_TYPE_PGP_SIGNATURE;
+
+  return GPGME_DATA_TYPE_UNKNOWN;
+}
+
 
 /* Note that DATA may be binary but a final nul is required so that
    string operations will find a terminator.
@@ -167,7 +395,7 @@ basic_detection (const char *data, size_t datalen)
          at all defined and in any case it is uncommon.  Thus we don't
          do any further plausibility checks but stupidly assume no CMS
          armored data will follow.  */
-      return GPGME_DATA_TYPE_UNKNOWN;
+      return pgp_binary_detection (data, datalen);
     }
 
   /* Now check whether there are armor lines.  */
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index dc2f143..790485d 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -239,8 +239,10 @@ typedef enum
     GPGME_DATA_TYPE_INVALID      = 0,   /* Not detected.  */
     GPGME_DATA_TYPE_UNKNOWN      = 1,
     GPGME_DATA_TYPE_PGP_SIGNED   = 0x10,
+    GPGME_DATA_TYPE_PGP_ENCRYPTED= 0x11,
     GPGME_DATA_TYPE_PGP_OTHER    = 0x12,
     GPGME_DATA_TYPE_PGP_KEY      = 0x13,
+    GPGME_DATA_TYPE_PGP_SIGNATURE= 0x18, /* Detached signature */
     GPGME_DATA_TYPE_CMS_SIGNED   = 0x20,
     GPGME_DATA_TYPE_CMS_ENCRYPTED= 0x21,
     GPGME_DATA_TYPE_CMS_OTHER    = 0x22,

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

Summary of changes:
 NEWS                 |   2 +
 src/data-identify.c  | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/gpgme-tool.c     |   2 +
 src/gpgme.h.in       |   2 +
 tests/Makefile.am    |   2 +-
 tests/run-identify.c | 129 +++++++++++++++++++++++++++++
 6 files changed, 365 insertions(+), 2 deletions(-)
 create mode 100644 tests/run-identify.c


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




More information about the Gnupg-commits mailing list