This is a revision of a patch we posted earlier.  It's much better.  It should 
compile on any system that has mmap, mprotect, madvise. We would like to thank 
Dr. Stephen Henson, Fedor Indutny, Willem Pinckaers and, in particular, Tim 
Hudson for feedback and review. No endorsement by any of them is implied. There 
are certainly other, finer-grain, approaches, and we are not confident that all 
intermediate forms that might be used in any calculations are kept in the 
secure heap; we encourage further review and feedback.

The following description is taken from the documentation:

In order to help protect applications (particularly long-running servers) from 
pointer overruns or underruns that could return arbitrary data from
the program's dynamic memory area, where keys and other sensitive information 
might be stored, OpenSSL supports the concept of a "secure heap."
The level and type of security guarantees depend on the operating system. It is 
a good idea to review the code and see if it addresses your threat model and 
concerns.

If a secure heap is used, then all B<BIGNUM> values are stored in that heap. 
This is more than strictly necessary -- the public part of an RSA key, for 
example, need not be kept private -- but it is a secure approach and least 
invasive to the OpenSSL source code.

Thanks.

                /rich $alz

--
Principal Security Engineer
Akamai Technology
Cambridge, MA
Jabber: rs...@jabber.me<mailto:rs...@jabber.me>; twitter: RichSalz
--- //sandbox/rsalz/ak-openssl/apps/version.c   2014-04-16 15:49:56.000000000 
0000
+++ /home/rsalz/p4/misc/ak-openssl/apps/version.c       2014-04-16 
15:49:56.000000000 0000
@@ -140,7 +140,7 @@
 int MAIN(int argc, char **argv)
        {
        int i,ret=0;
-       int cflags=0,version=0,date=0,options=0,platform=0,dir=0;
+       int cflags=0,version=0,date=0,options=0,platform=0,dir=0,secheap=0;
 
        apps_startup();
 
@@ -163,11 +163,13 @@
                        platform=1;
                else if (strcmp(argv[i],"-d") == 0)
                        dir=1;
+               else if (strcmp(argv[i],"-s") == 0)
+                       secheap=1;
                else if (strcmp(argv[i],"-a") == 0)
-                       date=version=cflags=options=platform=dir=1;
+                       date=version=cflags=options=platform=dir=secheap=1;
                else
                        {
-                       BIO_printf(bio_err,"usage:version -[avbofpd]\n");
+                       BIO_printf(bio_err,"usage:version -[avbofpds]\n");
                        ret=1;
                        goto end;
                        }
@@ -187,6 +189,7 @@
                        }
                }
        if (date)    printf("%s\n",SSLeay_version(SSLEAY_BUILT_ON));
+       if (secheap) printf("%s\n",SSLeay_version(SSLEAY_SECURE_HEAP));
        if (platform) printf("%s\n",SSLeay_version(SSLEAY_PLATFORM));
        if (options) 
                {
--- //sandbox/rsalz/ak-openssl/crypto/Makefile  2014-04-16 15:49:56.000000000 
0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/Makefile      2014-04-16 
15:49:56.000000000 0000
@@ -35,8 +35,10 @@
 LIB= $(TOP)/libcrypto.a
 SHARED_LIB= libcrypto$(SHLIB_EXT)
 LIBSRC=        cryptlib.c mem.c mem_clr.c mem_dbg.c cversion.c ex_data.c 
cpt_err.c \
+       sec_mem.c \
        ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fips.c o_init.c fips_ers.c
 LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o cpt_err.o ebcdic.o \
+       sec_mem.o \
        uid.o o_time.o o_str.o o_dir.o o_fips.o o_init.o fips_ers.o $(CPUID_OBJ)
 
 SRC= $(LIBSRC)
--- //sandbox/rsalz/ak-openssl/crypto/bn/bn.h   2014-04-16 15:49:56.000000000 
0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/bn/bn.h       2014-04-16 
15:49:56.000000000 0000
@@ -272,6 +272,7 @@
 #endif /* defined(OPENSSL_SYS_VMS) [else] */
 
 #define BN_DEFAULT_BITS        1280
+#define BN_MAX_WORDS   (16*1024) /* maximum heap size to use */
 
 #define BN_FLG_MALLOCED                0x01
 #define BN_FLG_STATIC_DATA     0x02
--- //sandbox/rsalz/ak-openssl/crypto/bn/bn_lib.c       2014-04-16 
15:49:56.000000000 0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/bn/bn_lib.c   2014-04-16 
15:49:56.000000000 0000
@@ -245,7 +245,13 @@
                {
                OPENSSL_cleanse(a->d,a->dmax*sizeof(a->d[0]));
                if (!(BN_get_flags(a,BN_FLG_STATIC_DATA)))
+                       {
+#ifndef OPENSSL_NO_SECURE_HEAP
+                       OPENSSL_secure_free(a->d);
+#else
                        OPENSSL_free(a->d);
+#endif
+                       }
                }
        i=BN_get_flags(a,BN_FLG_MALLOCED);
        OPENSSL_cleanse(a,sizeof(BIGNUM));
@@ -258,7 +264,13 @@
        if (a == NULL) return;
        bn_check_top(a);
        if ((a->d != NULL) && !(BN_get_flags(a,BN_FLG_STATIC_DATA)))
+               {
+#ifndef OPENSSL_NO_SECURE_HEAP
+               OPENSSL_secure_free(a->d);
+#else
                OPENSSL_free(a->d);
+#endif
+               }
        if (a->flags & BN_FLG_MALLOCED)
                OPENSSL_free(a);
        else
@@ -314,7 +326,16 @@
                
BNerr(BN_F_BN_EXPAND_INTERNAL,BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
                return(NULL);
                }
+#ifndef OPENSSL_NO_SECURE_HEAP
+       if (CRYPTO_secure_malloc_initialized() && (words > BN_MAX_WORDS))
+               {
+               BNerr(BN_F_BN_EXPAND_INTERNAL,BN_R_BIGNUM_TOO_LONG);
+               return NULL;
+               }
+       a=A=(BN_ULONG *)OPENSSL_secure_malloc(sizeof(BN_ULONG)*words);
+#else
        a=A=(BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG)*words);
+#endif
        if (A == NULL)
                {
                BNerr(BN_F_BN_EXPAND_INTERNAL,ERR_R_MALLOC_FAILURE);
@@ -401,7 +422,11 @@
                        else
                                {
                                /* r == NULL, BN_new failure */
+#ifndef OPENSSL_NO_SECURE_HEAP
+                               OPENSSL_secure_free(a);
+#else
                                OPENSSL_free(a);
+#endif
                                }
                        }
                /* If a == NULL, there was an error in allocation in
@@ -431,7 +456,11 @@
                {
                BN_ULONG *a = bn_expand_internal(b, words);
                if(!a) return NULL;
+#ifndef OPENSSL_NO_SECURE_HEAP
+               if(b->d) OPENSSL_secure_free(b->d);
+#else
                if(b->d) OPENSSL_free(b->d);
+#endif
                b->d=a;
                b->dmax=words;
                }
--- //sandbox/rsalz/ak-openssl/crypto/crypto.h  2014-04-16 15:49:56.000000000 
0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/crypto.h      2014-04-16 
15:49:56.000000000 0000
@@ -152,6 +152,7 @@
 #define SSLEAY_BUILT_ON                3
 #define SSLEAY_PLATFORM                4
 #define SSLEAY_DIR             5
+#define SSLEAY_SECURE_HEAP      6
 
 /* Already declared in ossl_typ.h */
 #if 0
@@ -463,7 +464,7 @@
 /* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions --
  * call the latter last if you need different functions */
 int CRYPTO_set_mem_functions(void *(*m)(size_t),void *(*r)(void *,size_t), 
void (*f)(void *));
-int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*free_func)(void 
*));
+int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*f)(void *));
 int CRYPTO_set_mem_ex_functions(void *(*m)(size_t,const char *,int),
                                 void *(*r)(void *,size_t,const char *,int),
                                 void (*f)(void *));
@@ -497,6 +498,29 @@
                           int line);
 void *CRYPTO_remalloc(void *addr,int num, const char *file, int line);
 
+#ifndef OPENSSL_NO_SECURE_HEAP
+#define OPENSSL_secure_malloc(num) \
+        CRYPTO_secure_malloc((int)num,__FILE__,__LINE__)
+#define OPENSSL_secure_free(addr) \
+        CRYPTO_secure_free(addr)
+
+int CRYPTO_secure_malloc_init(size_t sz, int minsize);
+void CRYPTO_secure_malloc_done();
+void *CRYPTO_secure_malloc(int num, const char *file, int line);
+void CRYPTO_secure_free(void *ptr);
+int CRYPTO_secure_allocated(const void *ptr);
+int CRYPTO_secure_malloc_initialized();
+
+int CRYPTO_set_secure_mem_functions(void *(*m)(size_t), void (*f)(void *));
+int CRYPTO_set_secure_mem_ex_functions(
+        void *(*m)(size_t,const char *,int),
+        void (*f)(void *));
+void CRYPTO_get_secure_mem_functions(void *(**m)(size_t), void (**f)(void *));
+void CRYPTO_get_secure_mem_ex_functions(
+        void *(**m)(size_t,const char *,int),
+        void (**f)(void *));
+#endif
+
 void OPENSSL_cleanse(void *ptr, size_t len);
 
 void CRYPTO_set_mem_debug_options(long bits);
--- //sandbox/rsalz/ak-openssl/crypto/cversion.c        2014-04-16 
15:49:56.000000000 0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/cversion.c    2014-04-16 
15:49:56.000000000 0000
@@ -107,6 +107,14 @@
                return "OPENSSLDIR: N/A";
 #endif
                }
+       if (t == SSLEAY_SECURE_HEAP)
+               {
+#ifndef OPENSSL_NO_SECURE_HEAP
+               return "Secure heap: available";
+#else
+               return "Secure heap: not available";
+#endif
+               }
        return("not available");
        }
 
--- //sandbox/rsalz/ak-openssl/crypto/mem.c     2014-04-16 15:49:56.000000000 
0000
+++ /home/rsalz/p4/misc/ak-openssl/crypto/mem.c 2014-04-16 15:49:56.000000000 
0000
@@ -89,6 +89,15 @@
 
 static void (*free_func)(void *)            = free;
 
+#ifndef OPENSSL_NO_SECURE_HEAP
+static void *(*malloc_secure_func)(size_t)         = malloc;
+static void *default_malloc_secure_ex(size_t num, const char *file, int line)
+       { return malloc_secure_func(num); }
+static void *(*malloc_secure_ex_func)(size_t, const char *file, int line)
+        = default_malloc_secure_ex;
+static void (*free_secure_func)(void *)            = free;
+#endif
+
 static void *(*malloc_locked_func)(size_t)  = malloc;
 static void *default_malloc_locked_ex(size_t num, const char *file, int line)
        { return malloc_locked_func(num); }
@@ -133,6 +142,12 @@
        malloc_func=m; malloc_ex_func=default_malloc_ex;
        realloc_func=r; realloc_ex_func=default_realloc_ex;
        free_func=f;
+        /* If user wants to intercept the secure or locked functions, do it
+         * after the basic functions. */
+#ifndef OPENSSL_NO_SECURE_HEAP
+       malloc_secure_func=m; malloc_secure_ex_func=default_malloc_secure_ex;
+       free_secure_func=f;
+#endif
        malloc_locked_func=m; malloc_locked_ex_func=default_malloc_locked_ex;
        free_locked_func=f;
        return 1;
@@ -150,10 +165,49 @@
        malloc_func=0; malloc_ex_func=m;
        realloc_func=0; realloc_ex_func=r;
        free_func=f;
+#ifndef OPENSSL_NO_SECURE_HEAP
+       malloc_secure_func=0; malloc_secure_ex_func=m;
+       free_secure_func=f;
+#endif
+       malloc_locked_func=0; malloc_locked_ex_func=m;
+       free_locked_func=f;
+       return 1;
+       }
+
+#ifndef OPENSSL_NO_SECURE_HEAP
+int CRYPTO_set_secure_mem_functions(void *(*m)(size_t), void (*f)(void *))
+        {
+       /* Dummy call just to ensure OPENSSL_init() gets linked in */
+       OPENSSL_init();
+       if (!allow_customize)
+               return 0;
+       if ((m == 0) || (f == 0))
+               return 0;
+        malloc_secure_func=m; malloc_secure_ex_func=default_malloc_secure_ex;
+        free_secure_func=f;
+        /* If user wants to intercept the locked functions, do it after
+         * the secure functions. */
+        malloc_locked_func=m; malloc_locked_ex_func=default_malloc_secure_ex;
+        free_locked_func=f;
+        return 1;
+        }
+
+int CRYPTO_set_secure_mem_ex_functions(
+        void *(*m)(size_t,const char *,int),
+        void (*f)(void *))
+       {
+       if (!allow_customize)
+               return 0;
+       if ((m == NULL) || (f == NULL))
+               return 0;
+       malloc_secure_func=0; malloc_secure_ex_func=m;
+       free_secure_func=f;
        malloc_locked_func=0; malloc_locked_ex_func=m;
        free_locked_func=f;
        return 1;
        }
+#endif
+
 
 int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*f)(void *))
        {
@@ -219,6 +273,24 @@
        if (f != NULL) *f=free_func;
        }
 
+#ifndef OPENSSL_NO_SECURE_HEAP
+void CRYPTO_get_secure_mem_functions(void *(**m)(size_t), void (**f)(void *))
+       {
+       if (m != NULL) *m = (malloc_secure_ex_func == default_malloc_secure_ex) 
? 
+                            malloc_secure_func : 0;
+       if (f != NULL) *f=free_secure_func;
+       }
+
+void CRYPTO_get_secure_mem_ex_functions(
+        void *(**m)(size_t,const char *,int),
+        void (**f)(void *))
+       {
+       if (m != NULL) *m = (malloc_secure_ex_func != default_malloc_secure_ex) 
?
+                           malloc_secure_ex_func : 0;
+       if (f != NULL) *f=free_secure_func;
+       }
+#endif
+
 void CRYPTO_get_locked_mem_functions(void *(**m)(size_t), void (**f)(void *))
        {
        if (m != NULL) *m = (malloc_locked_ex_func == default_malloc_locked_ex) 
? 
--- /dev/null   2014-04-16 11:40:30.444317870 -0400
+++ crypto/sec_mem.c    2014-04-18 16:00:07.000000000 -0400
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2004-2014, Akamai Technologies. All Rights Reserved.
+ * This file is distributed under the terms of the OpenSSL license.
+ */
+
+/*
+ * This file is in two halves. The first half implements the public API
+ * to be used by external consumers, and to be used by OpenSSL to store
+ * data in a "secure arena." The second half implements the secure arena.
+ * For details on that implementation, see below (look for uppercase
+ * "SECURE HEAP IMPLEMENTATION").
+ */
+#include <openssl/crypto.h>
+#include <stdlib.h>  
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#ifndef OPENSSL_NO_SECURE_HEAP
+
+#ifdef AKAMAI_BUILD
+#include <pthread.h>
+static pthread_mutex_t secure_allocation_lock = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK()         pthread_mutex_lock(&secure_allocation_lock)
+#define UNLOCK()       pthread_mutex_unlock(&secure_allocation_lock)
+#define CLEAR(p, s)    memset(p, 0, s)
+#else
+#define LOCK()                 CRYPTO_w_lock(CRYPTO_LOCK_MALLOC)
+#define UNLOCK()       CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC)
+#define CLEAR(p, s)    OPENSSL_cleanse(p, s)
+#define PAGE_SIZE      4096
+#endif
+
+size_t secure_mem_used;
+
+static int secure_mem_initialized;
+static int too_late;
+
+/*
+ * These are the functions that must be implemented by a secure heap (sh).
+ */
+static int sh_init(size_t size, int minsize);
+static void *sh_malloc(size_t size);
+static void sh_free(void *ptr);
+static void sh_done();
+static int sh_actual_size(void *ptr);
+static int sh_allocated(const void *ptr);
+
+
+int CRYPTO_secure_malloc_init(size_t size, int minsize)
+       {
+       int ret = 0;
+
+        if (too_late)
+                return 0;
+       LOCK();
+       OPENSSL_assert(!secure_mem_initialized);
+       if (!secure_mem_initialized)
+               {
+               ret = sh_init(size, minsize);
+               secure_mem_initialized = 1;
+               }
+       UNLOCK();
+       return ret;
+       }
+
+
+void CRYPTO_secure_malloc_done()
+       {
+       LOCK();
+       sh_done();
+       secure_mem_initialized = 0;
+       UNLOCK();
+       }
+
+int CRYPTO_secure_malloc_initialized()
+       {
+       return secure_mem_initialized;
+       }
+
+void *CRYPTO_secure_malloc(int num, const char *file, int line)
+       {
+       void *ret;
+       size_t actual_size;
+
+       if (!secure_mem_initialized)
+                {
+                too_late = 1;
+               return CRYPTO_malloc(num, file, line);
+                }
+       LOCK();
+       ret = sh_malloc(num);
+       actual_size = ret ? sh_actual_size(ret) : 0;
+       secure_mem_used += actual_size;
+       UNLOCK();
+       return ret;
+       }
+
+
+void CRYPTO_secure_free(void *ptr)
+       {
+       size_t actual_size;
+
+       if (ptr == NULL)
+               return;
+       if (!secure_mem_initialized)
+               {
+               CRYPTO_free(ptr);
+               return;
+               }
+       LOCK();
+       actual_size = sh_actual_size(ptr);
+       CLEAR(ptr, actual_size);
+       secure_mem_used -= actual_size;
+       sh_free(ptr);
+       UNLOCK();
+       }
+
+int CRYPTO_secure_allocated(const void *ptr)
+       {
+       int ret;
+       
+       if (!secure_mem_initialized)
+               return 0;
+       LOCK();
+       ret = sh_allocated(ptr);
+       UNLOCK();
+       return ret;
+       }
+
+/* END OF PAGE ...
+
+... START OF PAGE */
+
+/*
+ * SECURE HEAP IMPLEMENTATION
+ */
+
+
+/*
+ * The implementation provided here uses a fixed-sized mmap() heap,
+ * which is locked into memory, not written to core files, and protected
+ * on either side by an unmapped page, which will catch pointer overruns
+ * (or underruns) and an attempt to read data out of the secure heap.
+ * Free'd memory is zero'd or otherwise cleansed.
+ *
+ * This is a pretty standard buddy allocator.  We keep areas in a multiple
+ * of "sh.minsize" units.  The freelist and bitmaps are kept separately,
+ * so all (and only) data is kept in the mmap'd heap.
+ *
+ * This code assumes eight-bit bytes.  The numbers 3 and 7 are all over the
+ * place.
+ */
+
+#define TESTBIT(t, b)  (t[(b) >> 3] &  (1 << ((b) & 7)))
+#define SETBIT(t, b)   (t[(b) >> 3] |= (1 << ((b) & 7)))
+#define CLEARBIT(t, b) (t[(b) >> 3] &= (0xFF & ~(1 << ((b) & 7))))
+
+#define WITHIN_ARENA(p) \
+       ((void*)(p) >= sh.arena && (void*)(p) < sh.arena + sh.arena_size)
+#define WITHIN_FREELIST(p) \
+       ((void*)(p) >= (void*)sh.freelist && (void*)(p) < 
(void*)&sh.freelist[sh.freelist_size])
+
+
+typedef struct sh_list_st
+       {
+       struct sh_list_st *next;
+       struct sh_list_st **p_next;
+       } SH_LIST;
+
+typedef struct sh_st
+       {
+       char* map_result;
+       size_t map_size;
+       void *arena;
+       int arena_size;
+       void **freelist;
+       int freelist_size;
+       int minsize;
+       unsigned char *bittable;
+       unsigned char *bitmalloc;
+       int bittable_size; /* size in bits */
+       } SH;
+
+static SH sh;
+
+
+static int sh_getlist(void *ptr)
+       {
+       int list = sh.freelist_size - 1;
+       int bit = (sh.arena_size + ptr - sh.arena) / sh.minsize;
+
+       for (; bit; bit >>= 1, list--)
+               {
+               if (TESTBIT(sh.bittable, bit))
+                       break;
+               OPENSSL_assert((bit & 1) == 0);
+               }
+
+       return list;
+       }
+
+
+static int sh_testbit(void *ptr, int list, unsigned char *table)
+       {
+       int bit;
+
+       OPENSSL_assert(list >= 0 && list < sh.freelist_size);
+       OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
+       bit = (1 << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
+       OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
+       return TESTBIT(table, bit);
+       }
+
+static void sh_clearbit(void *ptr, int list, unsigned char *table)
+       {
+       int bit;
+
+       OPENSSL_assert(list >= 0 && list < sh.freelist_size);
+       OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
+       bit = (1 << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
+       OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
+       OPENSSL_assert(TESTBIT(table, bit));
+       CLEARBIT(table, bit);
+       }
+
+static void sh_setbit(void *ptr, int list, unsigned char *table)
+       {
+       int bit;
+
+       OPENSSL_assert(list >= 0 && list < sh.freelist_size);
+       OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
+       bit = (1 << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
+       OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
+       OPENSSL_assert(!TESTBIT(table, bit));
+       SETBIT(table, bit);
+       }
+
+static void sh_add_to_list(void **list, void *ptr)
+       {
+       SH_LIST *temp;
+
+       OPENSSL_assert(WITHIN_FREELIST(list));
+       OPENSSL_assert(WITHIN_ARENA(ptr));
+
+       temp = (SH_LIST *)ptr;
+       temp->next = *(SH_LIST **)list;
+       OPENSSL_assert(temp->next == NULL || WITHIN_ARENA(temp->next));
+       temp->p_next = (SH_LIST **)list;
+
+       if (temp->next != NULL)
+               {
+               OPENSSL_assert((void **)temp->next->p_next == list);
+               temp->next->p_next = &(temp->next);
+               }
+
+       *list = ptr;
+       }
+
+static void sh_remove_from_list(void *ptr, void *list)
+       {
+       SH_LIST *temp, *temp2;
+
+       temp = (SH_LIST *)ptr;
+       if (temp->next != NULL)
+               temp->next->p_next = temp->p_next;
+       *temp->p_next = temp->next;
+       if (temp->next == NULL)
+               return;
+
+       temp2 = temp->next;
+       OPENSSL_assert(WITHIN_FREELIST(temp2->p_next) || 
WITHIN_ARENA(temp2->p_next));
+       }
+
+
+static int sh_init(size_t size, int minsize)
+       {
+       int i, ret;
+       size_t pgsize;
+       size_t aligned;
+
+       memset(&sh, 0, sizeof sh);
+
+       /* make sure size and minsize are powers of 2 */
+       OPENSSL_assert(size > 0);
+       OPENSSL_assert((size & (size - 1)) == 0);
+       OPENSSL_assert(minsize > 0);
+       OPENSSL_assert((minsize & (minsize - 1)) == 0);
+       if (size <= 0 || (size & (size - 1)) != 0)
+               goto err;
+       if (minsize <= 0 || (minsize & (minsize - 1)) != 0)
+               goto err;
+
+       sh.arena_size = size;
+       sh.minsize = minsize;
+       sh.bittable_size = (sh.arena_size / sh.minsize) * 2;
+
+       sh.freelist_size = -1;
+       for (i = sh.bittable_size; i; i >>= 1)
+               sh.freelist_size++;
+
+       sh.freelist = OPENSSL_malloc(sh.freelist_size * sizeof (void *));
+       OPENSSL_assert(sh.freelist != NULL);
+       if (sh.freelist == NULL)
+               goto err;
+       memset(sh.freelist, 0, sh.freelist_size * sizeof (void *));
+
+       sh.bittable = OPENSSL_malloc(sh.bittable_size >> 3);
+       OPENSSL_assert(sh.bittable != NULL);
+       if (sh.bittable == NULL)
+               goto err;
+       memset(sh.bittable, 0, sh.bittable_size >> 3);
+
+       sh.bitmalloc = OPENSSL_malloc(sh.bittable_size >> 3);
+       OPENSSL_assert(sh.bitmalloc != NULL);
+       if (sh.bitmalloc == NULL)
+               goto err;
+       memset(sh.bitmalloc, 0, sh.bittable_size >> 3);
+
+       /* Allocate space for heap, and two extra pages as guards */
+#ifdef _SC_PAGE_SIZE
+       pgsize = (size_t)sysconf(_SC_PAGE_SIZE);
+#else
+       pgsize = PAGE_SIZE;
+#endif
+       sh.map_size = pgsize + sh.arena_size + pgsize;
+       sh.map_result = mmap(NULL, sh.map_size,
+               PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+       OPENSSL_assert(sh.map_result != MAP_FAILED);
+       if (sh.map_result == MAP_FAILED)
+               goto err;
+       sh.arena = (void *)(sh.map_result + pgsize);
+       sh_setbit(sh.arena, 0, sh.bittable);
+       sh_add_to_list(&sh.freelist[0], sh.arena);
+
+       /* Now try to add guard pages and lock into memory. */
+       ret = 1;
+
+       /* Starting guard is already aligned from mmap. */
+       if (mprotect(sh.map_result, pgsize, PROT_NONE) < 0)
+               ret = 2;
+
+       /* Ending guard page - need to round up to page boundary */
+       aligned = (pgsize + sh.arena_size + (pgsize - 1)) & ~(pgsize - 1);
+       if (mprotect(sh.map_result + aligned, pgsize, PROT_NONE) < 0)
+               ret = 2;
+
+       if (mlock(sh.arena, sh.arena_size) < 0)
+               ret = 2;
+#ifdef MADV_DONTDUMP
+       if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0)
+               ret = 2;
+#endif
+
+       return ret;
+
+err:
+       sh_done();
+       return 0;
+       }
+
+static void sh_done()
+       {
+       if (sh.freelist)
+               OPENSSL_free(sh.freelist);
+       if (sh.bittable)
+               OPENSSL_free(sh.bittable);
+       if (sh.bitmalloc)
+               OPENSSL_free(sh.bittable);
+       if (sh.map_result != NULL && sh.map_size)
+               munmap(sh.map_result, sh.map_size);
+       memset(&sh, 0, sizeof sh);
+       }
+
+static int sh_allocated(const void *ptr)
+       {
+       return WITHIN_ARENA(ptr) ? 1 : 0;
+       }
+
+static void *sh_find_my_buddy(void *ptr, int list)
+       {
+       int bit;
+       void *chunk = NULL;
+
+       bit = (1 << list) + (ptr - sh.arena) / (sh.arena_size >> list);
+       bit ^= 1;
+
+       if (TESTBIT(sh.bittable, bit) && !TESTBIT(sh.bitmalloc, bit))
+               chunk = sh.arena + ((bit & ((1 << list) - 1)) * (sh.arena_size 
>> list));
+
+       return chunk;
+       }
+
+static void *sh_malloc(size_t size)
+       {
+       int i, list, slist;
+       void *chunk;
+
+       list = sh.freelist_size - 1;
+       for (i = sh.minsize; i < size; i <<= 1)
+               list--;
+       if (list < 0)
+               return NULL;
+
+       /* try to find a larger entry to split */
+       for (slist = list; slist >= 0; slist--)
+               if (sh.freelist[slist] != NULL)
+                       break;
+       if (slist < 0)
+               return NULL;
+
+       /* split larger entry */
+       while (slist != list)
+               {
+               void *temp = sh.freelist[slist];
+
+               /* remove from bigger list */
+               OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
+               sh_clearbit(temp, slist, sh.bittable);
+               sh_remove_from_list(temp, sh.freelist[slist]);
+               OPENSSL_assert(temp != sh.freelist[slist]);
+
+               /* done with bigger list */
+               slist++;
+
+               /* add to smaller list */
+               OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
+               sh_setbit(temp, slist, sh.bittable);
+               sh_add_to_list(&sh.freelist[slist], temp);
+               OPENSSL_assert(sh.freelist[slist] == temp);
+
+               /* split in 2 */
+               temp += sh.arena_size >> slist;
+               OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
+               sh_setbit(temp, slist, sh.bittable);
+               sh_add_to_list(&sh.freelist[slist], temp);
+               OPENSSL_assert(sh.freelist[slist] == temp);
+
+               OPENSSL_assert(temp-(sh.arena_size >> slist) == 
sh_find_my_buddy(temp, slist));
+               }
+
+       /* peel off memory to hand back */
+       chunk = sh.freelist[list];
+       OPENSSL_assert(sh_testbit(chunk, list, sh.bittable));
+       sh_setbit(chunk, list, sh.bitmalloc);
+       sh_remove_from_list(chunk, sh.freelist[list]);
+
+       OPENSSL_assert(WITHIN_ARENA(chunk));
+
+       return chunk;
+       }
+
+
+static void sh_free(void *ptr)
+       {
+       int list;
+       void *buddy;
+
+       if (ptr == NULL)
+               return;
+       OPENSSL_assert(WITHIN_ARENA(ptr));
+       if (!WITHIN_ARENA(ptr))
+               return;
+
+       list = sh_getlist(ptr);
+       OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
+       sh_clearbit(ptr, list, sh.bitmalloc);
+       sh_add_to_list(&sh.freelist[list], ptr);
+
+       /* Try to coalesce two adjacent free areas. */
+       while ((buddy = sh_find_my_buddy(ptr, list)) != NULL)
+               {
+               OPENSSL_assert(ptr == sh_find_my_buddy(buddy, list));
+               OPENSSL_assert(ptr != NULL);
+               OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
+               sh_clearbit(ptr, list, sh.bittable);
+               sh_remove_from_list(ptr, sh.freelist[list]);
+               OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
+               sh_clearbit(buddy, list, sh.bittable);
+               sh_remove_from_list(buddy, sh.freelist[list]);
+
+               list--;
+
+               if (ptr > buddy)
+                       ptr = buddy;
+
+               OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
+               sh_setbit(ptr, list, sh.bittable);
+               sh_add_to_list(&sh.freelist[list], ptr);
+               OPENSSL_assert(sh.freelist[list] == ptr);
+               }
+       }
+
+static int sh_actual_size(void *ptr)
+       {
+       int list;
+
+       OPENSSL_assert(WITHIN_ARENA(ptr));
+       if (!WITHIN_ARENA(ptr))
+               return 0;
+       list = sh_getlist(ptr);
+       OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
+       return sh.arena_size / (1 << list);
+       }
+
+#endif
--- /dev/null   2014-04-16 11:40:30.444317870 -0400
+++ doc/crypto/CRYPTO_secure_malloc.pod 2014-04-18 16:08:38.000000000 -0400
@@ -0,0 +1,92 @@
+=pod
+
+=head1 NAME
+
+CRYPTO_secure_malloc_init, CRYPTO_secure_malloc_done, OPENSSL_secure_malloc, 
OPENSSL_secure_free, OPENSSL_secure_allocated - use secure heap storage
+
+=head1 SYNOPSIS
+
+ #include <openssl/crypto.h>
+
+ int CRYPTO_secure_malloc_init(size_t size, int minsize);
+
+ int CRYPTO_secure_malloc_initialized();
+
+ void CRYPTO_secure_malloc_done();
+
+ void *OPENSSL_secure_malloc(int num);
+
+ void OPENSSL_secure_free(void* ptr);
+
+ int OPENSSL_secure_allocated(const void* ptr);
+
+=head1 DESCRIPTION
+
+In order to help protect applications (particularly long-running servers)
+from pointer overruns or underruns that could return arbitrary data from
+the program's dynamic memory area, where keys and other sensitive
+information might be stored, OpenSSL supports the concept of a "secure heap."
+The level and type of security guarantees depend on the operating system.
+It is a good idea to review the code and see if it addresses your
+threat model and concerns.
+
+If a secure heap is used, then all B<BIGNUM> values are stored in that heap.
+This is more than strictly necessary -- the public part of an RSA key, for
+example, need not be kept private -- but it is a secure approach and least
+invasive to the OpenSSL source code.
+
+B<CRYPTO_secure_malloc_init> creates the secure heap, with the specified
+C<size> in bytes. The C<minsize> parameter is the minimum size to
+allocate from the heap. Both C<size> and C<minsize> must be a power
+of two.  It is an error to call this after any B<OPENSSL_secure_malloc>
+calls have been made.
+
+B<CRYPTO_secure_malloc_initialized> indicates whether or not the secure
+heap as been initialized and is available.
+
+B<CRYPTO_secure_malloc_done> releases the heap and makes the memory unavailable
+to the process. It can take noticeably long to complete.
+
+B<OPENSSL_secure_malloc> allocates C<num> bytes from the heap.
+If B<CRYPTO_secure_malloc_init> is not called, this is equivalent to
+calling B<OPENSSL_malloc>.
+
+B<OPENSSL_secure_free> releases the memory at C<ptr> back to the heap.
+It must be called with a value previously obtained from
+B<OPENSSL_secure_malloc>.
+If B<CRYPTO_secure_malloc_init> is not called, this is equivalent to
+calling B<OPENSSL_free>.
+
+B<OPENSSL_secure_allocated> tells whether or not a pointer is within
+the secure heap.
+
+=head1 RETURN VALUES
+
+B<CRYPTO_secure_malloc_init> returns 0 on failure, 1 if successful,
+and 2 if successful but the heap could not be protected by memory
+mapping.
+
+B<CRYPTO_secure_malloc_initialized> returns 1 if the secure heap is
+available (that is, if B<CRYPTO_secure_malloc_init> has been called,
+but B<CRYPTO_secure_malloc_done> has not) or 0 if not.
+
+B<OPENSSL_secure_malloc> returns a pointer into the secure heap of
+the requested size, or C<NULL> if memory could not be allocated.
+
+B<CRYPTO_secure_allocated> returns 1 if the pointer is in the
+the secure heap, or 0 if not.
+
+B<CRYPTO_secure_malloc_done> and B<OPENSSL_secure_free>
+return no values.
+
+=head1 SEE ALSO
+
+L<BN_new(3)|BN_new(3)>,
+L<bn_internal(3)|bn_internal(3)>
+
+=head1 HISTORY
+
+These functions were contributed to the OpenSSL project by
+Akamai Technologies in April, 2014.
+
+=cut

Reply via email to