[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-371-g862cf19

by Werner Koch cvs at cvs.gnupg.org
Fri Apr 1 13:59:10 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 "The GNU crypto library".

The branch, master has been updated
       via  862cf19a119427dd7ee7959a36c72d905f5ea5ca (commit)
      from  fcce0cb6e8af70b134c6ecc3f56afa07a7d31f27 (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 862cf19a119427dd7ee7959a36c72d905f5ea5ca
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Apr 1 13:42:01 2016 +0200

    mpi: Explicitly limit the allowed input length for gcry_mpi_scan.
    
    * mpi/mpicoder.c (MAX_EXTERN_SCAN_BYTES): New.
    (mpi_fromstr): Check against this limit.
    (_gcry_mpi_scan): Ditto.
    * tests/mpitests.c (test_maxsize): New.
    (main): Cal that test.
    --
    
    A too large buffer length may lead to an unsigned integer overflow on
    systems where size_t > unsigned int (ie. 64 bit systems).  The
    computation of the required number of nlimbs may also be affected by
    this.  However this is not a real world case because any processing
    which has allocated such a long buffer from an external source would
    be prone to other DoS attacks: The required buffer length to exhibit
    this overflow is at least 2^32 - 8 bytes.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 437dddb..c710765 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -4526,7 +4526,8 @@ representation of an MPI and the internal one of Libgcrypt.
 Convert the external representation of an integer stored in @var{buffer}
 with a length of @var{buflen} into a newly created MPI returned which
 will be stored at the address of @var{r_mpi}.  For certain formats the
-length argument is not required and should be passed as @code{0}.  After a
+length argument is not required and should be passed as @code{0}. A
+ at var{buflen} larger than 16 MiByte will be rejected.  After a
 successful operation the variable @var{nscanned} receives the number of
 bytes actually scanned unless @var{nscanned} was given as
 @code{NULL}. @var{format} describes the format of the MPI as stored in
@@ -4540,6 +4541,7 @@ bytes actually scanned unless @var{nscanned} was given as
 @item GCRYMPI_FMT_PGP
 As used by OpenPGP (only defined as unsigned). This is basically
 @code{GCRYMPI_FMT_STD} with a 2 byte big endian length header.
+A length header indicating a length of more than 16384 is not allowed.
 
 @item GCRYMPI_FMT_SSH
 As used in the Secure Shell protocol.  This is @code{GCRYMPI_FMT_STD}
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index 896dda1..e315576 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -27,8 +27,21 @@
 #include "mpi-internal.h"
 #include "g10lib.h"
 
+/* The maximum length we support in the functions converting an
+ * external representation to an MPI.  This limit is used to catch
+ * programming errors and to avoid DoS due to insane long allocations.
+ * The 16 MiB limit is actually ridiculous large but some of those PQC
+ * algorithms use quite large keys and they might end up using MPIs
+ * for that.  */
+#define MAX_EXTERN_SCAN_BYTES (16*1024*1024)
+
+/* The maximum length (in bits) we support for OpenPGP MPIs.  Note
+ * that OpenPGP's MPI format uses only two bytes and thus would be
+ * limited to 64k anyway.  Note that this limit matches that used by
+ * GnuPG.  */
 #define MAX_EXTERN_MPI_BITS 16384
 
+
 /* Helper used to scan PGP style MPIs.  Returns NULL on failure. */
 static gcry_mpi_t
 mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread,
@@ -104,7 +117,13 @@ mpi_fromstr (gcry_mpi_t val, const char *str)
   if ( *str == '0' && str[1] == 'x' )
     str += 2;
 
-  nbits = 4 * strlen (str);
+  nbits = strlen (str);
+  if (nbits > MAX_EXTERN_SCAN_BYTES)
+    {
+      mpi_clear (val);
+      return 1;  /* Error.  */
+    }
+  nbits *= 4;
   if ((nbits % 8))
     prepend_zero = 1;
 
@@ -438,9 +457,9 @@ twocompl (unsigned char *p, unsigned int n)
 
 
 /* Convert the external representation of an integer stored in BUFFER
-   with a length of BUFLEN into a newly create MPI returned in
-   RET_MPI.  If NBYTES is not NULL, it will receive the number of
-   bytes actually scanned after a successful operation.  */
+ * with a length of BUFLEN into a newly create MPI returned in
+ * RET_MPI.  If NSCANNED is not NULL, it will receive the number of
+ * bytes actually scanned after a successful operation.  */
 gcry_err_code_t
 _gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
                 const void *buffer_arg, size_t buflen, size_t *nscanned)
@@ -450,6 +469,13 @@ _gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
   unsigned int len;
   int secure = (buffer && _gcry_is_secure (buffer));
 
+  if (buflen > MAX_EXTERN_SCAN_BYTES)
+    {
+      if (nscanned)
+        *nscanned = 0;
+      return GPG_ERR_INV_OBJ;
+    }
+
   if (format == GCRYMPI_FMT_SSH)
     len = 0;
   else
diff --git a/tests/mpitests.c b/tests/mpitests.c
index e6f8525..b663029 100644
--- a/tests/mpitests.c
+++ b/tests/mpitests.c
@@ -237,6 +237,42 @@ test_opaque (void)
 
 
 static void
+test_maxsize (void)
+{
+  gpg_error_t err;
+  gcry_mpi_t a;
+  char buffer[2+2048]; /* For PGP: 2 length bytes and 16384 bits.  */
+
+  memset (buffer, 0x55, sizeof buffer);
+
+  /* We use a short buffer but a give a too large length to simulate a
+   * programming error.  In case this test fails (i.e. die() is
+   * called) the scan function may have access data outside of BUFFER
+   * which may result in a segv but we ignore that to avoid actually
+   * allocating such a long buffer.  */
+  err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, buffer, 16*1024*1024 +1, NULL);
+  if (gpg_err_code (err) != GPG_ERR_INV_OBJ)
+    die ("gcry_mpi_scan does not detect its generic input limit\n");
+
+  /* Now test the PGP limit.  The scan code check the two length bytes
+   * from the buffer and thus it is sufficient to fake them.  */
+  buffer[0] = (16385 >> 8);
+  buffer[1] = (16385 & 0xff);
+  err = gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buffer, sizeof buffer, NULL);
+  if (gpg_err_code (err) != GPG_ERR_INV_OBJ)
+    die ("gcry_mpi_scan does not detect the PGP input limit\n");
+
+  buffer[0] = (16384 >> 8);
+  buffer[1] = (16384 & 0xff);
+
+  err = gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buffer, sizeof buffer, NULL);
+  if (err)
+    die ("gcry_mpi_scan did not parse a large PGP: %s\n", gpg_strerror (err));
+  gcry_mpi_release (a);
+}
+
+
+static void
 test_cmp (void)
 {
   gpg_error_t rc;
@@ -569,6 +605,7 @@ main (int argc, char* argv[])
 
   test_const_and_immutable ();
   test_opaque ();
+  test_maxsize ();
   test_cmp ();
   test_add ();
   test_sub ();

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

Summary of changes:
 doc/gcrypt.texi  |  4 +++-
 mpi/mpicoder.c   | 34 ++++++++++++++++++++++++++++++----
 tests/mpitests.c | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 5 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list