Salz, Rich | 20 Apr 16:42 2014

Secure storage of BIGNUM's

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: rsalz <at> 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
 <at>  <at>  -140,7 +140,7  <at>  <at> 
 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();

 <at>  <at>  -163,11 +163,13  <at>  <at> 
 			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;
 			}
 <at>  <at>  -187,6 +189,7  <at>  <at> 
 			}
 		}
 	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
 <at>  <at>  -35,8 +35,10  <at>  <at> 
 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
 <at>  <at>  -272,6 +272,7  <at>  <at> 
 #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
 <at>  <at>  -245,7 +245,13  <at>  <at> 
 		{
 		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));
 <at>  <at>  -258,7 +264,13  <at>  <at> 
 	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
 <at>  <at>  -314,7 +326,16  <at>  <at> 
 		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);
 <at>  <at>  -401,7 +422,11  <at>  <at> 
 			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
 <at>  <at>  -431,7 +456,11  <at>  <at> 
 		{
 		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
 <at>  <at>  -152,6 +152,7  <at>  <at> 
 #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
 <at>  <at>  -463,7 +464,7  <at>  <at> 
 /* 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 *));
 <at>  <at>  -497,6 +498,29  <at>  <at> 
 			   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
 <at>  <at>  -107,6 +107,14  <at>  <at> 
 		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
 <at>  <at>  -89,6 +89,15  <at>  <at> 

 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); }
 <at>  <at>  -133,6 +142,12  <at>  <at> 
 	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;
 <at>  <at>  -150,10 +165,49  <at>  <at> 
 	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 *))
 	{
 <at>  <at>  -219,6 +273,24  <at>  <at> 
 	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
 <at>  <at>  -0,0 +1,508  <at>  <at> 
+/*
+ * 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
 <at>  <at>  -0,0 +1,92  <at>  <at> 
+=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
antonio | 19 Apr 17:10 2014
Picon

CAdES and id-aa-signingCertificateV2

Hi,

issue has been already proposed here 
http://marc.info/?l=openssl-dev&m=138000831409222&w=2, now I am 
preparing a different patch. In the meantime you have no objection to 
apply simple attached patch?

Thanks,

--
Antonio Iacono
http://opensignature.sourceforge.net/english.php

Attachment (sha256.patch): text/x-patch, 2673 bytes
Hanno Böck | 19 Apr 10:49 2014
Picon

openssl 1.0.2 beta1 and heartbleed

Hi,

I just noted that the latest openssl 1.0.2 beta1 version was released
before the heartbleed bug became public and is thus vulnerable.

I am aware that beta versions aren't intended for real-world use but in
this situation I think it'd be appropriate to do something about it.
Can the openssl devs create a new beta2 version that includes the
heartbleed fix?

cu,
--

-- 
Hanno Böck
http://hboeck.de/

mail/jabber: hanno <at> hboeck.de
GPG: BBB51E42
Satish Kamavaram via RT | 18 Apr 09:00 2014
Picon

RE: [openssl.org #3316] Wrong trust chain with new version of openssl

We are not sure if it is a Apple iOS bug. Below is our observation.

- If we sign the profile using the 0.9.8 version, and download the profile from an https location, the iOS
profile installer shows the profile as "Verified"
- If we sign the same profile using the 1.0.1 version and download the profile from an https location, the iOS
profile installer shows the profile as "Not verified"

The only difference between these two versions of openSSL visibly is, the order in which the certificate is
listed in the profile. Is there a difference in these two versions that causes the difference in this
certificate listing order? Is there a way we can make the order same to make it work while still using the
latest version 1.0.1 of openSSL?

Thanks
SatishKumaar

-----Original Message-----
From: Stephen Henson via RT [mailto:rt <at> openssl.org] 
Sent: Wednesday, April 16, 2014 11:44 PM
To: Satish Kamavaram
Cc: openssl-dev <at> openssl.org
Subject: [openssl.org #3316] Wrong trust chain with new version of openssl 

On Wed Apr 16 19:37:20 2014, Satish.K <at> mportal.com wrote:
> Hi ,
>
> When the iOS WiFi Profile is signed using new openSSL 1.0.1 version, 
> it specifies the certificate chain in reverse order causing the device 
> not to recognize the certificate chain and show "Not Verified". 
> However, when we sign using version 0.9.8k, the chain is included in 
> the correct order and the device is showing the profile as a 
> "Verified" one , at the time of showing profile installation prompt. 
> Is there a possibility that we will get a fix in next version of 
> openssl ?
>

I'm not sure what you mean by "correct order". The order of certificates in a
PKCS#7 structure should not be considered significant and there is additional information (issuer name
and serial number) which should enable a verifier to locate the appropriate signing certificate.

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev <at> openssl.org
Automated List Manager                           majordomo <at> openssl.org

satish lvr via RT | 18 Apr 07:36 2014
Picon

[openssl.org #3319] [Bug report & Patch] Fix TLS export keying material generation for TLS 1.2 version

Hello,

There is a bug in tls export keying material for TLS 1.2 version.
The digest mask uses for prf function in tls1_export_keying_material,
directly passes algorithm2 from structure. Due to this, still the digest
mask will come as md5 and sha1 combination which voilates rfc 5246 as
digest mask should be based on cipher selected. This may lead to
interoperability issues.

The fix is as below:

In tls1_export_keying_material function,

- rv=tls_PRF(s->s3->tmp.new_cipher->algorithm2, .....

To be changed to

+ rv=TLS_PRF(ssl_get_algorithm2(s), ...

Regards
Satish.

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev <at> openssl.org
Automated List Manager                           majordomo <at> openssl.org

sundarajan Srinivasan | 18 Apr 04:20 2014
Picon

Regarding openssl RSA_verify() api on openssl_1.0.0a

Hi,

I am using openssl_1.0.0a. 

My question is about the RSA_verify() api. 

First of all, can i use the RSA_verify() api to verify a signature which was generated using openssl commandline (openssl dgst -sign -sha256 ) ?. Should RSA_sign() always preceed RSA_verify() or the apis can be interchangeably used with commandline openssl as well?, like can i sign an image with commandline openssl tool and verify it in C code with RSA_verify() using sha256 or sha1?. 

Secondly im using the api like below. But it doesnt work for me( I get a return value of 0, because ASN1_get_object() in asn1_check_tlen() fails and returns i=128 for the case: ASN1_ITYPE_SEQUENCE). 

All the parameters to the api are valid. Is there any preliminary setup that should be done before calling RSA_verify() ?.

ret = RSA_verify(NID_sha256, digest_ptr, digest_size, signature_ptr, SIGNATURE_SIZE, rsa_key);

Need your help to resolve it. Please let me know if you need more info.

Thanks,
Sundarajan.
Fedor Indutny | 18 Apr 01:44 2014

Cert chain inconsistency between client and server

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello devs!

It has just caught my attention that `SSL_get_peer_cert_chain` does
not contain `SSL_get_peer_certificate`'s value for server, but it does for
client.

Would you mind accepting patch for fixing it?

Here are relevant lines of code:


Cheers,
Fedor.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJTUGdXAAoJEPsOEJWxeXmZwokQAIISCTOnQwCBeX7kBJgEdWeg
nJTDiHMM+I6bBm/C1ZkiodkIapPX+w7RAHE1OxYaqgeCKp7JWO+Bey6qQfroxJ1U
q9FtOBFzqg4O5fB6+MwbhWUXyqJE5cAgVxXeU2E9MokDNFvOpGXXtOmmRv7sBGMO
i0d5L0Fs7YS56eHYGxuy8qf7KrCswJ9muGcr/f/XNHiR6ZU0HliJRnrdoLRsiQAM
SdwtTe2L2FNeBG+q9Czh/nch5RhEv9hucnV9IPpFehzAfn3404y9wH0eBNpNnYlf
g48ccSTqTgyQQG/OlNeLbOD41qRHdUoZZ85ueU+2Gw4WrjhMxwi3fxNgU8ml5Ik+
4HINmeAshkksycWfx5tdnBXZy3iguurzpe7C9NoHl0fDJf8VCvn7sAEM50t+4ftM
4j1EqisQZufLp5R4WLlUVUHDk3bopjFvRqlZoal9SdFdUeqzqv6BDtEEKxv+6LRO
D86SsHRnpazfgkqdoizI+cZgo0b3IdRs8bsOZ4IR5RCKNt8YROEwlXqV1CueKyZJ
zpz8xkXv+tezREsiFwe2rR7iNtwqNnANwEAViH/b0GpR5IFcenKRbb/UprOVsrgF
4AlpyBPcheVRblOn4FRvUDGnQ8vNa4QW+5jxlRZuEXpaJot0xMMBFSCISUsE4bZ3
L+7POMtxSlEVXI1zChMw
=/o6W
-----END PGP SIGNATURE-----
Micha Borrmann | 17 Apr 12:05 2014
Picon

spelling error

Hello,

I've found a spelling mistake a couple of months ago. However, it would
be nice if anybody can commit this small patch to correct it. Thanks!

Regards,

Micha Borrmann
Attachment (ocsp.patch): text/x-patch, 493 bytes
Attachment (smime.p7s): application/pkcs7-signature, 4347 bytes
Peter Malone via RT | 17 Apr 09:40 2014
Picon

[openssl.org #3318] memcmp vulnerable to remote timing attack

Hi there,

I believe the following memcmp call is vulnerable to a remote timing
attack.

https://github.com/openssl/openssl/blob/master/ssl/ssl_lib.c#L1974

static int ssl_session_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
        {
        if (a->ssl_version != b->ssl_version)
                return(1);
        if (a->session_id_length != b->session_id_length)
                return(1);
        return(memcmp(a->session_id,b->session_id,a->session_id_length));
        }

For more information on memcmp timing attacks please see:
http://rdist.root.org/2010/08/05/optimized-memcmp-leaks-useful-timing-differences/
&&
https://lkml.org/lkml/2013/2/10/131

Regards,
Peter.

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev <at> openssl.org
Automated List Manager                           majordomo <at> openssl.org

Ricardo Villegas | 17 Apr 06:09 2014

Custom build now available


I have built a version of OpenSSL 1.0.1g for Windows with:

no external dependencies (statically linked libc, multi-threaded, no
MSVCR*.DLL)
buffer-overflow protection
DTLS heartbeat support (use at your own risk)
misc. optimisations for modern Windows (requires Windows 2000 or later;
recommended: Windows 7+)

Download it here: http://downloads.rickyv.tk/openssl1.0.1g_win32_nodeps.zip

Includes binaries, header files, import libraries, engines, and default
openssl.cnf file.

This is mostly an experimental build, since the default build is to use the
multi-threaded libc shared library
(i.e. MSVCR*.DLL)

Any feedback when developing apps using this custom build will be
appreciated.
Send feedback to: <rickyv <at> rickyv.tk>
(Recommendation: digitally signed or encrypted: my public key is available
at keyserver.ubuntu.com)

Built using Visual Studio.NET 2002 (this MAY pose an issue when using the
import libraries;
dynamic linking to the OpenSSL library, at run-time, is recommended.)

_RVX

PGP key: 9DB6C73E (It has changed, please update your keyrings.)
Andrey Kulikov via RT | 17 Apr 00:20 2014
Picon

Re: [openssl.org #3308] Re: Return missed NULL-check in CMS_add0_cert back

> > Well...
> > With this check 'make test' fails with:
> >
> > CMS => PKCS#7 compatibility tests
> > signed content DER format, RSA key: generation error
> > make[1]: *** [test_cms] Error 1
> >
> >

> Can't reproduce that here. Anyone else seeing this?

I saw it on Debian 7 x64, gcc  4.7.2

But anyway, as *pcerts can be NULL legitimately, this seems to be not
important.
Sorry for wasting your time. :(

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev <at> openssl.org
Automated List Manager                           majordomo <at> openssl.org


Gmane