See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch
authorWerner Koch <wk@gnupg.org>
Mon, 24 Jan 2000 11:55:48 +0000 (11:55 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 24 Jan 2000 11:55:48 +0000 (11:55 +0000)
22 files changed:
ChangeLog
Makefile.am
README-alpha [new file with mode: 0644]
cipher/ChangeLog
cipher/pubkey.c
configure.in
doc/Makefile.am
mpi/ChangeLog
mpi/mpi-mpow.c
mpi/mpicoder.c
mpi/mpiutil.c
src/ChangeLog
src/Makefile.am
src/gcrypt.h
src/global.c
src/mpi.h
src/secmem.c [new file with mode: 0644]
src/secmem.h [new file with mode: 0644]
src/sexp.c
src/stdmem.c [new file with mode: 0644]
src/stdmem.h [new file with mode: 0644]
src/wrapper.c

index 31c2173..b5139d5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * jnlib/ : New.
+
+       * configure.in: Do set development version when the version has
+       a dash in it.  Suggested by Dave Dykstra.
+
 Thu Dec  9 17:22:27 CET 1999  Werner Koch  <wk@gnupg.de>
 
        * acinclude.m4 (GNUPG_FIX_HDR_VERSION): New.
index b783612..60fb64c 100644 (file)
@@ -17,7 +17,7 @@ else
 checks = checks
 endif
 
-SUBDIRS = intl zlib util mpi cipher ${gcrypt} g10 po doc ${checks}
+SUBDIRS = intl zlib jnlib util mpi cipher ${gcrypt} g10 po doc ${checks}
 EXTRA_DIST = README-alpha VERSION  PROJECTS BUGS
 # gettext never gets it right, so we take here care of deleting the
 # symlink.  my_clean_gcrypt is just a kludge until we can include
diff --git a/README-alpha b/README-alpha
new file mode 100644 (file)
index 0000000..1b5dfff
--- /dev/null
@@ -0,0 +1,9 @@
+The 1.1 series are the current development branch of GnuPG.
+
+       DO NOT USE IN A PRODUCTION ENVIRONMENT!
+
+The source may change quite often and may have serious
+problems; it may even not compile on some machines.
+
+Use GnuPG from the stable 1.0.x series for real work.
+
index df0eeee..33b04e4 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * pubkey.c (pubkey_nbits): Removed and replaced by ...
+       (gcry_pk_get_nbits): this new one.
+
 Wed Dec  8 21:58:32 CET 1999  Werner Koch  <wk@gnupg.de>
 
        * dsa.c: s/mpi_powm/gcry_mpi_powm/g
index 86b797d..949e3b9 100644 (file)
@@ -196,6 +196,14 @@ setup_pubkey_table(void)
        pubkey_table[i].name = NULL;
 }
 
+static void
+release_mpi_array( MPI *array )
+{
+    for( ; *array; array++ ) {
+       mpi_free(*array);
+       *array = NULL;
+    }
+}
 
 /****************
  * Try to load all modules and return true if new modules are available
@@ -423,27 +431,6 @@ pubkey_get_nenc( int algo )
     return 0;
 }
 
-/****************
- * Get the number of nbits from the public key
- * FIXME: This should also take a S-Expt but must be optimized in
- * some way becuase it is used in keylistsings ans such (store it with the
- * S-Exp as some private data?)
- */
-unsigned
-pubkey_nbits( int algo, MPI *pkey )
-{
-    int i;
-
-    do {
-       for(i=0; pubkey_table[i].name; i++ )
-           if( pubkey_table[i].algo == algo )
-               return (*pubkey_table[i].get_nbits)( algo, pkey );
-    } while( load_pubkey_modules() );
-    if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */
-       return mpi_get_nbits( pkey[0] );
-    return 0;
-}
-
 
 int
 pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
@@ -605,14 +592,6 @@ pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
 }
 
 
-static void
-release_mpi_array( MPI *array )
-{
-    for( ; *array; array++ ) {
-       mpi_free(*array);
-       *array = NULL;
-    }
-}
 
 /****************
  * Convert a S-Exp with either a private or a public key to our
@@ -910,6 +889,41 @@ gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
 }
 
 
+/****************
+ * Get the number of nbits from the public key
+ * Hmmm: Should we have really this function or is it
+ * better to have a more general function to retrieve
+ * different propoerties of the key?
+ */
+unsigned int
+gcry_pk_get_nbits( GCRY_SEXP key )
+{
+    int rc, i, algo;
+    MPI *keyarr;
+    unsigned int nbits = 0;
+
+    rc = sexp_to_key( key, 0, &keyarr, &algo );
+    if( rc == GCRYERR_INV_OBJ )
+       rc = sexp_to_key( key, 0, &keyarr, &algo );
+    if( rc )
+       return 0;
+
+    do {
+       for(i=0; pubkey_table[i].name; i++ )
+           if( pubkey_table[i].algo == algo ) {
+               nbits = (*pubkey_table[i].get_nbits)( algo, keyarr );
+               goto leave;
+           }
+    } while( load_pubkey_modules() );
+    if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */
+       nbits = mpi_get_nbits( keyarr[0] );
+  leave:
+    release_mpi_array( keyarr );
+    return nbits;
+}
+
+
+
 int
 gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
 {
index 2651b87..ff584f5 100644 (file)
@@ -667,7 +667,7 @@ AC_SUBST(ZLIBS)
 changequote(,)dnl
 tmp_pat='[a-zA-Z]'
 changequote([,])dnl
-if echo "$VERSION" | grep "$tmp_pat" >/dev/null ; then
+if echo "$VERSION" | sed 's/-.*//' | grep "$tmp_pat" >/dev/null ; then
     AC_DEFINE(IS_DEVELOPMENT_VERSION)
 fi
 
@@ -720,6 +720,7 @@ AC_OUTPUT([
 Makefile
 intl/Makefile
 po/Makefile.in
+jnlib/Makefile
 util/Makefile
 mpi/Makefile
 cipher/Makefile
index 9d06f9b..39fabf9 100644 (file)
@@ -17,6 +17,8 @@ else
 endif
 
 
+gcryptref.dvi : gcryptref.sgml
+
 %.dvi: %.sgml
        db2dvi $<
 
index 125fa1a..2d2ec8b 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * mpiutil.c: Removed all memory debugging code.
+
+       * mpicoder.c (gcry_mpi_aprint): New.
+
+       * Replaced all m_ memory functions by g10_ ones.
+
 Fri Dec 31 14:06:56 CET 1999  Werner Koch  <wk@gnupg.de>
 
        * mpi-bit.c (gcry_mpi_get_nbits): New.
index a8c561d..556f7e1 100644 (file)
@@ -45,16 +45,16 @@ static int
 build_index( MPI *exparray, int k, int i, int t )
 {
     int j, bitno;
-    int index = 0;
+    int idx = 0;
 
     bitno = t-i;
     for(j=k-1; j >= 0; j-- ) {
-       index <<= 1;
+       idx <<= 1;
        if( mpi_test_bit( exparray[j], bitno ) )
-           index |= 1;
+           idx |= 1;
     }
-    /*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
-    return index;
+    /*log_debug("t=%d i=%d idx=%d\n", t, i, idx );*/
+    return idx;
 }
 
 /****************
@@ -87,7 +87,7 @@ mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
     assert(t);
     assert( k < 10 );
 
-    G = m_alloc_clear( (1<<k) * sizeof *G );
+    G = g10_xcalloc( (1<<k) , sizeof *G );
   #ifdef USE_BARRETT
     barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 );
   #endif
@@ -128,7 +128,7 @@ mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
   #endif
     for(i=0; i < (1<<k); i++ )
        mpi_free(G[i]);
-    m_free(G);
+    g10_free(G);
 }
 
 
index 753c176..ca805f2 100644 (file)
@@ -221,8 +221,8 @@ do_get_buffer( MPI a, unsigned *nbytes, int *sign, int force_secure )
     if( sign )
        *sign = a->sign;
     *nbytes = a->nlimbs * BYTES_PER_MPI_LIMB;
-    p = buffer = force_secure || mpi_is_secure(a) ? m_alloc_secure( *nbytes)
-                                                 : m_alloc( *nbytes );
+    p = buffer = force_secure || mpi_is_secure(a) ? g10_xmalloc_secure( *nbytes)
+                                                 : g10_xmalloc( *nbytes );
 
     for(i=a->nlimbs-1; i >= 0; i-- ) {
        alimb = a->d[i];
@@ -340,6 +340,7 @@ gcry_mpi_scan( struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
     /* TODO: add a way to allocate the MPI in secure memory
      * Hmmm: maybe it is better to retrieve this information from
      * the provided buffer. */
+     #warning secure memory is not used here.
     if( format == GCRYMPI_FMT_STD ) {
        const byte *s = buffer;
 
@@ -458,7 +459,7 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
        }
 
        if( n > len && buffer ) {
-           m_free(tmp);
+           g10_free(tmp);
            return GCRYERR_TOO_SHORT;  /* the provided buffer is too short */
        }
        if( buffer ) {
@@ -468,7 +469,24 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
 
            memcpy( s, tmp, n-extra );
        }
-       m_free(tmp);
+       g10_free(tmp);
+       *nbytes = n;
+       return 0;
+    }
+    else if( format == GCRYMPI_FMT_USG ) {
+       unsigned int n = (nbits + 7)/8;
+
+       /* we ignore the sign for this format */
+       /* FIXME: for performance reasons we should put this into
+        * mpi_aprint becuase we can then use the buffer directly */
+       if( n > len && buffer )
+           return GCRYERR_TOO_SHORT;  /* the provided buffer is too short */
+       if( buffer ) {
+           char *tmp;
+           tmp = mpi_get_buffer( a, &n, NULL );
+           memcpy( buffer, tmp, n );
+           g10_free(tmp);
+       }
        *nbytes = n;
        return 0;
     }
@@ -488,7 +506,7 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
 
            tmp = mpi_get_buffer( a, &n, NULL );
            memcpy( s+2, tmp, n );
-           m_free(tmp);
+           g10_free(tmp);
        }
        *nbytes = n+2;
        return 0;
@@ -508,7 +526,7 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
        }
 
        if( n+4 > len && buffer ) {
-           m_free(tmp);
+           g10_free(tmp);
            return GCRYERR_TOO_SHORT;  /* the provided buffer is too short */
        }
        if( buffer ) {
@@ -522,7 +540,7 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
 
            memcpy( s, tmp, n-extra );
        }
-       m_free(tmp);
+       g10_free(tmp);
        *nbytes = 4+n;
        return 0;
     }
@@ -534,10 +552,10 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
 
        tmp = mpi_get_buffer( a, &n, NULL );
        if( !n || (*tmp & 0x80) )
-           extra=1;
+           extra=2;
 
-       if( 2*n+3+1 > len && buffer ) {
-           m_free(tmp);
+       if( 2*n + extra + !!a->sign + 1 > len && buffer ) {
+           g10_free(tmp);
            return GCRYERR_TOO_SHORT;  /* the provided buffer is too short */
        }
        if( buffer ) {
@@ -559,17 +577,38 @@ gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes,
            *nbytes = (char*)s - buffer;
        }
        else {
-           *nbytes = n;
-           if( a->sign )
-               ++*nbytes;
-           if( extra )
-               *nbytes += 2;
-           ++*nbytes; /* terminating Nul */
+           *nbytes = 2*n + extra + !!a->sign + 1;
        }
-       m_free(tmp);
+       g10_free(tmp);
        return 0;
     }
     else
        return GCRYERR_INV_ARG;
 }
 
+/****************
+ * Like gcry_mpi_print but this function allocates the buffer itself.
+ * The caller has to supply the address of a pointer. nbytes may be
+ * NULL.
+ */
+int
+gcry_mpi_aprint( enum gcry_mpi_format format, void **buffer, size_t *nbytes,
+                struct gcry_mpi *a )
+{
+    size_t n;
+    int rc;
+
+    *buffer = NULL;
+    rc = gcry_mpi_print( format, NULL, &n, a );
+    if( rc )
+       return rc;
+    *buffer = mpi_is_secure(a) ? g10_xmalloc_secure( n ) : g10_xmalloc( n );
+    rc = gcry_mpi_print( format, *buffer, &n, a );
+    if( rc ) {
+       g10_free(*buffer);
+       *buffer = NULL;
+    }
+    return rc;
+}
+
+
index 58d0697..2dad135 100644 (file)
@@ -1,5 +1,5 @@
 /* mpiutil.ac  -  Utility functions for MPI
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -41,8 +41,6 @@ mpi_alloc( unsigned nlimbs )
 {
     MPI a;
 
-    if( DBG_MEMORY )
-       log_debug("mpi_alloc(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
     a = g10_xmalloc( sizeof *a );
     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL;
     a->alloced = nlimbs;
@@ -64,8 +62,6 @@ mpi_alloc_secure( unsigned nlimbs )
 {
     MPI a;
 
-    if( DBG_MEMORY )
-       log_debug("mpi_alloc_secure(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
     a = g10_xmalloc( sizeof *a );
     a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 1 ) : NULL;
     a->alloced = nlimbs;
@@ -83,9 +79,6 @@ mpi_alloc_limb_space( unsigned nlimbs, int secure )
     size_t len = nlimbs * sizeof(mpi_limb_t);
     mpi_ptr_t p;
 
-    if( DBG_MEMORY )
-       log_debug("mpi_alloc_limb_space(%u)\n", (unsigned)len*8 );
-
     p = secure? g10_xmalloc_secure( len ) : g10_xmalloc( len );
 
     return p;
@@ -96,9 +89,6 @@ mpi_free_limb_space( mpi_ptr_t a )
 {
     if( !a )
        return;
-    if( DBG_MEMORY )
-       log_debug("mpi_free_limb_space\n" );
-
     g10_free(a);
 }
 
@@ -147,8 +137,6 @@ mpi_free( MPI a )
 {
     if( !a )
        return;
-    if( DBG_MEMORY )
-       log_debug("mpi_free\n" );
     if( a->flags & 4 )
        g10_free( a->d );
     else {
@@ -385,7 +373,7 @@ gcry_mpi_randomize( GCRY_MPI w,
     char *p = mpi_is_secure(w) ? gcry_random_bytes( (nbits+7)/8, level )
                               : gcry_random_bytes_secure( (nbits+7)/8, level );
     mpi_set_buffer( w, p, (nbits+7)/8, 0 );
-    m_free(p);
+    g10_free(p);
 }
 
 
index d59feab..4c2a5b2 100644 (file)
@@ -1,3 +1,10 @@
+Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+
+       * secmem.c: Moved from ../util to here.
+       * secmem.h: New.
+       * stdmem.c: New. Based on the old ../util/memory.c.
+       * stdmem.h: New.
+
 Wed Dec  8 21:58:32 CET 1999  Werner Koch  <wk@gnupg.de>
 
        * gcrypt.m4: New.
index e88bba1..4117487 100644 (file)
@@ -25,12 +25,15 @@ libgcrypt_la_SOURCES =       mpi.h \
                         global.c \
                         sexp.c \
                         wrapper.c \
-                        memory.c \
-                        secmem.c
+                        stdmem.c \
+                        stdmem.h \
+                        secmem.c \
+                        secmem.h
 
 libgcrypt_la_DEPENDENCIES = libgcrypt.sym
 libgcrypt_la_LIBADD = ../cipher/libcipher.la  \
-                     ../mpi/libmpi.la
+                     ../mpi/libmpi.la \
+                     ../jnlib/libjnlib.la
 
 BUILT_SOURCES = libgcrypt.sym
 
index 4611918..63715d4 100644 (file)
@@ -118,6 +118,14 @@ enum gcry_ctl_cmds {
     GCRYCTL_SET_DEBUG_FLAGS   = 20,
     GCRYCTL_CLEAR_DEBUG_FLAGS = 21,
     GCRYCTL_USE_SECURE_RNDPOOL= 22,
+    GCRYCTL_DUMP_MEMORY_STATS = 23,
+    GCRYCTL_INIT_SECMEM       = 24,
+    GCRYCTL_TERM_SECMEM       = 25,
+    GCRYCTL_DISABLE_SECMEM_WARN = 27,
+    GCRYCTL_SUSPEND_SECMEM_WARN = 28,
+    GCRYCTL_RESUME_SECMEM_WARN = 29,
+    GCRYCTL_DROP_PRIVS         = 30,
+    GCRYCTL_ENABLE_M_GUARD     = 31,
 };
 
 int gcry_control( enum gcry_ctl_cmds, ... );
@@ -210,6 +218,8 @@ int  gcry_mpi_scan( GCRY_MPI *ret_mpi, enum gcry_mpi_format format,
                                       const char *buffer, size_t *nbytes );
 int     gcry_mpi_print( enum gcry_mpi_format format,
                         char *buffer, size_t *nbytes, const GCRY_MPI a );
+int     gcry_mpi_aprint( enum gcry_mpi_format format,
+                         void **buffer, size_t *nbytes, const GCRY_MPI a );
 
 void gcry_mpi_powm( GCRY_MPI w,
                    const GCRY_MPI b, const GCRY_MPI e, const GCRY_MPI m );
@@ -324,6 +334,7 @@ int gcry_pk_ctl( int cmd, void *buffer, size_t buflen);
 int gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes);
 const char *gcry_pk_algo_name( int algo );
 int gcry_pk_map_name( const char* name );
+unsigned int gcry_pk_get_nbits( GCRY_SEXP key );
 
 
 #define gcry_pk_test_algo(a) \
@@ -444,7 +455,8 @@ void *gcry_xmalloc_secure( size_t n );
 void *gcry_xcalloc_secure( size_t n, size_t m );
 void *gcry_xrealloc( void *a, size_t n );
 char *gcry_xstrdup( const char * a);
-void  gcry_free( void *p );
+void  gcry_free( void *a );
+int   gcry_is_secure( const void *a );
 
 
 #ifndef GCRYPT_NO_MPI_MACROS
index 1de2bd6..2e84f4b 100644 (file)
@@ -27,7 +27,8 @@
 #include <assert.h>
 
 #include "g10lib.h"
-#include "memory.h" /* for the m_* functions */
+#include "stdmem.h" /* our own memory allocator */
+#include "secmem.h" /* our own secmem allocator */
 
 /****************
  * flag bits: 0 : general cipher debug
@@ -128,14 +129,47 @@ gcry_control( enum gcry_ctl_cmds cmd, ... )
       case GCRYCTL_SET_FATAL_FNC:
        break;
      #endif
+
+      case GCRYCTL_ENABLE_M_GUARD:
+       g10_private_enable_m_guard();
+       break;
+
       case GCRYCTL_DUMP_RANDOM_STATS:
        random_dump_stats();
        break;
 
+      case GCRYCTL_DUMP_MEMORY_STATS:
+       /*m_print_stats("[fixme: prefix]");*/
+       break;
+
       case GCRYCTL_DUMP_SECMEM_STATS:
        secmem_dump_stats();
        break;
 
+      case GCRYCTL_DROP_PRIVS:
+       secmem_init( 0 );
+       break;
+
+      case GCRYCTL_INIT_SECMEM:
+       secmem_init( va_arg( arg_ptr, unsigned int ) );
+       break;
+
+      case GCRYCTL_TERM_SECMEM:
+       secmem_term();
+       break;
+
+      case GCRYCTL_DISABLE_SECMEM_WARN:
+       secmem_set_flags( secmem_get_flags() | 1 );
+       break;
+
+      case GCRYCTL_SUSPEND_SECMEM_WARN:
+       secmem_set_flags( secmem_get_flags() | 2 );
+       break;
+
+      case GCRYCTL_RESUME_SECMEM_WARN:
+       secmem_set_flags( secmem_get_flags() & ~2 );
+       break;
+
       case GCRYCTL_USE_SECURE_RNDPOOL:
        secure_random_alloc(); /* put random number into secure memory */
        break;
@@ -234,11 +268,11 @@ gcry_set_allocation_handler( void *(*new_alloc_func)(size_t n),
  * ran out of memory.  This handler may do one of these things:
  *   o free some memory and return true, so that the xmalloc function
  *     tries again.
- *   o Do whatever tit like and return false, so that the xmalloc functions
+ *   o Do whatever it like and return false, so that the xmalloc functions
  *     use the default fatal error handler.
  *   o Terminate the program and don't return.
  *
- * The handler function is called with 3 argiments:  The opaque value set with
+ * The handler function is called with 3 arguments:  The opaque value set with
  * this function, the requested memory size, and a flag with these bits
  * currently defined:
  *     bit 0 set = secure memory has been requested.
index 91458d4..e139288 100644 (file)
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -93,7 +93,6 @@ void mpi_swap( MPI a, MPI b);
 
 /*-- mpicoder.c --*/
 int mpi_fromstr(MPI val, const char *str);
-int mpi_print( FILE *fp, MPI a, int mode );
 void g10_log_mpidump( const char *text, MPI a );
 u32 mpi_get_keyid( MPI a, u32 *keyid );
 byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign );
diff --git a/src/secmem.c b/src/secmem.c
new file mode 100644 (file)
index 0000000..7c27de0
--- /dev/null
@@ -0,0 +1,422 @@
+/* secmem.c  - memory allocation from a secure heap
+ *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
+  #include <sys/mman.h>
+  #include <sys/types.h>
+  #include <fcntl.h>
+  #ifdef USE_CAPABILITIES
+    #include <sys/capability.h>
+  #endif
+#endif
+
+#include "types.h"
+#include "secmem.h"
+#include "util.h"
+#include "i18n.h"
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+  #define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#define DEFAULT_POOLSIZE 16384
+
+typedef struct memblock_struct MEMBLOCK;
+struct memblock_struct {
+    unsigned size;
+    union {
+       MEMBLOCK *next;
+       PROPERLY_ALIGNED_TYPE aligned;
+    } u;
+};
+
+
+
+static void  *pool;
+static volatile int pool_okay; /* may be checked in an atexit function */
+static int   pool_is_mmapped;
+static size_t poolsize; /* allocated length */
+static size_t poollen; /* used length */
+static MEMBLOCK *unused_blocks;
+static unsigned max_alloced;
+static unsigned cur_alloced;
+static unsigned max_blocks;
+static unsigned cur_blocks;
+static int disable_secmem;
+static int show_warning;
+static int no_warning;
+static int suspend_warning;
+
+
+static void
+print_warn(void)
+{
+    if( !no_warning )
+       log_info(_("Warning: using insecure memory!\n"));
+}
+
+
+static void
+lock_pool( void *p, size_t n )
+{
+  #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
+    int err;
+
+    cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
+    err = mlock( p, n );
+    if( err && errno )
+       err = errno;
+    cap_set_proc( cap_from_text("cap_ipc_lock+p") );
+
+    if( err ) {
+       if( errno != EPERM
+         #ifdef EAGAIN  /* OpenBSD returns this */
+           && errno != EAGAIN
+         #endif
+         #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
+           && errno != ENOSYS
+         #endif
+         )
+           log_error("can't lock memory: %s\n", strerror(err));
+       show_warning = 1;
+    }
+
+  #elif defined(HAVE_MLOCK)
+    uid_t uid;
+    int err;
+
+    uid = getuid();
+
+  #ifdef HAVE_BROKEN_MLOCK
+    if( uid ) {
+       errno = EPERM;
+       err = errno;
+    }
+    else {
+       err = mlock( p, n );
+       if( err && errno )
+           err = errno;
+    }
+  #else
+    err = mlock( p, n );
+    if( err && errno )
+       err = errno;
+  #endif
+
+    if( uid && !geteuid() ) {
+       if( setuid( uid ) || getuid() != geteuid()  )
+           log_fatal("failed to reset uid: %s\n", strerror(errno));
+    }
+
+    if( err ) {
+       if( errno != EPERM
+         #ifdef EAGAIN  /* OpenBSD returns this */
+           && errno != EAGAIN
+         #endif
+         #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
+           && errno != ENOSYS
+         #endif
+         )
+           log_error("can't lock memory: %s\n", strerror(err));
+       show_warning = 1;
+    }
+
+  #else
+    log_info("Please note that you don't have secure memory on this system\n");
+  #endif
+}
+
+
+static void
+init_pool( size_t n)
+{
+    size_t pgsize;
+
+    poolsize = n;
+
+    if( disable_secmem )
+       log_bug("secure memory is disabled");
+
+  #ifdef HAVE_GETPAGESIZE
+    pgsize = getpagesize();
+  #else
+    pgsize = 4096;
+  #endif
+
+  #if HAVE_MMAP
+    poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
+    #ifdef MAP_ANONYMOUS
+       pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+                                MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+    #else /* map /dev/zero instead */
+    {  int fd;
+
+       fd = open("/dev/zero", O_RDWR);
+       if( fd == -1 ) {
+           log_error("can't open /dev/zero: %s\n", strerror(errno) );
+           pool = (void*)-1;
+       }
+       else {
+           pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+                                     MAP_PRIVATE, fd, 0);
+       }
+    }
+    #endif
+    if( pool == (void*)-1 )
+       log_info("can't mmap pool of %u bytes: %s - using malloc\n",
+                           (unsigned)poolsize, strerror(errno));
+    else {
+       pool_is_mmapped = 1;
+       pool_okay = 1;
+    }
+
+  #endif
+    if( !pool_okay ) {
+       pool = malloc( poolsize );
+       if( !pool )
+           log_fatal("can't allocate memory pool of %u bytes\n",
+                                                      (unsigned)poolsize);
+       else
+           pool_okay = 1;
+    }
+    lock_pool( pool, poolsize );
+    poollen = 0;
+}
+
+
+/* concatenate unused blocks */
+static void
+compress_pool(void)
+{
+    /* fixme: we really should do this */
+}
+
+void
+secmem_set_flags( unsigned flags )
+{
+    int was_susp = suspend_warning;
+
+    no_warning = flags & 1;
+    suspend_warning = flags & 2;
+
+    /* and now issue the warning if it is not longer suspended */
+    if( was_susp && !suspend_warning && show_warning ) {
+       show_warning = 0;
+       print_warn();
+    }
+}
+
+unsigned
+secmem_get_flags(void)
+{
+    unsigned flags;
+
+    flags  = no_warning      ? 1:0;
+    flags |= suspend_warning ? 2:0;
+    return flags;
+}
+
+void
+secmem_init( size_t n )
+{
+    if( !n ) {
+      #ifdef USE_CAPABILITIES
+       /* drop all capabilities */
+       cap_set_proc( cap_from_text("all-eip") );
+
+      #elif !defined(HAVE_DOSISH_SYSTEM)
+       uid_t uid;
+
+       disable_secmem=1;
+       uid = getuid();
+       if( uid != geteuid() ) {
+           if( setuid( uid ) || getuid() != geteuid() )
+               log_fatal("failed to drop setuid\n" );
+       }
+      #endif
+    }
+    else {
+       if( n < DEFAULT_POOLSIZE )
+           n = DEFAULT_POOLSIZE;
+       if( !pool_okay )
+           init_pool(n);
+       else
+           log_error("Oops, secure memory pool already initialized\n");
+    }
+}
+
+
+void *
+secmem_malloc( size_t size )
+{
+    MEMBLOCK *mb, *mb2;
+    int compressed=0;
+
+    if( !pool_okay ) {
+       log_info(
+        _("operation is not possible without initialized secure memory\n"));
+       log_info(_("(you may have used the wrong program for this task)\n"));
+       exit(2);
+    }
+    if( show_warning && !suspend_warning ) {
+       show_warning = 0;
+       print_warn();
+    }
+
+    /* blocks are always a multiple of 32 */
+    size += sizeof(MEMBLOCK);
+    size = ((size + 31) / 32) * 32;
+
+  retry:
+    /* try to get it from the used blocks */
+    for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
+       if( mb->size >= size ) {
+           if( mb2 )
+               mb2->u.next = mb->u.next;
+           else
+               unused_blocks = mb->u.next;
+           goto leave;
+       }
+    /* allocate a new block */
+    if( (poollen + size <= poolsize) ) {
+       mb = (void*)((char*)pool + poollen);
+       poollen += size;
+       mb->size = size;
+    }
+    else if( !compressed ) {
+       compressed=1;
+       compress_pool();
+       goto retry;
+    }
+    else
+       return NULL;
+
+  leave:
+    cur_alloced += mb->size;
+    cur_blocks++;
+    if( cur_alloced > max_alloced )
+       max_alloced = cur_alloced;
+    if( cur_blocks > max_blocks )
+       max_blocks = cur_blocks;
+
+    return &mb->u.aligned.c;
+}
+
+
+void *
+secmem_realloc( void *p, size_t newsize )
+{
+    MEMBLOCK *mb;
+    size_t size;
+    void *a;
+
+    mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+    size = mb->size;
+    if( newsize < size )
+       return p; /* it is easier not to shrink the memory */
+    a = secmem_malloc( newsize );
+    memcpy(a, p, size);
+    memset((char*)a+size, 0, newsize-size);
+    secmem_free(p);
+    return a;
+}
+
+
+void
+secmem_free( void *a )
+{
+    MEMBLOCK *mb;
+    size_t size;
+
+    if( !a )
+       return;
+
+    mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+    size = mb->size;
+    /* This does not make much sense: probably this memory is held in the
+     * cache. We do it anyway: */
+    memset(mb, 0xff, size );
+    memset(mb, 0xaa, size );
+    memset(mb, 0x55, size );
+    memset(mb, 0x00, size );
+    mb->size = size;
+    mb->u.next = unused_blocks;
+    unused_blocks = mb;
+    cur_blocks--;
+    cur_alloced -= size;
+}
+
+
+int
+g10_private_is_secure( const void *p )
+{
+    return p >= pool && p < (void*)((char*)pool+poolsize);
+}
+
+
+
+/****************
+ * Warning:  This code might be called by an interrupt handler
+ *          and frankly, there should really be such a handler,
+ *          to make sure that the memory is wiped out.
+ *          We hope that the OS wipes out mlocked memory after
+ *          receiving a SIGKILL - it really should do so, otherwise
+ *          there is no chance to get the secure memory cleaned.
+ */
+void
+secmem_term()
+{
+    if( !pool_okay )
+       return;
+
+    memset( pool, 0xff, poolsize);
+    memset( pool, 0xaa, poolsize);
+    memset( pool, 0x55, poolsize);
+    memset( pool, 0x00, poolsize);
+  #if HAVE_MMAP
+    if( pool_is_mmapped )
+       munmap( pool, poolsize );
+  #endif
+    pool = NULL;
+    pool_okay = 0;
+    poolsize=0;
+    poollen=0;
+    unused_blocks=NULL;
+}
+
+
+void
+secmem_dump_stats()
+{
+    if( disable_secmem )
+       return;
+    fprintf(stderr,
+               "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
+               cur_alloced, max_alloced, cur_blocks, max_blocks,
+               (ulong)poollen, (ulong)poolsize );
+}
+
diff --git a/src/secmem.h b/src/secmem.h
new file mode 100644 (file)
index 0000000..e1feedf
--- /dev/null
@@ -0,0 +1,35 @@
+/* secmem.h -  internal definitions for secmem
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_SECMEM_H
+#define G10_SECMEM_H 1
+
+void secmem_init( size_t npool );
+void secmem_term( void );
+void *secmem_malloc( size_t size );
+void *secmem_realloc( void *a, size_t newsize );
+void secmem_free( void *a );
+void secmem_dump_stats(void);
+void secmem_set_flags( unsigned flags );
+unsigned secmem_get_flags(void);
+
+int g10_private_is_secure( const void *p );
+
+#endif /* G10_SECMEM_H */
index 4c84448..915c633 100644 (file)
 #include "memory.h"
 
 
-/* FIXME: We should really have the m_lib functions to allow
- *       overriding of the default malloc functions
- * For now use this kludge: */
-#define m_lib_alloc       m_alloc
-#define m_lib_alloc_clear  m_alloc_clear
-#define m_lib_free        m_free
-
-
-
 
 #if 0
 struct sexp_node;
@@ -173,11 +164,11 @@ gcry_sexp_new_data( const char *buffer, size_t length )
 
     if( !length )
        length = strlen(buffer);
-    node = m_alloc_clear( sizeof *node + length );
+    node = g10_xcalloc( 1, sizeof *node + length );
     node->type = ntDATA;
     node->u.data.len = length;
     memcpy(node->u.data.d, buffer, length );
-    list = m_alloc_clear( sizeof *list );
+    list = g10_xcalloc( 1, sizeof *list );
     list->type = ntLIST;
     list->u.list = node;
     return list;
@@ -191,10 +182,10 @@ gcry_sexp_new_mpi( GCRY_MPI mpi )
 {
     NODE list, node;
 
-    node = m_alloc_clear( sizeof *node );
+    node = g10_xcalloc( 1, sizeof *node );
     node->type = ntMPI;
     node->u.mpi = gcry_mpi_copy( mpi );
-    list = m_alloc_clear( sizeof *list );
+    list = g10_xcalloc( 1, sizeof *list );
     list->type = ntLIST;
     list->u.list = node;
     return list;
@@ -254,7 +245,7 @@ gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
     }
 
 
-    head = m_alloc_clear( sizeof *head );
+    head = g10_xcalloc( 1, sizeof *head );
     head->type = ntLIST;
     if( !a->u.list->next ) { /* a has only one item */
        NODE tmp = a;
@@ -290,7 +281,7 @@ gcry_sexp_vlist( GCRY_SEXP a, ... )
        fputs("sexp_vlist: arg 1 is not a list\n", stderr );
        return NULL;
     }
-    head = m_alloc_clear( sizeof *node );
+    head = g10_xcalloc( 1, sizeof *node );
     head->type = ntLIST;
     if( !a->u.list->next ) { /* a has only one item */
        NODE tmp = a;
@@ -645,7 +636,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
                    return -2; /* buffer too short */
                }
                /* make a new list entry */
-               node = m_alloc_clear( sizeof *node + datalen );
+               node = g10_xcalloc( 1, sizeof *node + datalen );
                if( first ) { /* stuff it into the first node */
                    first = 0;
                    node->up = tail;
@@ -687,7 +678,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
                *erroff = p - buffer;
                return -9; /* open display hint */
            }
-           node = m_alloc_clear( sizeof *node );
+           node = g10_xcalloc( 1, sizeof *node );
            if( !head )
                head = node;
            else {
@@ -842,30 +833,30 @@ sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
     algo = algos[i].algo;
     elems1 = algos[i].common_elements;
     elems2 = want_private? algos[i].secret_elements : algos[i].public_elements;
-    array = m_lib_alloc_clear( (strlen(elems1)+strlen(elems2)+1) * sizeof *array );
+    array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array );
     idx = 0;
     for(s=elems1; *s; s++, idx++ ) {
        l2 = gcry_sexp_find_token( list, s, 1 );
        if( !l2 ) {
-           m_lib_free( array );
+           g10_free( array );
            return -5; /* required parameter not found */
        }
        array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
        if( !array[idx] ) {
-           m_lib_free( array );
+           g10_free( array );
            return -6; /* required parameter is invalid */
        }
     }
     for(s=elems2; *s; s++, idx++ ) {
        l2 = gcry_sexp_find_token( list, s, 1 );
        if( !l2 ) {
-           m_lib_free( array );
+           g10_free( array );
            return -5; /* required parameter not found */
        }
        /* FIXME: put the MPI in secure memory when needed */
        array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
        if( !array[idx] ) {
-           m_lib_free( array );
+           g10_free( array );
            return -6; /* required parameter is invalid */
        }
     }
diff --git a/src/stdmem.c b/src/stdmem.c
new file mode 100644 (file)
index 0000000..073c385
--- /dev/null
@@ -0,0 +1,186 @@
+/* stdmem.c  - private memory allocator
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "g10lib.h"
+#include "stdmem.h"
+#include "secmem.h"
+
+
+#define MAGIC_NOR_BYTE 0x55
+#define MAGIC_SEC_BYTE 0xcc
+#define MAGIC_END_BYTE 0xaa
+
+#if SIZEOF_UNSIGNED_LONG == 8
+  #define EXTRA_ALIGN 4
+#else
+  #define EXTRA_ALIGN 0
+#endif
+
+
+static int use_m_guard = 1;
+
+/****************
+ * Warning: Never use this function after any of the functions
+ * here have been used.
+ */
+void
+g10_private_enable_m_guard(void)
+{
+    use_m_guard = 1;
+}
+
+/****************
+ * Allocate memory of size n.
+ * Return NULL if we are out of memory.
+ */
+void *
+g10_private_malloc( size_t n)
+{
+    if( use_m_guard ) {
+       char *p;
+
+       if( !(p = malloc( n + EXTRA_ALIGN+5 )) )
+           return NULL;
+       ((byte*)p)[EXTRA_ALIGN+0] = n;
+       ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ;
+       ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ;
+       ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_NOR_BYTE;
+       p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
+       return p+EXTRA_ALIGN+4;
+    }
+    else {
+       return malloc( n );
+    }
+}
+
+/****************
+ * Allocate memory of size n from the secure memory pool.
+ * Return NULL if we are out of memory.
+ */
+void *
+g10_private_malloc_secure( size_t n)
+{
+    if( use_m_guard ) {
+       char *p;
+
+       if( !(p = secmem_malloc( n +EXTRA_ALIGN+ 5 )) )
+           return NULL;
+       ((byte*)p)[EXTRA_ALIGN+0] = n;
+       ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ;
+       ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ;
+       ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_SEC_BYTE;
+       p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
+       return p+EXTRA_ALIGN+4;
+    }
+    else {
+       return secmem_malloc( n );
+    }
+}
+
+
+/****************
+ * realloc and clear the old space
+ * Return NULL if there is not enoug memory.
+ */
+void *
+g10_private_realloc( void *a, size_t n )
+{
+    if( use_m_guard ) {
+       unsigned char *p = a;
+       void *b;
+       size_t len;
+
+       g10_private_check_heap(p);
+       len  = p[-4];
+       len |= p[-3] << 8;
+       len |= p[-2] << 16;
+       if( len >= n ) /* we don't shrink for now */
+           return a;
+       if( p[-1] == MAGIC_SEC_BYTE )
+           b = g10_private_malloc_secure(n);
+       else
+           b = g10_private_malloc(n);
+       if( !b )
+           return NULL;
+       memcpy(b, a, len );
+       memset(b+len, 0, n-len );
+       g10_private_free( p );
+       return b;
+    }
+    else if( g10_private_is_secure(a) ) {
+       return secmem_realloc( a, n );
+    }
+    else {
+       return realloc( a, n );
+    }
+}
+
+
+void
+g10_private_check_heap( const void *a )
+{
+    if( use_m_guard ) {
+       const byte *p = a;
+       size_t len;
+
+       if( !p )
+           return;
+
+       if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) )
+           g10_log_fatal("memory at %p corrupted (underflow=%02x)\n", p, p[-1] );
+       len  = p[-4];
+       len |= p[-3] << 8;
+       len |= p[-2] << 16;
+       if( p[len] != MAGIC_END_BYTE )
+           g10_log_fatal("memory at %p corrupted (overflow=%02x)\n", p, p[-1] );
+    }
+}
+
+/****************
+ * Free a memory block allocated by this opr the secmem module
+ */
+void
+g10_private_free( void *a )
+{
+    byte *p = a;
+
+    if( !p )
+       return;
+    if( use_m_guard ) {
+       g10_private_check_heap(p);
+       if( g10_private_is_secure(a) )
+           secmem_free(p-EXTRA_ALIGN-4);
+       else {
+           free(p-EXTRA_ALIGN-4);
+       }
+    }
+    else if( g10_private_is_secure(a) )
+       secmem_free(p);
+    else
+       free(p);
+}
+
+
diff --git a/src/stdmem.h b/src/stdmem.h
new file mode 100644 (file)
index 0000000..f7e340f
--- /dev/null
@@ -0,0 +1,32 @@
+/* stdmem.h -  internal definitions for stdmem
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_STDMEM_H
+#define G10_STDMEM_H 1
+
+void g10_private_enable_m_guard(void);
+
+void *g10_private_malloc( size_t n);
+void *g10_private_malloc_secure( size_t n);
+void *g10_private_realloc( void *a, size_t n );
+void g10_private_check_heap( const void *a );
+void g10_private_free( void *a );
+
+#endif /* G10_STDMEM_H */
index 3b486de..c38e0a4 100644 (file)
@@ -1,4 +1,4 @@
-/* wrapper.c  -  wrapper around some inertal functions
+/* wrapper.c  -  wrapper around the internal functions
  *     Copyright (C) 1999 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -38,4 +38,5 @@ void *gcry_xcalloc_secure( size_t n, size_t m )
 void *gcry_xrealloc( void *a, size_t n ) { return g10_xrealloc( a, n ); }
 char *gcry_xstrdup( const char * a)     { return g10_xstrdup( a); }
 void  gcry_free( void *p )              { g10_free( p ); }
+int   gcry_is_secure( const void *p )   { g10_is_secure( p ); }