From 1fecae98ee7e0fa49b29f98efa6817ca121ed98a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Mar 2013 20:20:42 +0100 Subject: Add GCRYMPI_FLAG_IMMUTABLE to help debugging. * 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 | 1 + doc/gcrypt.texi | 47 ++++++++++++++++++++++------- mpi/mpi-bit.c | 93 +++++++++++++++++++++++++++++++++++++++++---------------- mpi/mpicoder.c | 6 ++++ mpi/mpiutil.c | 48 +++++++++++++++++++++++++---- src/gcrypt.h.in | 3 +- src/mpi.h | 11 +++++-- 7 files changed, 164 insertions(+), 45 deletions(-) diff --git a/NEWS b/NEWS index 733dd88e..3a4ca4c0 100644 --- 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) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index c986ec7f..bfc825d6 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -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}}) diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c index cdc6b0b3..74042e89 100644 --- a/mpi/mpi-bit.c +++ b/mpi/mpi-bit.c @@ -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. */ diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index a3435ed1..06d5553e 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -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; diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c index d410d90b..64a2f7e1 100644 --- a/mpi/mpiutil.c +++ b/mpi/mpiutil.c @@ -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*/ diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 57b841eb..9f6438ce 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -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. */ }; diff --git a/src/mpi.h b/src/mpi.h index 23afa683..93ad8897 100644 --- 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)) -- cgit v1.2.1