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>
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>]
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)
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
#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,
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)
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)
int utype, char *free_cont, const ASN1_ITEM *it)
{
BIGNUM *bn;
+
if (!*pval)
bn_new(pval, it);
bn = (BIGNUM *)*pval;
}
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);
+}
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,
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,
return (&mem_method);
}
+BIO_METHOD *BIO_s_secmem(void)
+{
+ return(&secmem_method);
+}
+
BIO *BIO_new_mem_buf(void *buf, int len)
{
BIO *ret;
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)
} 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);
/************/
int err_stack;
/* Block "gets" until an "end" (compatibility behaviour) */
int too_many;
+ /* Flags. */
+ int flags;
};
/* Enable this to find BN_CTX bugs */
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;
}
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;
}
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.
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;
}
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;
}
-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;
/* 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)
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
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));
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 {
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)
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);
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;
}
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)) {
*/
#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;
BUFerr(BUF_F_BUF_MEM_NEW, ERR_R_MALLOC_FAILURE);
return (NULL);
}
+ ret->flags = 0;
ret->length = 0;
ret->max = 0;
ret->data = NULL;
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;
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;
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;
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;
}
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;
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;
}
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)
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;
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);
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)
{
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;
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;
return 0;
malloc_locked_func = 0;
malloc_locked_ex_func = m;
- free_func = f;
+ free_locked_func = f;
return 1;
}
*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 *))
{
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)
/* 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);
--- /dev/null
+/*
+ * 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 */
#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)
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.
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.
=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
BN_CTX *BN_CTX_new(void);
+ BN_CTX *BN_CTX_secure_new(void);
+
void BN_CTX_free(BN_CTX *c);
=head1 DESCRIPTION
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.
=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.
--- /dev/null
+=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
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)>
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);
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);
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.
=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
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);
* 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 */
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);
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);
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);
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,
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);
P5_CRPT2_TEST= p5_crpt2_test
IGETEST= igetest
JPAKETEST= jpaketest
+SECMEMTEST= secmemtest
SRPTEST= srptest
V3NAMETEST= v3nametest
HEARTBEATTEST= heartbeat_test
$(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)
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
@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
$(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)
--- /dev/null
+
+#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;
+}
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: