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; } OPENSSL_secure_free(p); OPENSSL_free(q); CRYPTO_secure_malloc_done(); #else /* Should fail. */ if (CRYPTO_secure_malloc_init(4096, 32)) { perror("failed"); return 1; } #endif return 0; }
size_t drbg_entropy_from_parent(RAND_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { int st; unsigned char *randomness; if (min_len > (size_t)drbg->size) { /* Should not happen. See comment near RANDOMNESS_NEEDED. */ min_len = drbg->size; } randomness = drbg->secure ? OPENSSL_secure_malloc(drbg->size) : OPENSSL_malloc(drbg->size); /* Get random from parent, include our state as additional input. */ st = RAND_DRBG_generate(drbg->parent, randomness, min_len, 0, (unsigned char *)drbg, sizeof(*drbg)); if (st == 0) { drbg_release_entropy(drbg, randomness, min_len); return 0; } *pout = randomness; return min_len; }
/* Copy Curve25519 private key buffer, allocating is necessary */ static int x25519_init_private(EC_KEY *dst, const void *src) { if (dst->custom_data == NULL) { dst->custom_data = OPENSSL_secure_malloc(EC_X25519_KEYLEN); if (dst->custom_data == NULL) return 0; } if (src != NULL) memcpy(dst->custom_data, src, EC_X25519_KEYLEN); return 1; }
/* 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); }
/* * DRBG has two sets of callbacks; we only discuss the "entropy" one * here. When the DRBG needs additional randomness bits (called entropy * in the NIST document), it calls the get_entropy callback which fills in * a pointer and returns the number of bytes. When the DRBG is finished with * the buffer, it calls the cleanup_entropy callback, with the value of * the buffer that the get_entropy callback filled in. * * Get entropy from the system, via RAND_poll if needed. The |entropy| * is the bits of randomness required, and is expected to fit into a buffer * of |min_len|..|max__len| size. We assume we're getting high-quality * randomness from the system, and that |min_len| bytes will do. */ size_t drbg_entropy_from_system(RAND_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { int i; if (min_len > (size_t)drbg->size) { /* Should not happen. See comment near RANDOMNESS_NEEDED. */ min_len = drbg->size; } if (drbg->filled) { /* Re-use what we have. */ *pout = drbg->randomness; return drbg->size; } drbg->randomness = drbg->secure ? OPENSSL_secure_malloc(drbg->size) : OPENSSL_malloc(drbg->size); /* If we don't have enough, try to get more. */ CRYPTO_THREAD_write_lock(rand_bytes.lock); for (i = RAND_POLL_RETRIES; rand_bytes.curr < min_len && --i >= 0; ) { CRYPTO_THREAD_unlock(rand_bytes.lock); RAND_poll(); CRYPTO_THREAD_write_lock(rand_bytes.lock); } /* Get desired amount, but no more than we have. */ if (min_len > rand_bytes.curr) min_len = rand_bytes.curr; if (min_len != 0) { memcpy(drbg->randomness, rand_bytes.buff, min_len); drbg->filled = 1; /* Update amount left and shift it down. */ rand_bytes.curr -= min_len; if (rand_bytes.curr != 0) memmove(rand_bytes.buff, &rand_bytes.buff[min_len], rand_bytes.curr); } CRYPTO_THREAD_unlock(rand_bytes.lock); *pout = drbg->randomness; return min_len; }
/* * Set up a global DRBG. */ static int setup_drbg(RAND_DRBG *drbg) { int ret = 1; drbg->lock = CRYPTO_THREAD_lock_new(); ret &= drbg->lock != NULL; drbg->size = RANDOMNESS_NEEDED; drbg->secure = CRYPTO_secure_malloc_initialized(); drbg->randomness = drbg->secure ? OPENSSL_secure_malloc(drbg->size) : OPENSSL_malloc(drbg->size); ret &= drbg->randomness != NULL; /* If you change these parameters, see RANDOMNESS_NEEDED */ ret &= RAND_DRBG_set(drbg, NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF) == 1; ret &= RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_system, drbg_release_entropy, NULL, NULL) == 1; return ret; }
static int test_sec_mem_clear(void) { #if defined(OPENSSL_SYS_LINUX) || defined(OPENSSL_SYS_UNIX) const int size = 64; unsigned char *p = NULL; int i, res = 0; if (!TEST_true(CRYPTO_secure_malloc_init(4096, 32)) || !TEST_ptr(p = OPENSSL_secure_malloc(size))) goto err; for (i = 0; i < size; i++) if (!TEST_uchar_eq(p[i], 0)) goto err; for (i = 0; i < size; i++) p[i] = (unsigned char)(i + ' ' + 1); OPENSSL_secure_free(p); /* * A deliberate use after free here to verify that the memory has been * cleared properly. Since secure free doesn't return the memory to * libc's memory pool, it technically isn't freed. However, the header * bytes have to be skipped and these consist of two pointers in the * current implementation. */ for (i = sizeof(void *) * 2; i < size; i++) if (!TEST_uchar_eq(p[i], 0)) return 0; res = 1; p = NULL; err: OPENSSL_secure_free(p); CRYPTO_secure_malloc_done(); return res; #else return 1; #endif }
static void *pem_malloc(int num, unsigned int flags) { return (flags & PEM_FLAG_SECURE) ? OPENSSL_secure_malloc(num) : OPENSSL_malloc(num); }
static int test_sec_mem(void) { #if defined(OPENSSL_SYS_LINUX) || defined(OPENSSL_SYS_UNIX) int testresult = 0; char *p = NULL, *q = NULL, *r = NULL, *s = NULL; s = OPENSSL_secure_malloc(20); /* s = non-secure 20 */ if (!TEST_ptr(s) || !TEST_false(CRYPTO_secure_allocated(s))) goto end; r = OPENSSL_secure_malloc(20); /* r = non-secure 20, s = non-secure 20 */ if (!TEST_ptr(r) || !TEST_true(CRYPTO_secure_malloc_init(4096, 32)) || !TEST_false(CRYPTO_secure_allocated(r))) goto end; p = OPENSSL_secure_malloc(20); if (!TEST_ptr(p) /* r = non-secure 20, p = secure 20, s = non-secure 20 */ || !TEST_true(CRYPTO_secure_allocated(p)) /* 20 secure -> 32-byte minimum allocation unit */ || !TEST_size_t_eq(CRYPTO_secure_used(), 32)) goto end; q = OPENSSL_malloc(20); if (!TEST_ptr(q)) goto end; /* r = non-secure 20, p = secure 20, q = non-secure 20, s = non-secure 20 */ if (!TEST_false(CRYPTO_secure_allocated(q))) goto end; OPENSSL_secure_clear_free(s, 20); s = OPENSSL_secure_malloc(20); if (!TEST_ptr(s) /* r = non-secure 20, p = secure 20, q = non-secure 20, s = secure 20 */ || !TEST_true(CRYPTO_secure_allocated(s)) /* 2 * 20 secure -> 64 bytes allocated */ || !TEST_size_t_eq(CRYPTO_secure_used(), 64)) goto end; OPENSSL_secure_clear_free(p, 20); p = NULL; /* 20 secure -> 32 bytes allocated */ if (!TEST_size_t_eq(CRYPTO_secure_used(), 32)) goto end; OPENSSL_free(q); q = NULL; /* should not complete, as secure memory is still allocated */ if (!TEST_false(CRYPTO_secure_malloc_done()) || !TEST_true(CRYPTO_secure_malloc_initialized())) goto end; OPENSSL_secure_free(s); s = NULL; /* secure memory should now be 0, so done should complete */ if (!TEST_size_t_eq(CRYPTO_secure_used(), 0) || !TEST_true(CRYPTO_secure_malloc_done()) || !TEST_false(CRYPTO_secure_malloc_initialized())) goto end; TEST_info("Possible infinite loop: allocate more than available"); if (!TEST_true(CRYPTO_secure_malloc_init(32768, 16))) goto end; TEST_ptr_null(OPENSSL_secure_malloc((size_t)-1)); TEST_true(CRYPTO_secure_malloc_done()); /* * If init fails, then initialized should be false, if not, this * could cause an infinite loop secure_malloc, but we don't test it */ if (TEST_false(CRYPTO_secure_malloc_init(16, 16)) && !TEST_false(CRYPTO_secure_malloc_initialized())) { TEST_true(CRYPTO_secure_malloc_done()); goto end; } /*- * There was also a possible infinite loop when the number of * elements was 1<<31, as |int i| was set to that, which is a * negative number. However, it requires minimum input values: * * CRYPTO_secure_malloc_init((size_t)1<<34, (size_t)1<<4); * * Which really only works on 64-bit systems, since it took 16 GB * secure memory arena to trigger the problem. It naturally takes * corresponding amount of available virtual and physical memory * for test to be feasible/representative. Since we can't assume * that every system is equipped with that much memory, the test * remains disabled. If the reader of this comment really wants * to make sure that infinite loop is fixed, they can enable the * code below. */ # if 0 /*- * On Linux and BSD this test has a chance to complete in minimal * time and with minimum side effects, because mlock is likely to * fail because of RLIMIT_MEMLOCK, which is customarily [much] * smaller than 16GB. In other words Linux and BSD users can be * limited by virtual space alone... */ if (sizeof(size_t) > 4) { TEST_info("Possible infinite loop: 1<<31 limit"); if (TEST_true(CRYPTO_secure_malloc_init((size_t)1<<34, (size_t)1<<4) != 0)) TEST_true(CRYPTO_secure_malloc_done()); } # endif /* this can complete - it was not really secure */ testresult = 1; end: OPENSSL_secure_free(p); OPENSSL_free(q); OPENSSL_secure_free(r); OPENSSL_secure_free(s); return testresult; #else /* Should fail. */ return TEST_false(CRYPTO_secure_malloc_init(4096, 32)); #endif }
/* Setup EVP_PKEY using public, private or generation */ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg, const unsigned char *p, int plen, ecx_key_op_t op) { ECX_KEY *key = NULL; unsigned char *privkey, *pubkey; if (op != KEY_OP_KEYGEN) { if (palg != NULL) { int ptype; /* Algorithm parameters must be absent */ X509_ALGOR_get0(NULL, &ptype, NULL, palg); if (ptype != V_ASN1_UNDEF) { ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); return 0; } } if (p == NULL || plen != KEYLENID(id)) { ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); return 0; } } key = OPENSSL_zalloc(sizeof(*key)); if (key == NULL) { ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); return 0; } pubkey = key->pubkey; if (op == KEY_OP_PUBLIC) { memcpy(pubkey, p, plen); } else { privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id)); if (privkey == NULL) { ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); goto err; } if (op == KEY_OP_KEYGEN) { if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) { OPENSSL_secure_free(privkey); key->privkey = NULL; goto err; } if (id == EVP_PKEY_X25519) { privkey[0] &= 248; privkey[X25519_KEYLEN - 1] &= 127; privkey[X25519_KEYLEN - 1] |= 64; } else if (id == EVP_PKEY_X448) { privkey[0] &= 252; privkey[X448_KEYLEN - 1] |= 128; } } else { memcpy(privkey, p, KEYLENID(id)); } switch (id) { case EVP_PKEY_X25519: X25519_public_from_private(pubkey, privkey); break; case EVP_PKEY_ED25519: ED25519_public_from_private(pubkey, privkey); break; case EVP_PKEY_X448: X448_public_from_private(pubkey, privkey); break; case EVP_PKEY_ED448: ED448_public_from_private(pubkey, privkey); break; } } EVP_PKEY_assign(pkey, id, key); return 1; err: OPENSSL_free(key); return 0; }