Add GCRYMPI_FLAG_IMMUTABLE to help debugging.
authorWerner Koch <wk@gnupg.org>
Tue, 12 Mar 2013 19:20:42 +0000 (20:20 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 13 Mar 2013 11:38:30 +0000 (12:38 +0100)
* src/gcrypt.h.in (GCRYMPI_FLAG_IMMUTABLE): New.
* src/mpi.h (mpi_is_immutable): New macro.
* mpi/mpiutil.c (gcry_mpi_set_flag, gcry_mpi_clear_flag)
(gcry_mpi_get_flag): Implement new flag
(_gcry_mpi_immutable_failed): New.

* mpi/mpiutil.c (_gcry_mpi_clear, _gcry_mpi_free, gcry_mpi_snatch)
(gcry_mpi_set, gcry_mpi_randomize): Act upon the immutable flag.
* mpi/mpi-bit.c (gcry_mpi_set_bit, gcry_mpi_set_highbit)
(gcry_mpi_clear_highbit, gcry_mpi_clear_bit)
(_gcry_mpi_rshift_limbs, gcry_mpi_lshift): Ditto.
* mpi/mpicoder.c (_gcry_mpi_set_buffer): Ditto.
--

Note that this flag is currently only checked by a few MPI functions.
The reason why we eventually need such a flag is to help implementing
a generic way to retrieve and set ECC parameters without accidentally
changing a curve parameter taken from a list of predefined curves.

NEWS
doc/gcrypt.texi
mpi/mpi-bit.c
mpi/mpicoder.c
mpi/mpiutil.c
src/gcrypt.h.in
src/mpi.h

diff --git a/NEWS b/NEWS
index 733dd88..3a4ca4c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -50,6 +50,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  gcry_mpi_ec_dup                 NEW.
  gcry_mpi_ec_add                 NEW.
  gcry_mpi_ec_mul                 NEW.
+ GCRYMPI_FLAG_IMMUTABLE          NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
index c986ec7..bfc825d 100644 (file)
@@ -3970,6 +3970,9 @@ Multiply the point @var{u} of the elliptic curve described by
 @node Miscellaneous
 @section Miscellaneous
 
+An MPI data type is allowed to be ``misused'' to store an arbitrary
+value.  Two functions implement this kludge:
+
 @deftypefun gcry_mpi_t gcry_mpi_set_opaque (@w{gcry_mpi_t @var{a}}, @w{void *@var{p}}, @w{unsigned int @var{nbits}})
 
 Store @var{nbits} of the value @var{p} points to in @var{a} and mark
@@ -3980,7 +3983,6 @@ math calculation and is only used to store an arbitrary bit pattern in
 WARNING: Never use an opaque MPI for actual math operations.  The only
 valid functions are gcry_mpi_get_opaque and gcry_mpi_release.  Use
 gcry_mpi_scan to convert a string of arbitrary bytes into an MPI.
-
 @end deftypefun
 
 @deftypefun {void *} gcry_mpi_get_opaque (@w{gcry_mpi_t @var{a}}, @w{unsigned int *@var{nbits}})
@@ -3991,23 +3993,46 @@ size in @var{nbits}.  Note that the returned pointer is still owned by
 MPI.
 @end deftypefun
 
-@deftypefun void gcry_mpi_set_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+Each MPI has an associated set of flags for special purposes.  The
+currently defined flags are:
 
-Set the @var{flag} for the MPI @var{a}.  Currently only the flag
-@code{GCRYMPI_FLAG_SECURE} is allowed to convert @var{a} into an MPI
-stored in "secure memory".
-@end deftypefun
+@table @code
+@item GCRYMPI_FLAG_SECURE
+Setting this flag converts @var{a} into an MPI stored in "secure
+memory".  Clearing this flag is not allowed.
+@item GCRYMPI_FLAG_OPAQUE
+This is an interanl flag, indicating the an opaque valuue and not an
+integer is stored.  This is an read-only flag; it may not be set or
+cleared.
+@item GCRYMPI_FLAG_IMMUTABLE
+If this flag is set, the MPI is marked as immutable.  Setting or
+changing the value of that MPI is ignored and an error message is
+logged.  The flag is sometimes useful for debugging.
+@end table
 
-@deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+@deftypefun void gcry_mpi_set_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
 
-Clear @var{flag} for the multi-precision-integers @var{a}.  Note that
-this function is currently useless as no flags are allowed.
+Set the @var{flag} for the MPI @var{a}.  The only allowed flags are
+@code{GCRYMPI_FLAG_SECURE} and @code{GCRYMPI_FLAG_IMMUTABLE}.
 @end deftypefun
 
-@deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
+@deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
 
-Return true when the @var{flag} is set for @var{a}.
+Clear @var{flag} for the multi-precision-integers @var{a}.  The only
+allowed flag is @code{GCRYMPI_FLAG_IMMUTABLE}.
 @end deftypefun
+o
+@deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @
+ @w{enum gcry_mpi_flag @var{flag}})
+
+Return true if @var{flag} is set for @var{a}.
+@end deftypefun
+
+
+To put a random value into an MPI, the following convenience function
+may be used:
 
 @deftypefun void gcry_mpi_randomize (@w{gcry_mpi_t @var{w}}, @w{unsigned int @var{nbits}}, @w{enum gcry_random_level @var{level}})
 
index cdc6b0b..74042e8 100644 (file)
@@ -1,5 +1,6 @@
 /* mpi-bit.c  -  MPI bit level functions
  * Copyright (C) 1998, 1999, 2001, 2002, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2013  g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -117,6 +118,12 @@ gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
 {
   unsigned int limbno, bitno;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   limbno = n / BITS_PER_MPI_LIMB;
   bitno  = n % BITS_PER_MPI_LIMB;
 
@@ -136,6 +143,12 @@ gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 {
   unsigned int limbno, bitno;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   limbno = n / BITS_PER_MPI_LIMB;
   bitno  = n % BITS_PER_MPI_LIMB;
 
@@ -156,18 +169,23 @@ gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
 void
 gcry_mpi_clear_highbit( gcry_mpi_t a, unsigned int n )
 {
-    unsigned int limbno, bitno;
+  unsigned int limbno, bitno;
 
-    limbno = n / BITS_PER_MPI_LIMB;
-    bitno  = n % BITS_PER_MPI_LIMB;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
 
-    if( limbno >= a->nlimbs )
-       return; /* not allocated, therefore no need to clear bits
-                  :-) */
+  limbno = n / BITS_PER_MPI_LIMB;
+  bitno  = n % BITS_PER_MPI_LIMB;
+
+  if( limbno >= a->nlimbs )
+    return; /* not allocated, therefore no need to clear bits :-) */
 
-    for( ; bitno < BITS_PER_MPI_LIMB; bitno++ )
-       a->d[limbno] &= ~(A_LIMB_1 << bitno);
-    a->nlimbs = limbno+1;
+  for( ; bitno < BITS_PER_MPI_LIMB; bitno++ )
+    a->d[limbno] &= ~(A_LIMB_1 << bitno);
+  a->nlimbs = limbno+1;
 }
 
 /****************
@@ -176,14 +194,20 @@ gcry_mpi_clear_highbit( gcry_mpi_t a, unsigned int n )
 void
 gcry_mpi_clear_bit( gcry_mpi_t a, unsigned int n )
 {
-    unsigned int limbno, bitno;
+  unsigned int limbno, bitno;
 
-    limbno = n / BITS_PER_MPI_LIMB;
-    bitno  = n % BITS_PER_MPI_LIMB;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
 
-    if( limbno >= a->nlimbs )
-       return; /* don't need to clear this bit, it's to far to left */
-    a->d[limbno] &= ~(A_LIMB_1 << bitno);
+  limbno = n / BITS_PER_MPI_LIMB;
+  bitno  = n % BITS_PER_MPI_LIMB;
+
+  if (limbno >= a->nlimbs)
+    return; /* Don't need to clear this bit, it's far too left.  */
+  a->d[limbno] &= ~(A_LIMB_1 << bitno);
 }
 
 
@@ -194,19 +218,26 @@ gcry_mpi_clear_bit( gcry_mpi_t a, unsigned int n )
 void
 _gcry_mpi_rshift_limbs( gcry_mpi_t a, unsigned int count )
 {
-    mpi_ptr_t ap = a->d;
-    mpi_size_t n = a->nlimbs;
-    unsigned int i;
+  mpi_ptr_t ap = a->d;
+  mpi_size_t n = a->nlimbs;
+  unsigned int i;
 
-    if( count >= n ) {
-       a->nlimbs = 0;
-       return;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
     }
 
-    for( i = 0; i < n - count; i++ )
-       ap[i] = ap[i+count];
-    ap[i] = 0;
-    a->nlimbs -= count;
+  if (count >= n)
+    {
+      a->nlimbs = 0;
+      return;
+    }
+
+  for( i = 0; i < n - count; i++ )
+    ap[i] = ap[i+count];
+  ap[i] = 0;
+  a->nlimbs -= count;
 }
 
 
@@ -221,6 +252,12 @@ gcry_mpi_rshift ( gcry_mpi_t x, gcry_mpi_t a, unsigned int n )
   unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
   unsigned int nbits = (n%BITS_PER_MPI_LIMB);
 
+  if (mpi_is_immutable (x))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   if ( x == a )
     {
       /* In-place operation.  */
@@ -328,6 +365,12 @@ gcry_mpi_lshift ( gcry_mpi_t x, gcry_mpi_t a, unsigned int n )
   unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
   unsigned int nbits = (n%BITS_PER_MPI_LIMB);
 
+  if (mpi_is_immutable (x))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   if (x == a && !n)
     return;  /* In-place shift with an amount of zero.  */
 
index a3435ed..06d5553 100644 (file)
@@ -305,6 +305,12 @@ _gcry_mpi_set_buffer (gcry_mpi_t a, const void *buffer_arg,
   int nlimbs;
   int i;
 
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+
   nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
   RESIZE_IF_NEEDED(a, nlimbs);
   a->sign = sign;
index d410d90..64a2f7e 100644 (file)
@@ -163,8 +163,13 @@ _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs)
 void
 _gcry_mpi_clear( gcry_mpi_t a )
 {
-    a->nlimbs = 0;
-    a->flags = 0;
+  if (mpi_is_immutable (a))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
+  a->nlimbs = 0;
+  a->flags = 0;
 }
 
 
@@ -179,11 +184,21 @@ _gcry_mpi_free( gcry_mpi_t a )
     {
       _gcry_mpi_free_limb_space(a->d, a->alloced);
     }
-  if ((a->flags & ~7))
-    log_bug("invalid flag value in mpi\n");
+  /* Check that the flags makes sense.  We better allow for bit 1
+     (value 2) for backward ABI compatibility.  */
+  if ((a->flags & ~(1|2|4|16)))
+    log_bug("invalid flag value in mpi_free\n");
   gcry_free(a);
 }
 
+
+void
+_gcry_mpi_immutable_failed (void)
+{
+  log_info ("Warning: trying to change immutable MPI\n");
+}
+
+
 static void
 mpi_set_secure( gcry_mpi_t a )
 {
@@ -303,6 +318,11 @@ gcry_mpi_snatch (gcry_mpi_t w, gcry_mpi_t u)
 {
   if (w)
     {
+      if (mpi_is_immutable (w))
+        {
+          mpi_immutable_failed ();
+          return;
+        }
       _gcry_mpi_assign_limb_space (w, u->d, u->alloced);
       w->nlimbs = u->nlimbs;
       w->sign   = u->sign;
@@ -324,6 +344,11 @@ gcry_mpi_set( gcry_mpi_t w, gcry_mpi_t u)
 
   if (!w)
     w = _gcry_mpi_alloc( mpi_get_nlimbs(u) );
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return w;
+    }
   RESIZE_IF_NEEDED(w, usize);
   wp = w->d;
   up = u->d;
@@ -342,6 +367,11 @@ gcry_mpi_set_ui( gcry_mpi_t w, unsigned long u)
     w = _gcry_mpi_alloc (1);
   /* FIXME: If U is 0 we have no need to resize and thus possible
      allocating the the limbs. */
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return w;
+    }
   RESIZE_IF_NEEDED(w, 1);
   w->d[0] = u;
   w->nlimbs = u? 1:0;
@@ -426,6 +456,11 @@ gcry_mpi_randomize( gcry_mpi_t w,
   unsigned char *p;
   size_t nbytes = (nbits+7)/8;
 
+  if (mpi_is_immutable (w))
+    {
+      mpi_immutable_failed ();
+      return;
+    }
   if (level == GCRY_WEAK_RANDOM)
     {
       p = mpi_is_secure(w) ? gcry_xmalloc_secure (nbytes)
@@ -446,7 +481,8 @@ void
 gcry_mpi_set_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 {
     switch( flag ) {
-      case GCRYMPI_FLAG_SECURE:  mpi_set_secure(a); break;
+      case GCRYMPI_FLAG_SECURE: mpi_set_secure(a); break;
+      case GCRYMPI_FLAG_IMMUTABLE:  a->flags |= 16; break;
       case GCRYMPI_FLAG_OPAQUE:
       default: log_bug("invalid flag value\n");
     }
@@ -459,6 +495,7 @@ gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 
   switch (flag)
     {
+    case GCRYMPI_FLAG_IMMUTABLE: a->flags &= ~16; break;
     case GCRYMPI_FLAG_SECURE:
     case GCRYMPI_FLAG_OPAQUE:
     default: log_bug("invalid flag value\n");
@@ -472,6 +509,7 @@ gcry_mpi_get_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
     {
     case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
     case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
+    case GCRYMPI_FLAG_IMMUTABLE:  return (a->flags & 16);
     default: log_bug("invalid flag value\n");
     }
   /*NOTREACHED*/
index 57b841e..9f6438c 100644 (file)
@@ -454,9 +454,10 @@ enum gcry_mpi_format
 enum gcry_mpi_flag
   {
     GCRYMPI_FLAG_SECURE = 1,  /* Allocate the number in "secure" memory.  */
-    GCRYMPI_FLAG_OPAQUE = 2   /* The number is not a real one but just
+    GCRYMPI_FLAG_OPAQUE = 2,  /* The number is not a real one but just
                                  a way to store some bytes.  This is
                                  useful for encrypted big integers.  */
+    GCRYMPI_FLAG_IMMUTABLE = 4  /* Mark the MPI as immutable.  */
   };
 
 
index 23afa68..93ad889 100644 (file)
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -69,7 +69,8 @@ struct gcry_mpi
   int sign;           /* Indicates a negative number and is also used
                          for opaque MPIs to store the length.  */
   unsigned int flags; /* Bit 0: Array to be allocated in secure memory space.*/
-                      /* Bit 2: the limb is a pointer to some m_alloced data.*/
+                      /* Bit 2: The limb is a pointer to some m_alloced data.*/
+                      /* Bit 4: Const MPI - the MPI may not be modified.  */
   mpi_limb_t *d;      /* Array with the limbs */
 };
 
@@ -104,8 +105,12 @@ struct gcry_mpi
   gcry_mpi_t  _gcry_mpi_copy( gcry_mpi_t a );
 #endif
 
-#define mpi_is_opaque(a) ((a) && ((a)->flags&4))
-#define mpi_is_secure(a) ((a) && ((a)->flags&1))
+void _gcry_mpi_immutable_failed (void);
+#define mpi_immutable_failed() _gcry_mpi_immutable_failed ()
+
+#define mpi_is_immutable(a)   ((a) && ((a)->flags&16))
+#define mpi_is_opaque(a)      ((a) && ((a)->flags&4))
+#define mpi_is_secure(a)      ((a) && ((a)->flags&1))
 #define mpi_clear(a)          _gcry_mpi_clear ((a))
 #define mpi_alloc_like(a)     _gcry_mpi_alloc_like((a))
 #define mpi_snatch(a,b)       _gcry_mpi_snatch ((a),(b))