More secure storage of key material.

Add secure heap for storage of private keys (when possible).
Add BIO_s_secmem(), CBIGNUM, etc.
Add BIO_CTX_secure_new so all BIGNUM's in the context are secure.
Contributed by Akamai Technologies under the Corporate CLA.

Reviewed-by: Richard Levitte <levitte@openssl.org>
This commit is contained in:
Rich Salz 2015-04-24 16:39:40 -04:00 committed by Rich Salz
parent ce7e647bc2
commit 74924dcb38
30 changed files with 1009 additions and 76 deletions

View file

@ -126,6 +126,11 @@
NULL. Remove the non-null checks from callers. Save much code.
[Rich Salz]
*) Add secure heap for storage of private keys (when possible).
Add BIO_s_secmem(), CBIGNUM, etc.
Contributed by Akamai Technologies under our Corporate CLA.
[Rich Salz]
*) Experimental support for a new, fast, unbiased prime candidate generator,
bn_probable_prime_dh_coprime(). Not currently used by any prime generator.
[Felix Laurie von Massenbach <felix@erbridge.co.uk>]

View file

@ -36,10 +36,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 \
ebcdic.c uid.c o_time.c o_str.c o_dir.c thr_id.c lock.c fips_ers.c \
o_init.c o_fips.c
o_init.c o_fips.c sec_mem.c
LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o cpt_err.o \
ebcdic.o uid.o o_time.o o_str.o o_dir.o thr_id.o lock.o fips_ers.o \
o_init.o o_fips.o $(CPUID_OBJ)
o_init.o o_fips.o sec_mem.o $(CPUID_OBJ)
SRC= $(LIBSRC)
@ -208,6 +208,10 @@ o_time.o: ../include/openssl/crypto.h ../include/openssl/e_os2.h
o_time.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
o_time.o: ../include/openssl/ossl_typ.h ../include/openssl/safestack.h
o_time.o: ../include/openssl/stack.h ../include/openssl/symhacks.h o_time.c
sec_mem.o: ../e_os.h ../include/openssl/crypto.h ../include/openssl/e_os2.h
sec_mem.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
sec_mem.o: ../include/openssl/ossl_typ.h ../include/openssl/safestack.h
sec_mem.o: ../include/openssl/stack.h ../include/openssl/symhacks.h sec_mem.c
thr_id.o: ../e_os.h ../include/openssl/bio.h ../include/openssl/buffer.h
thr_id.o: ../include/openssl/crypto.h ../include/openssl/e_os2.h
thr_id.o: ../include/openssl/err.h ../include/openssl/lhash.h

View file

@ -72,12 +72,15 @@
#define BN_SENSITIVE 1
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
static int bn_secure_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it);
static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it);
static int bn_secure_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it);
static ASN1_PRIMITIVE_FUNCS bignum_pf = {
NULL, 0,
@ -88,12 +91,21 @@ static ASN1_PRIMITIVE_FUNCS bignum_pf = {
bn_i2c
};
static ASN1_PRIMITIVE_FUNCS cbignum_pf = {
NULL, 0,
bn_secure_new,
bn_free,
0,
bn_secure_c2i,
bn_i2c
};
ASN1_ITEM_start(BIGNUM)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM"
ASN1_ITEM_end(BIGNUM)
ASN1_ITEM_start(CBIGNUM)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM"
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &cbignum_pf, BN_SENSITIVE, "CBIGNUM"
ASN1_ITEM_end(CBIGNUM)
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
@ -105,6 +117,15 @@ static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
return 0;
}
static int bn_secure_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
*pval = (ASN1_VALUE *)BN_secure_new();
if (*pval)
return 1;
else
return 0;
}
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
if (!*pval)
@ -141,6 +162,7 @@ static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it)
{
BIGNUM *bn;
if (!*pval)
bn_new(pval, it);
bn = (BIGNUM *)*pval;
@ -150,3 +172,11 @@ static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
}
return 1;
}
static int bn_secure_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it)
{
if (!*pval)
bn_secure_new(pval, it);
return bn_c2i(pval, cont, len, utype, free_cont, it);
}

View file

@ -67,6 +67,7 @@ static int mem_puts(BIO *h, const char *str);
static int mem_gets(BIO *h, char *str, int size);
static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int mem_new(BIO *h);
static int secmem_new(BIO *h);
static int mem_free(BIO *data);
static BIO_METHOD mem_method = {
BIO_TYPE_MEM,
@ -80,6 +81,18 @@ static BIO_METHOD mem_method = {
mem_free,
NULL,
};
static BIO_METHOD secmem_method = {
BIO_TYPE_MEM,
"secure memory buffer",
mem_write,
mem_read,
mem_puts,
mem_gets,
mem_ctrl,
secmem_new,
mem_free,
NULL,
};
/*
* bio->num is used to hold the value to return on 'empty', if it is 0,
@ -91,6 +104,11 @@ BIO_METHOD *BIO_s_mem(void)
return (&mem_method);
}
BIO_METHOD *BIO_s_secmem(void)
{
return(&secmem_method);
}
BIO *BIO_new_mem_buf(void *buf, int len)
{
BIO *ret;
@ -114,17 +132,27 @@ BIO *BIO_new_mem_buf(void *buf, int len)
return ret;
}
static int mem_new(BIO *bi)
static int mem_init(BIO *bi, unsigned long flags)
{
BUF_MEM *b;
if ((b = BUF_MEM_new()) == NULL)
return (0);
if ((b = BUF_MEM_new_ex(flags)) == NULL)
return(0);
bi->shutdown = 1;
bi->init = 1;
bi->num = -1;
bi->ptr = (char *)b;
return (1);
return(1);
}
static int mem_new(BIO *bi)
{
return (mem_init(bi, 0L));
}
static int secmem_new(BIO *bi)
{
return (mem_init(bi, BUF_MEM_FLAG_SECURE));
}
static int mem_free(BIO *a)

View file

@ -103,7 +103,7 @@ typedef struct bignum_pool {
} BN_POOL;
static void BN_POOL_init(BN_POOL *);
static void BN_POOL_finish(BN_POOL *);
static BIGNUM *BN_POOL_get(BN_POOL *);
static BIGNUM *BN_POOL_get(BN_POOL *, int);
static void BN_POOL_release(BN_POOL *, unsigned int);
/************/
@ -138,6 +138,8 @@ struct bignum_ctx {
int err_stack;
/* Block "gets" until an "end" (compatibility behaviour) */
int too_many;
/* Flags. */
int flags;
};
/* Enable this to find BN_CTX bugs */
@ -186,8 +188,9 @@ static void ctxdbg(BN_CTX *ctx)
BN_CTX *BN_CTX_new(void)
{
BN_CTX *ret = OPENSSL_malloc(sizeof(*ret));
if (!ret) {
BN_CTX *ret;
if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
BNerr(BN_F_BN_CTX_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
@ -197,6 +200,16 @@ BN_CTX *BN_CTX_new(void)
ret->used = 0;
ret->err_stack = 0;
ret->too_many = 0;
ret->flags = 0;
return ret;
}
BN_CTX *BN_CTX_secure_new(void)
{
BN_CTX *ret = BN_CTX_new();
if (ret)
ret->flags = BN_FLG_SECURE;
return ret;
}
@ -258,10 +271,11 @@ void BN_CTX_end(BN_CTX *ctx)
BIGNUM *BN_CTX_get(BN_CTX *ctx)
{
BIGNUM *ret;
CTXDBG_ENTRY("BN_CTX_get", ctx);
if (ctx->err_stack || ctx->too_many)
return NULL;
if ((ret = BN_POOL_get(&ctx->pool)) == NULL) {
if ((ret = BN_POOL_get(&ctx->pool, ctx->flags)) == NULL) {
/*
* Setting too_many prevents repeated "get" attempts from cluttering
* the error stack.
@ -289,26 +303,23 @@ static void BN_STACK_init(BN_STACK *st)
static void BN_STACK_finish(BN_STACK *st)
{
if (st->size)
OPENSSL_free(st->indexes);
OPENSSL_free(st->indexes);
st->indexes = NULL;
}
static int BN_STACK_push(BN_STACK *st, unsigned int idx)
{
if (st->depth == st->size)
if (st->depth == st->size) {
/* Need to expand */
{
unsigned int newsize = (st->size ?
(st->size * 3 / 2) : BN_CTX_START_FRAMES);
unsigned int *newitems = OPENSSL_malloc(newsize *
sizeof(unsigned int));
if (!newitems)
unsigned int newsize =
st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES;
unsigned int *newitems = OPENSSL_malloc(sizeof(*newitems) * newsize);
if (newitems == NULL)
return 0;
if (st->depth)
memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int));
if (st->size)
OPENSSL_free(st->indexes);
memcpy(newitems, st->indexes, sizeof(*newitems) * st->depth);
OPENSSL_free(st->indexes);
st->indexes = newitems;
st->size = newsize;
}
@ -333,14 +344,13 @@ static void BN_POOL_init(BN_POOL *p)
static void BN_POOL_finish(BN_POOL *p)
{
unsigned int loop;
BIGNUM *bn;
while (p->head) {
unsigned int loop = 0;
BIGNUM *bn = p->head->vals;
while (loop++ < BN_CTX_POOL_SIZE) {
for (loop = 0, bn = p->head->vals; loop++ < BN_CTX_POOL_SIZE; bn++)
if (bn->d)
BN_clear_free(bn);
bn++;
}
p->current = p->head->next;
OPENSSL_free(p->head);
p->head = p->current;
@ -348,22 +358,25 @@ static void BN_POOL_finish(BN_POOL *p)
}
static BIGNUM *BN_POOL_get(BN_POOL *p)
static BIGNUM *BN_POOL_get(BN_POOL *p, int flag)
{
BIGNUM *bn;
unsigned int loop;
/* Full; allocate a new pool item and link it in. */
if (p->used == p->size) {
BIGNUM *bn;
unsigned int loop = 0;
BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(*item));
if (!item)
if (item == NULL)
return NULL;
/* Initialise the structure */
bn = item->vals;
while (loop++ < BN_CTX_POOL_SIZE)
BN_init(bn++);
for (loop = 0, bn = item->vals; loop++ < BN_CTX_POOL_SIZE; bn++) {
BN_init(bn);
if ((flag & BN_FLG_SECURE) != 0)
BN_set_flags(bn, BN_FLG_SECURE);
}
item->prev = p->tail;
item->next = NULL;
/* Link it in */
if (!p->head)
if (p->head == NULL)
p->head = p->current = p->tail = item;
else {
p->tail->next = item;
@ -375,6 +388,7 @@ static BIGNUM *BN_POOL_get(BN_POOL *p)
/* Return the first bignum from the new pool */
return item->vals;
}
if (!p->used)
p->current = p->head;
else if ((p->used % BN_CTX_POOL_SIZE) == 0)
@ -385,10 +399,11 @@ static BIGNUM *BN_POOL_get(BN_POOL *p)
static void BN_POOL_release(BN_POOL *p, unsigned int num)
{
unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
p->used -= num;
while (num--) {
bn_check_top(p->current->vals + offset);
if (!offset) {
if (offset == 0) {
offset = BN_CTX_POOL_SIZE - 1;
p->current = p->current->prev;
} else

View file

@ -232,8 +232,12 @@ void BN_clear_free(BIGNUM *a)
bn_check_top(a);
if (a->d != NULL) {
OPENSSL_cleanse(a->d, a->dmax * sizeof(a->d[0]));
if (!(BN_get_flags(a, BN_FLG_STATIC_DATA)))
OPENSSL_free(a->d);
if (!(BN_get_flags(a, BN_FLG_STATIC_DATA))) {
if (BN_get_flags(a,BN_FLG_SECURE))
OPENSSL_secure_free(a->d);
else
OPENSSL_free(a->d);
}
}
i = BN_get_flags(a, BN_FLG_MALLOCED);
OPENSSL_cleanse(a, sizeof(BIGNUM));
@ -247,7 +251,12 @@ void BN_free(BIGNUM *a)
return;
bn_check_top(a);
if (!BN_get_flags(a, BN_FLG_STATIC_DATA))
OPENSSL_free(a->d);
if ((a->d != NULL) && !(BN_get_flags(a, BN_FLG_STATIC_DATA))) {
if (BN_get_flags(a, BN_FLG_SECURE))
OPENSSL_secure_free(a->d);
else
OPENSSL_free(a->d);
}
if (a->flags & BN_FLG_MALLOCED)
OPENSSL_free(a);
else {
@ -281,6 +290,14 @@ BIGNUM *BN_new(void)
return (ret);
}
BIGNUM *BN_secure_new(void)
{
BIGNUM *ret = BN_new();
if (ret)
ret->flags |= BN_FLG_SECURE;
return (ret);
}
/* This is used both by bn_expand2() and bn_dup_expand() */
/* The caller MUST check that words > b->dmax before calling this */
static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
@ -299,7 +316,10 @@ static BN_ULONG *bn_expand_internal(const BIGNUM *b, int words)
BNerr(BN_F_BN_EXPAND_INTERNAL, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
return (NULL);
}
a = A = OPENSSL_malloc(sizeof(*a) * words);
if (BN_get_flags(b,BN_FLG_SECURE))
a = A = OPENSSL_secure_malloc(words * sizeof(*a));
else
a = A = OPENSSL_malloc(words * sizeof(*a));
if (A == NULL) {
BNerr(BN_F_BN_EXPAND_INTERNAL, ERR_R_MALLOC_FAILURE);
return (NULL);
@ -378,7 +398,12 @@ BIGNUM *bn_expand2(BIGNUM *b, int words)
BN_ULONG *a = bn_expand_internal(b, words);
if (!a)
return NULL;
OPENSSL_free(b->d);
if (b->d) {
if (BN_get_flags(b,BN_FLG_SECURE))
OPENSSL_secure_free(b->d);
else
OPENSSL_free(b->d);
}
b->d = a;
b->dmax = words;
}
@ -395,7 +420,7 @@ BIGNUM *BN_dup(const BIGNUM *a)
return NULL;
bn_check_top(a);
t = BN_new();
t = BN_get_flags(a, BN_FLG_SECURE) ? BN_secure_new() : BN_new();
if (t == NULL)
return NULL;
if (!BN_copy(t, a)) {

View file

@ -67,6 +67,16 @@
*/
#define LIMIT_BEFORE_EXPANSION 0x5ffffffc
BUF_MEM *BUF_MEM_new_ex(unsigned long flags)
{
BUF_MEM *ret;
ret = BUF_MEM_new();
if (ret != NULL)
ret->flags = flags;
return (ret);
}
BUF_MEM *BUF_MEM_new(void)
{
BUF_MEM *ret;
@ -76,6 +86,7 @@ BUF_MEM *BUF_MEM_new(void)
BUFerr(BUF_F_BUF_MEM_NEW, ERR_R_MALLOC_FAILURE);
return (NULL);
}
ret->flags = 0;
ret->length = 0;
ret->max = 0;
ret->data = NULL;
@ -88,11 +99,30 @@ void BUF_MEM_free(BUF_MEM *a)
return;
if (a->data != NULL) {
OPENSSL_clear_free(a->data, a->max);
memset(a->data, 0, (unsigned int)a->max);
if (a->flags & BUF_MEM_FLAG_SECURE)
OPENSSL_secure_free(a->data);
else
OPENSSL_clear_free(a->data, a->max);
}
OPENSSL_free(a);
}
/* Allocate a block of secure memory; copy over old data if there
* was any, and then free it. */
static char *sec_alloc_realloc(BUF_MEM *str, size_t len)
{
char *ret;
ret = OPENSSL_secure_malloc(len);
if (str->data != NULL) {
if (ret != NULL)
memcpy(ret, str->data, str->length);
OPENSSL_secure_free(str->data);
}
return (ret);
}
size_t BUF_MEM_grow(BUF_MEM *str, size_t len)
{
char *ret;
@ -113,7 +143,10 @@ size_t BUF_MEM_grow(BUF_MEM *str, size_t len)
return 0;
}
n = (len + 3) / 3 * 4;
ret = OPENSSL_realloc(str->data, n);
if ((str->flags & BUF_MEM_FLAG_SECURE))
ret = sec_alloc_realloc(str, n);
else
ret = OPENSSL_realloc(str->data, n);
if (ret == NULL) {
BUFerr(BUF_F_BUF_MEM_GROW, ERR_R_MALLOC_FAILURE);
len = 0;
@ -147,7 +180,10 @@ size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
return 0;
}
n = (len + 3) / 3 * 4;
ret = OPENSSL_realloc_clean(str->data, str->max, n);
if ((str->flags & BUF_MEM_FLAG_SECURE))
ret = sec_alloc_realloc(str, n);
else
ret = OPENSSL_realloc_clean(str->data, str->max, n);
if (ret == NULL) {
BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
len = 0;

View file

@ -228,7 +228,8 @@ static int dh_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
goto decerr;
/* We have parameters now set private key */
if ((dh->priv_key = ASN1_INTEGER_to_BN(privkey, NULL)) == NULL) {
if ((dh->priv_key = BN_secure_new()) == NULL
|| !ASN1_INTEGER_to_BN(privkey, dh->priv_key)) {
DHerr(DH_F_DH_PRIV_DECODE, DH_R_BN_ERROR);
goto dherr;
}

View file

@ -125,7 +125,7 @@ static int generate_key(DH *dh)
goto err;
if (dh->priv_key == NULL) {
priv_key = BN_new();
priv_key = BN_secure_new();
if (priv_key == NULL)
goto err;
generate_new_key = 1;

View file

@ -245,7 +245,8 @@ static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
if ((dsa = d2i_DSAparams(NULL, &pm, pmlen)) == NULL)
goto decerr;
/* We have parameters now set private key */
if ((dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL)) == NULL) {
if ((dsa->priv_key = BN_secure_new()) == NULL
|| !ASN1_INTEGER_to_BN(privkey, dsa->priv_key)) {
DSAerr(DSA_F_DSA_PRIV_DECODE, DSA_R_BN_ERROR);
goto dsaerr;
}

View file

@ -113,7 +113,7 @@ ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = {
ASN1_SIMPLE(DSA, q, BIGNUM),
ASN1_SIMPLE(DSA, g, BIGNUM),
ASN1_SIMPLE(DSA, pub_key, BIGNUM),
ASN1_SIMPLE(DSA, priv_key, BIGNUM)
ASN1_SIMPLE(DSA, priv_key, CBIGNUM)
} ASN1_SEQUENCE_END_cb(DSA, DSAPrivateKey)
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey)

View file

@ -82,7 +82,7 @@ static int dsa_builtin_keygen(DSA *dsa)
goto err;
if (dsa->priv_key == NULL) {
if ((priv_key = BN_new()) == NULL)
if ((priv_key = BN_secure_new()) == NULL)
goto err;
} else
priv_key = dsa->priv_key;

View file

@ -1023,6 +1023,8 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
ret->version = priv_key->version;
if (priv_key->privateKey) {
if (ret->priv_key == NULL)
ret->priv_key = BN_secure_new();
ret->priv_key = BN_bin2bn(ASN1_STRING_data(priv_key->privateKey),
ASN1_STRING_length(priv_key->privateKey),
ret->priv_key);

View file

@ -94,6 +94,15 @@ static void *(*realloc_ex_func) (void *, size_t, const char *file, int line)
static void (*free_func) (void *) = free;
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;
static void *(*malloc_locked_func) (size_t) = malloc;
static void *default_malloc_locked_ex(size_t num, const char *file, int line)
{
@ -145,6 +154,11 @@ int CRYPTO_set_mem_functions(void *(*m) (size_t), void *(*r) (void *, size_t),
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. */
malloc_secure_func = m;
malloc_secure_ex_func = default_malloc_secure_ex;
free_secure_func = f;
malloc_locked_func = m;
malloc_locked_ex_func = default_malloc_locked_ex;
free_locked_func = f;
@ -164,6 +178,44 @@ int CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const char *, int),
realloc_func = 0;
realloc_ex_func = r;
free_func = f;
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;
}
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;
@ -191,7 +243,7 @@ int CRYPTO_set_locked_mem_ex_functions(void *(*m) (size_t, const char *, int),
return 0;
malloc_locked_func = 0;
malloc_locked_ex_func = m;
free_func = f;
free_locked_func = f;
return 1;
}
@ -236,6 +288,25 @@ void CRYPTO_get_mem_ex_functions(void *(**m) (size_t, const char *, int),
*f = free_func;
}
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;
}
void CRYPTO_get_locked_mem_functions(void *(**m) (size_t),
void (**f) (void *))
{

View file

@ -85,12 +85,12 @@ ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
ASN1_SIMPLE(RSA, version, LONG),
ASN1_SIMPLE(RSA, n, BIGNUM),
ASN1_SIMPLE(RSA, e, BIGNUM),
ASN1_SIMPLE(RSA, d, BIGNUM),
ASN1_SIMPLE(RSA, p, BIGNUM),
ASN1_SIMPLE(RSA, q, BIGNUM),
ASN1_SIMPLE(RSA, dmp1, BIGNUM),
ASN1_SIMPLE(RSA, dmq1, BIGNUM),
ASN1_SIMPLE(RSA, iqmp, BIGNUM)
ASN1_SIMPLE(RSA, d, CBIGNUM),
ASN1_SIMPLE(RSA, p, CBIGNUM),
ASN1_SIMPLE(RSA, q, CBIGNUM),
ASN1_SIMPLE(RSA, dmp1, CBIGNUM),
ASN1_SIMPLE(RSA, dmq1, CBIGNUM),
ASN1_SIMPLE(RSA, iqmp, CBIGNUM)
} ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey)

View file

@ -117,19 +117,19 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
/* We need the RSA components non-NULL */
if (!rsa->n && ((rsa->n = BN_new()) == NULL))
goto err;
if (!rsa->d && ((rsa->d = BN_new()) == NULL))
if (!rsa->d && ((rsa->d = BN_secure_new()) == NULL))
goto err;
if (!rsa->e && ((rsa->e = BN_new()) == NULL))
goto err;
if (!rsa->p && ((rsa->p = BN_new()) == NULL))
if (!rsa->p && ((rsa->p = BN_secure_new()) == NULL))
goto err;
if (!rsa->q && ((rsa->q = BN_new()) == NULL))
if (!rsa->q && ((rsa->q = BN_secure_new()) == NULL))
goto err;
if (!rsa->dmp1 && ((rsa->dmp1 = BN_new()) == NULL))
if (!rsa->dmp1 && ((rsa->dmp1 = BN_secure_new()) == NULL))
goto err;
if (!rsa->dmq1 && ((rsa->dmq1 = BN_new()) == NULL))
if (!rsa->dmq1 && ((rsa->dmq1 = BN_secure_new()) == NULL))
goto err;
if (!rsa->iqmp && ((rsa->iqmp = BN_new()) == NULL))
if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL))
goto err;
BN_copy(rsa->e, e_value);

513
crypto/sec_mem.c Normal file
View file

@ -0,0 +1,513 @@
/*
* 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 <e_os.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#if defined(OPENSSL_SYS_LINUX) || defined(OPENSSL_SYS_UNIX)
# define IMPLEMENTED
# include <sys/mman.h>
# include <sys/param.h>
#endif
#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
#ifdef IMPLEMENTED
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 char *sh_malloc(size_t size);
static void sh_free(char *ptr);
static void sh_done(void);
static int sh_actual_size(char *ptr);
static int sh_allocated(const char *ptr);
#endif
int CRYPTO_secure_malloc_init(size_t size, int minsize)
{
#ifdef IMPLEMENTED
int ret = 0;
if (too_late)
return ret;
LOCK();
OPENSSL_assert(!secure_mem_initialized);
if (!secure_mem_initialized) {
ret = sh_init(size, minsize);
secure_mem_initialized = 1;
}
UNLOCK();
return ret;
#else
return 0;
#endif /* IMPLEMENTED */
}
void CRYPTO_secure_malloc_done()
{
#ifdef IMPLEMENTED
LOCK();
sh_done();
secure_mem_initialized = 0;
UNLOCK();
#endif /* IMPLEMENTED */
}
int CRYPTO_secure_malloc_initialized()
{
#ifdef IMPLEMENTED
return secure_mem_initialized;
#else
return 0;
#endif /* IMPLEMENTED */
}
void *CRYPTO_secure_malloc(int num, const char *file, int line)
{
#ifdef IMPLEMENTED
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;
#else
return CRYPTO_malloc(num, file, line);
#endif /* IMPLEMENTED */
}
void CRYPTO_secure_free(void *ptr)
{
#ifdef IMPLEMENTED
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();
#else
CRYPTO_free(ptr);
#endif /* IMPLEMENTED */
}
int CRYPTO_secure_allocated(const void *ptr)
{
#ifdef IMPLEMENTED
int ret;
if (!secure_mem_initialized)
return 0;
LOCK();
ret = sh_allocated(ptr);
UNLOCK();
return ret;
#else
return 0;
#endif /* IMPLEMENTED */
}
/* END OF PAGE ...
... START OF PAGE */
/*
* SECURE HEAP IMPLEMENTATION
*/
#ifdef IMPLEMENTED
/*
* 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) \
((char*)(p) >= sh.arena && (char*)(p) < &sh.arena[sh.arena_size])
#define WITHIN_FREELIST(p) \
((char*)(p) >= (char*)sh.freelist && (char*)(p) < (char*)&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;
char *arena;
int arena_size;
char **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(char *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(char *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(char *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(char *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(char **list, char *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((char **)temp->next->p_next == list);
temp->next->p_next = &(temp->next);
}
*list = ptr;
}
static void sh_remove_from_list(char *ptr, char *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 (char *));
OPENSSL_assert(sh.freelist != NULL);
if (sh.freelist == NULL)
goto err;
memset(sh.freelist, 0, sh.freelist_size * sizeof (char *));
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 = (char *)(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()
{
OPENSSL_free(sh.freelist);
OPENSSL_free(sh.bittable);
OPENSSL_free(sh.bitmalloc);
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 char *ptr)
{
return WITHIN_ARENA(ptr) ? 1 : 0;
}
static char *sh_find_my_buddy(char *ptr, int list)
{
int bit;
char *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 char *sh_malloc(size_t size)
{
int list, slist;
size_t i;
char *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) {
char *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(char *ptr)
{
int list;
char *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(char *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 /* IMPLEMENTED */

View file

@ -10,6 +10,7 @@ BIO_get_mem_ptr, BIO_new_mem_buf - memory BIO
#include <openssl/bio.h>
BIO_METHOD * BIO_s_mem(void);
BIO_METHOD * BIO_s_secmem(void);
BIO_set_mem_eof_return(BIO *b,int v)
long BIO_get_mem_data(BIO *b, char **pp)
@ -26,6 +27,9 @@ A memory BIO is a source/sink BIO which uses memory for its I/O. Data
written to a memory BIO is stored in a BUF_MEM structure which is extended
as appropriate to accommodate the stored data.
BIO_s_secmem() is like BIO_s_mem() except that the secure heap is used
for buffer storage.
Any data written to a memory BIO can be recalled by reading from it.
Unless the memory BIO is read only any data read from it is deleted from
the BIO.
@ -79,6 +83,9 @@ read in small chunks the operation can be very slow. The use of a read only
memory BIO avoids this problem. If the BIO must be read write then adding
a buffering BIO to the chain will speed up the process.
Calling BIO_set_mem_buf() on a BIO created with BIO_new_secmem() will
give undefined results, including perhaps a program crash.
=head1 BUGS
There should be an option to set the maximum size of a memory BIO.

View file

@ -2,7 +2,7 @@
=head1 NAME
BN_CTX_new, BN_CTX_init, BN_CTX_free - allocate and free BN_CTX structures
BN_CTX_new, BN_CTX_secure_new, BN_CTX_init, BN_CTX_free - allocate and free BN_CTX structures
=head1 SYNOPSIS
@ -10,6 +10,8 @@ BN_CTX_new, BN_CTX_init, BN_CTX_free - allocate and free BN_CTX structures
BN_CTX *BN_CTX_new(void);
BN_CTX *BN_CTX_secure_new(void);
void BN_CTX_free(BN_CTX *c);
=head1 DESCRIPTION
@ -19,8 +21,10 @@ library functions. Since dynamic memory allocation to create B<BIGNUM>s
is rather expensive when used in conjunction with repeated subroutine
calls, the B<BN_CTX> structure is used.
BN_CTX_new() allocates and initializes a B<BN_CTX>
structure.
BN_CTX_new() allocates and initializes a B<BN_CTX> structure.
BN_CTX_secure_new() allocates and initializes a B<BN_CTX> structure
but uses the secure heap (see L<CRYPTO_secure_malloc(3)>) to hold the
B<BIGNUM>s.
BN_CTX_free() frees the components of the B<BN_CTX>, and if it was
created by BN_CTX_new(), also the structure itself.
@ -31,8 +35,9 @@ If B<c> is NULL, nothing is done.
=head1 RETURN VALUES
BN_CTX_new() returns a pointer to the B<BN_CTX>. If the allocation fails,
it returns B<NULL> and sets an error code that can be obtained by
BN_CTX_new() and BN_CTX_secure_new() return a pointer to the B<BN_CTX>.
If the allocation fails,
they return B<NULL> and sets an error code that can be obtained by
L<ERR_get_error(3)|ERR_get_error(3)>.
BN_CTX_free() has no return values.

View file

@ -0,0 +1,91 @@
=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 private key B<BIGNUM> values are stored there.
This protects long-term storage of private keys, but will not necessarily
put all intermediate values and computations there.
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

View file

@ -49,6 +49,7 @@ L<BIO_push(3)|BIO_push(3)>, L<BIO_read(3)|BIO_read(3)>,
L<BIO_s_accept(3)|BIO_s_accept(3)>, L<BIO_s_bio(3)|BIO_s_bio(3)>,
L<BIO_s_connect(3)|BIO_s_connect(3)>, L<BIO_s_fd(3)|BIO_s_fd(3)>,
L<BIO_s_file(3)|BIO_s_file(3)>, L<BIO_s_mem(3)|BIO_s_mem(3)>,
L<BIO_s_secmem(3)|BIO_s_mem(3)>,
L<BIO_s_null(3)|BIO_s_null(3)>, L<BIO_s_socket(3)|BIO_s_socket(3)>,
L<BIO_set_callback(3)|BIO_set_callback(3)>,
L<BIO_should_retry(3)|BIO_should_retry(3)>

View file

@ -14,6 +14,7 @@ bn - multiprecision integer arithmetics
void BN_clear_free(BIGNUM *a);
BN_CTX *BN_CTX_new(void);
BN_CTX *BN_CTX_secure_new(void);
void BN_CTX_free(BN_CTX *c);
BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);

View file

@ -11,6 +11,10 @@ character arrays structure
BUF_MEM *BUF_MEM_new(void);
#define BUF_MEM_FLAG_SECURE
BUF_MEM * BUF_MEM_new_ex(unsigned long flags);
void BUF_MEM_free(BUF_MEM *a);
int BUF_MEM_grow(BUF_MEM *str, int len);
@ -37,6 +41,10 @@ and one "miscellaneous" function.
BUF_MEM_new() allocates a new buffer of zero size.
BUF_MEM_new_ex() allocates a buffer with the specified flags.
The flag B<BUF_MEM_FLAG_SECURE> specifies that the B<data> pointer
should be allocated on the secure heap; see L<CRYPTO_secure_malloc(3)>.
BUF_MEM_free() frees up an already existing buffer. The data is zeroed
before freeing up in case the buffer contains sensitive data.
@ -63,11 +71,15 @@ BUF_MEM_grow() returns zero on error or the new size (i.e. B<len>).
=head1 SEE ALSO
L<bio(3)|bio(3)>
L<bio(3)|bio(3)>,
L<CRYPTO_secure_malloc(3)>.
=head1 HISTORY
BUF_MEM_new(), BUF_MEM_free() and BUF_MEM_grow() are available in all
versions of SSLeay and OpenSSL. BUF_strdup() was added in SSLeay 0.8.
BUF_MEM_new_ex() was contributed to OpenSSL by Akamai Technologies
in May, 2014.
=cut

View file

@ -670,6 +670,7 @@ long BIO_debug_callback(BIO *bio, int cmd, const char *argp, int argi,
long argl, long ret);
BIO_METHOD *BIO_s_mem(void);
BIO_METHOD *BIO_s_secmem(void);
BIO *BIO_new_mem_buf(void *buf, int len);
BIO_METHOD *BIO_s_socket(void);
BIO_METHOD *BIO_s_connect(void);

View file

@ -268,6 +268,7 @@ extern "C" {
* BN_mod_inverse() will call BN_mod_inverse_no_branch.
*/
# define BN_FLG_CONSTTIME 0x04
# define BN_FLG_SECURE 0x08
# ifdef OPENSSL_USE_DEPRECATED
/* deprecated name for the flag */
@ -349,6 +350,7 @@ void BN_zero_ex(BIGNUM *a);
const BIGNUM *BN_value_one(void);
char *BN_options(void);
BN_CTX *BN_CTX_new(void);
BN_CTX *BN_CTX_secure_new(void);
void BN_CTX_free(BN_CTX *c);
void BN_CTX_start(BN_CTX *ctx);
BIGNUM *BN_CTX_get(BN_CTX *ctx);
@ -361,6 +363,7 @@ int BN_num_bits(const BIGNUM *a);
int BN_num_bits_word(BN_ULONG l);
int BN_security_bits(int L, int N);
BIGNUM *BN_new(void);
BIGNUM *BN_secure_new(void);
void BN_clear_free(BIGNUM *a);
BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);
void BN_swap(BIGNUM *a, BIGNUM *b);

View file

@ -78,9 +78,13 @@ struct buf_mem_st {
size_t length; /* current number of bytes */
char *data;
size_t max; /* size of buffer */
unsigned long flags;
};
# define BUF_MEM_FLAG_SECURE 0x01
BUF_MEM *BUF_MEM_new(void);
BUF_MEM *BUF_MEM_new_ex(unsigned long flags);
void BUF_MEM_free(BUF_MEM *a);
size_t BUF_MEM_grow(BUF_MEM *str, size_t len);
size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len);

View file

@ -491,12 +491,12 @@ void (*CRYPTO_get_dynlock_destroy_callback(void)) (struct CRYPTO_dynlock_value
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 *));
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 *));
int CRYPTO_set_locked_mem_ex_functions(void *(*m) (size_t, const char *, int),
void (*free_func) (void *));
void (*f) (void *));
int CRYPTO_set_mem_debug_functions(void (*m)
(void *, int, const char *, int, int),
void (*r) (void *, void *, int,
@ -532,6 +532,25 @@ void *CRYPTO_realloc_clean(void *addr, int old_num, int num, const char *file,
int line);
void *CRYPTO_remalloc(void *addr, int num, const char *file, int line);
# 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);
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(void);
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 *));
void OPENSSL_cleanse(void *ptr, size_t len);
void CRYPTO_set_mem_debug_options(long bits);

View file

@ -63,6 +63,7 @@ EVPEXTRATEST=evp_extra_test
P5_CRPT2_TEST= p5_crpt2_test
IGETEST= igetest
JPAKETEST= jpaketest
SECMEMTEST= secmemtest
SRPTEST= srptest
V3NAMETEST= v3nametest
HEARTBEATTEST= heartbeat_test
@ -80,7 +81,8 @@ EXE= $(BNTEST)$(EXE_EXT) $(ECTEST)$(EXE_EXT) $(ECDSATEST)$(EXE_EXT) $(ECDHTEST)
$(BFTEST)$(EXE_EXT) $(CASTTEST)$(EXE_EXT) $(SSLTEST)$(EXE_EXT) \
$(EXPTEST)$(EXE_EXT) $(DSATEST)$(EXE_EXT) $(RSATEST)$(EXE_EXT) \
$(EVPTEST)$(EXE_EXT) $(EVPEXTRATEST)$(EXE_EXT) $(IGETEST)$(EXE_EXT) \
$(JPAKETEST)$(EXE_EXT) $(SRPTEST)$(EXE_EXT) $(V3NAMETEST)$(EXE_EXT) \
$(JPAKETEST)$(EXE_EXT) $(SECMEMTEST)$(EXE_EXT) \
$(SRPTEST)$(EXE_EXT) $(V3NAMETEST)$(EXE_EXT) \
$(HEARTBEATTEST)$(EXE_EXT) $(P5_CRPT2_TEST)$(EXE_EXT) \
$(CONSTTIMETEST)$(EXE_EXT)
@ -145,7 +147,8 @@ alltests: \
test_enc test_x509 test_rsa test_crl test_sid \
test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
test_ss test_ca test_engine test_evp test_evp_extra test_ssl test_tsa \
test_ige test_jpake test_srp test_cms test_v3name test_ocsp \
test_ige test_jpake test_secmem \
test_srp test_cms test_v3name test_ocsp \
test_gost2814789 test_heartbeat test_p5_crpt2 \
test_constant_time
@ -372,6 +375,10 @@ test_cms: ../apps/openssl$(EXE_EXT) cms-test.pl smcont.txt
@echo $(START) $@
$(PERL) cms-test.pl
test_secmem: $(SECMEMTEST)$(EXE_EXT)
@echo $(START) $@
../util/shlib_wrap.sh ./secmemtest
test_srp: $(SRPTEST)$(EXE_EXT)
@echo $(START) $@
../util/shlib_wrap.sh ./srptest
@ -564,6 +571,9 @@ $(IGETEST)$(EXE_EXT): $(IGETEST).o $(DLIBCRYPTO)
$(JPAKETEST)$(EXE_EXT): $(JPAKETEST).o $(DLIBCRYPTO)
@target=$(JPAKETEST); $(BUILD_CMD)
$(SECMEMTEST)$(EXE_EXT): $(SECMEMTEST).o $(DLIBCRYPTO)
@target=$(SECMEMTEST); $(BUILD_CMD)
$(SRPTEST)$(EXE_EXT): $(SRPTEST).o $(DLIBCRYPTO)
@target=$(SRPTEST); $(BUILD_CMD)

34
test/secmemtest.c Normal file
View file

@ -0,0 +1,34 @@
#include <openssl/crypto.h>
int main(int argc, char **argv)
{
#if defined(OPENSSL_SYS_LINUX) || defined(OPENSSL_SYS_UNIX)
char *p = NULL, *q = NULL;
if (!CRYPTO_secure_malloc_init(4096, 32)) {
perror("failed");
return 1;
}
p = OPENSSL_secure_malloc(20);
if (!CRYPTO_secure_allocated(p)) {
perror("failed 1");
return 1;
}
q = OPENSSL_malloc(20);
if (CRYPTO_secure_allocated(q)) {
perror("failed 1");
return 1;
}
CRYPTO_secure_free(p);
CRYPTO_free(q);
CRYPTO_secure_malloc_done();
#else
/* Should fail. */
if (CRYPTO_secure_malloc_init(4096, 32)) {
perror("failed");
return 1;
}
#endif
return 0;
}

View file

@ -4573,3 +4573,17 @@ PKCS5_pbe2_set_scrypt 4931 EXIST::FUNCTION:
PKCS8_set0_pbe 4932 EXIST::FUNCTION:
DH_bits 4933 EXIST::FUNCTION:DH
RSA_bits 4934 EXIST::FUNCTION:RSA
CRYPTO_set_secure_mem_ex_functions 4935 EXIST::FUNCTION:
CRYPTO_secure_allocated 4936 EXIST::FUNCTION:
BN_CTX_secure_new 4937 EXIST::FUNCTION:
CRYPTO_secure_malloc 4938 EXIST::FUNCTION:
CRYPTO_secure_malloc_done 4939 EXIST::FUNCTION:
BUF_MEM_new_ex 4940 EXIST::FUNCTION:
CRYPTO_secure_malloc_initialized 4941 EXIST::FUNCTION:
CRYPTO_secure_malloc_init 4942 EXIST::FUNCTION:
CRYPTO_get_secure_mem_functions 4943 EXIST::FUNCTION:
BN_secure_new 4944 EXIST::FUNCTION:
CRYPTO_secure_free 4945 EXIST::FUNCTION:
BIO_s_secmem 4946 EXIST::FUNCTION:
CRYPTO_get_secure_mem_ex_functions 4947 EXIST::FUNCTION:
CRYPTO_set_secure_mem_functions 4948 EXIST::FUNCTION: