X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=test%2Fdrbgtest.c;h=c1887d659d172601e7281c04c1c52bdaec91be77;hb=c2278c8bc41b01df9fac5fc3d7134430a88dd0e5;hp=68c169793c9987a5eed7d9fe4c6667eaf454ed5c;hpb=08a65d9686b131cb4193feaaf1d5cef941fa349c;p=openssl.git diff --git a/test/drbgtest.c b/test/drbgtest.c index 68c169793c..c1887d659d 100644 --- a/test/drbgtest.c +++ b/test/drbgtest.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -16,6 +16,11 @@ #include #include #include "../crypto/rand/rand_lcl.h" +#include "../crypto/include/internal/rand_int.h" + +#if defined(_WIN32) +# include +#endif #include "testutil.h" #include "drbgtest.h" @@ -88,16 +93,19 @@ typedef struct drbg_selftest_data_st { pr##_pr_returnedbits, sizeof(pr##_pr_returnedbits) \ } -#define make_drbg_test_data_df(nid, pr, p) \ - make_drbg_test_data(nid, RAND_DRBG_FLAG_CTR_USE_DF, pr, p) +#define make_drbg_test_data_use_df(nid, pr, p) \ + make_drbg_test_data(nid, 0, pr, p) + +#define make_drbg_test_data_no_df(nid, pr, p) \ + make_drbg_test_data(nid, RAND_DRBG_FLAG_CTR_NO_DF, pr, p) static DRBG_SELFTEST_DATA drbg_test[] = { - make_drbg_test_data (NID_aes_128_ctr, 0, aes_128_no_df, 0), - make_drbg_test_data (NID_aes_192_ctr, 0, aes_192_no_df, 0), - make_drbg_test_data (NID_aes_256_ctr, 0, aes_256_no_df, 1), - make_drbg_test_data_df(NID_aes_128_ctr, aes_128_use_df, 0), - make_drbg_test_data_df(NID_aes_192_ctr, aes_192_use_df, 0), - make_drbg_test_data_df(NID_aes_256_ctr, aes_256_use_df, 1), + make_drbg_test_data_no_df (NID_aes_128_ctr, aes_128_no_df, 0), + make_drbg_test_data_no_df (NID_aes_192_ctr, aes_192_no_df, 0), + make_drbg_test_data_no_df (NID_aes_256_ctr, aes_256_no_df, 1), + make_drbg_test_data_use_df(NID_aes_128_ctr, aes_128_use_df, 0), + make_drbg_test_data_use_df(NID_aes_192_ctr, aes_192_use_df, 0), + make_drbg_test_data_use_df(NID_aes_256_ctr, aes_256_use_df, 1), }; static int app_data_index; @@ -115,7 +123,8 @@ typedef struct test_ctx_st { } TEST_CTX; static size_t kat_entropy(RAND_DRBG *drbg, unsigned char **pout, - int entropy, size_t min_len, size_t max_len) + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) { TEST_CTX *t = (TEST_CTX *)RAND_DRBG_get_ex_data(drbg, app_data_index); @@ -179,7 +188,7 @@ static int single_kat(DRBG_SELFTEST_DATA *td) /* Reseed DRBG with test entropy and additional input */ t.entropy = td->entropyreseed; t.entropylen = td->entropyreseedlen; - if (!TEST_true(RAND_DRBG_reseed(drbg, td->adinreseed, td->adinreseedlen) + if (!TEST_true(RAND_DRBG_reseed(drbg, td->adinreseed, td->adinreseedlen, 0) || !TEST_true(RAND_DRBG_generate(drbg, buff, td->kat2len, 0, td->adin2, td->adin2len)) || !TEST_mem_eq(td->kat2, td->kat2len, buff, td->kat2len))) @@ -412,12 +421,12 @@ static int error_check(DRBG_SELFTEST_DATA *td) /* Test explicit reseed with too large additional input */ if (!init(drbg, td, &t) - || RAND_DRBG_reseed(drbg, td->adin, drbg->max_adinlen + 1) > 0) + || RAND_DRBG_reseed(drbg, td->adin, drbg->max_adinlen + 1, 0) > 0) goto err; /* Test explicit reseed with entropy source failure */ t.entropylen = 0; - if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen), 0) + if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; @@ -425,7 +434,7 @@ static int error_check(DRBG_SELFTEST_DATA *td) if (!init(drbg, td, &t)) goto err; t.entropylen = drbg->max_entropylen + 1; - if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen), 0) + if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; @@ -433,12 +442,12 @@ static int error_check(DRBG_SELFTEST_DATA *td) if (!init(drbg, td, &t)) goto err; t.entropylen = drbg->min_entropylen - 1; - if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen), 0) + if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; /* Standard says we have to check uninstantiate really zeroes */ - if (!TEST_mem_eq(zero, sizeof(drbg->ctr), &drbg->ctr, sizeof(drbg->ctr))) + if (!TEST_mem_eq(zero, sizeof(drbg->data), &drbg->data, sizeof(drbg->data))) goto err; ret = 1; @@ -501,7 +510,8 @@ static HOOK_CTX *get_hook_ctx(RAND_DRBG *drbg) /* Intercepts and counts calls to the get_entropy() callback */ static size_t get_entropy_hook(RAND_DRBG *drbg, unsigned char **pout, - int entropy, size_t min_len, size_t max_len) + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) { size_t ret; HOOK_CTX *ctx = get_hook_ctx(drbg); @@ -509,8 +519,8 @@ static size_t get_entropy_hook(RAND_DRBG *drbg, unsigned char **pout, if (ctx->fail != 0) return 0; - ret = ctx->get_entropy( - drbg, pout, entropy, min_len, max_len); + ret = ctx->get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); if (ret != 0) ctx->reseed_count++; @@ -544,7 +554,7 @@ static void reset_hook_ctx(HOOK_CTX *ctx) } /* Resets all drbg hook contexts */ -static void reset_drbg_hook_ctx() +static void reset_drbg_hook_ctx(void) { reset_hook_ctx(&master_ctx); reset_hook_ctx(&public_ctx); @@ -682,13 +692,28 @@ static int test_rand_reseed(void) || !TEST_ptr_eq(private->parent, master)) return 0; + /* uninstantiate the three global DRBGs */ + RAND_DRBG_uninstantiate(private); + RAND_DRBG_uninstantiate(public); + RAND_DRBG_uninstantiate(master); + + /* Install hooks for the following tests */ hook_drbg(master, &master_ctx); hook_drbg(public, &public_ctx); hook_drbg(private, &private_ctx); + /* - * Test initial state of shared DRBs + * Test initial seeding of shared DRBGs + */ + if (!TEST_true(test_drbg_reseed(1, master, public, private, 1, 1, 1))) + goto error; + reset_drbg_hook_ctx(); + + + /* + * Test initial state of shared DRBGs */ if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 0, 0))) goto error; @@ -757,6 +782,159 @@ error: return rv; } +#if defined(OPENSSL_THREADS) +static int multi_thread_rand_bytes_succeeded = 1; +static int multi_thread_rand_priv_bytes_succeeded = 1; + +static void run_multi_thread_test(void) +{ + unsigned char buf[256]; + time_t start = time(NULL); + RAND_DRBG *public, *private; + + public = RAND_DRBG_get0_public(); + private = RAND_DRBG_get0_private(); + RAND_DRBG_set_reseed_time_interval(public, 1); + RAND_DRBG_set_reseed_time_interval(private, 1); + + do { + if (RAND_bytes(buf, sizeof(buf)) <= 0) + multi_thread_rand_bytes_succeeded = 0; + if (RAND_priv_bytes(buf, sizeof(buf)) <= 0) + multi_thread_rand_priv_bytes_succeeded = 0; + } + while(time(NULL) - start < 5); +} + +# if defined(OPENSSL_SYS_WINDOWS) + +typedef HANDLE thread_t; + +static DWORD WINAPI thread_run(LPVOID arg) +{ + run_multi_thread_test(); + return 0; +} + +static int run_thread(thread_t *t) +{ + *t = CreateThread(NULL, 0, thread_run, NULL, 0, NULL); + return *t != NULL; +} + +static int wait_for_thread(thread_t thread) +{ + return WaitForSingleObject(thread, INFINITE) == 0; +} + +# else + +typedef pthread_t thread_t; + +static void *thread_run(void *arg) +{ + run_multi_thread_test(); + return NULL; +} + +static int run_thread(thread_t *t) +{ + return pthread_create(t, NULL, thread_run, NULL) == 0; +} + +static int wait_for_thread(thread_t thread) +{ + return pthread_join(thread, NULL) == 0; +} + +# endif + +/* + * The main thread will also run the test, so we'll have THREADS+1 parallel + * tests running + */ +# define THREADS 3 + +static int test_multi_thread(void) +{ + thread_t t[THREADS]; + int i; + + for (i = 0; i < THREADS; i++) + run_thread(&t[i]); + run_multi_thread_test(); + for (i = 0; i < THREADS; i++) + wait_for_thread(t[i]); + + if (!TEST_true(multi_thread_rand_bytes_succeeded)) + return 0; + if (!TEST_true(multi_thread_rand_priv_bytes_succeeded)) + return 0; + + return 1; +} +#endif + +/* + * This function only returns the entropy already added with RAND_add(), + * and does not get entropy from the OS. + * + * Returns 0 on failure and the size of the buffer on success. + */ +static size_t get_pool_entropy(RAND_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + if (drbg->pool == NULL) + return 0; + + if (drbg->pool->entropy < (size_t)entropy || drbg->pool->len < min_len + || drbg->pool->len > max_len) + return 0; + + *pout = drbg->pool->buffer; + return drbg->pool->len; +} + +/* + * Clean up the entropy that get_pool_entropy() returned. + */ +static void cleanup_pool_entropy(RAND_DRBG *drbg, unsigned char *out, size_t outlen) +{ + OPENSSL_secure_clear_free(drbg->pool->buffer, drbg->pool->max_len); + OPENSSL_free(drbg->pool); + drbg->pool = NULL; +} + +/* + * Test that instantiating works when OS entropy is not available and that + * RAND_add() is enough to reseed it. + */ +static int test_rand_add(void) +{ + RAND_DRBG *master = RAND_DRBG_get0_master(); + RAND_DRBG_get_entropy_fn old_get_entropy = master->get_entropy; + RAND_DRBG_cleanup_entropy_fn old_cleanup_entropy = master->cleanup_entropy; + int rv = 0; + unsigned char rand_add_buf[256]; + + master->get_entropy = get_pool_entropy; + master->cleanup_entropy = cleanup_pool_entropy; + master->reseed_counter++; + RAND_DRBG_uninstantiate(master); + memset(rand_add_buf, 0xCD, sizeof(rand_add_buf)); + RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf)); + if (!TEST_true(RAND_DRBG_instantiate(master, NULL, 0))) + goto error; + + rv = 1; + +error: + master->get_entropy = old_get_entropy; + master->cleanup_entropy = old_cleanup_entropy; + return rv; +} int setup_tests(void) { @@ -765,5 +943,9 @@ int setup_tests(void) ADD_ALL_TESTS(test_kats, OSSL_NELEM(drbg_test)); ADD_ALL_TESTS(test_error_checks, OSSL_NELEM(drbg_test)); ADD_TEST(test_rand_reseed); + ADD_TEST(test_rand_add); +#if defined(OPENSSL_THREADS) + ADD_TEST(test_multi_thread); +#endif return 1; }