From c9ed9307f2dfaba01b3c3b9e489fe358e6070b50 Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 5 Jun 2020 13:47:55 +1000 Subject: [PATCH] test: update EVP tests to include DRBG testing [extended tests] Reviewed-by: Matthias St. Pierre (Merged from https://github.com/openssl/openssl/pull/11682) --- test/evp_test.c | 286 +++++++++++++++++++++++++++++++++++++ test/recipes/30-test_evp.t | 3 +- test/testutil.h | 2 +- 3 files changed, 289 insertions(+), 2 deletions(-) diff --git a/test/evp_test.c b/test/evp_test.c index ef5d950018..c0b7b6f50f 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -2047,6 +2047,291 @@ static const EVP_TEST_METHOD encode_test_method = { }; +/** +*** RAND TESTS +**/ + +#define MAX_RAND_REPEATS 15 + +typedef struct rand_data_pass_st { + unsigned char *entropy; + unsigned char *reseed_entropy; + unsigned char *nonce; + unsigned char *pers; + unsigned char *reseed_addin; + unsigned char *addinA; + unsigned char *addinB; + unsigned char *pr_entropyA; + unsigned char *pr_entropyB; + unsigned char *output; + size_t entropy_len, nonce_len, pers_len, addinA_len, addinB_len, + pr_entropyA_len, pr_entropyB_len, output_len, reseed_entropy_len, + reseed_addin_len; +} RAND_DATA_PASS; + +typedef struct rand_data_st { + /* Context for this operation */ + EVP_RAND_CTX *ctx; + EVP_RAND_CTX *parent; + int n; + int prediction_resistance; + int use_df; + unsigned int generate_bits; + char *cipher; + char *digest; + + /* Expected output */ + RAND_DATA_PASS data[MAX_RAND_REPEATS]; +} RAND_DATA; + +static int rand_test_init(EVP_TEST *t, const char *name) +{ + RAND_DATA *rdata; + EVP_RAND *rand; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + unsigned int strength = 256; + + if (!TEST_ptr(rdata = OPENSSL_zalloc(sizeof(*rdata)))) + return 0; + + rand = EVP_RAND_fetch(NULL, "TEST-RAND", NULL); + if (rand == NULL) + goto err; + rdata->parent = EVP_RAND_CTX_new(rand, NULL); + EVP_RAND_free(rand); + if (rdata->parent == NULL) + goto err; + + *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength); + if (!EVP_RAND_set_ctx_params(rdata->parent, params)) + goto err; + + rand = EVP_RAND_fetch(NULL, name, NULL); + if (rand == NULL) + goto err; + rdata->ctx = EVP_RAND_CTX_new(rand, rdata->parent); + EVP_RAND_free(rand); + if (rdata->ctx == NULL) + goto err; + + rdata->n = -1; + t->data = rdata; + return 1; + err: + EVP_RAND_CTX_free(rdata->parent); + OPENSSL_free(rdata); + return 0; +} + +static void rand_test_cleanup(EVP_TEST *t) +{ + RAND_DATA *rdata = t->data; + int i; + + OPENSSL_free(rdata->cipher); + OPENSSL_free(rdata->digest); + + for (i = 0; i <= rdata->n; i++) { + OPENSSL_free(rdata->data[i].entropy); + OPENSSL_free(rdata->data[i].reseed_entropy); + OPENSSL_free(rdata->data[i].nonce); + OPENSSL_free(rdata->data[i].pers); + OPENSSL_free(rdata->data[i].reseed_addin); + OPENSSL_free(rdata->data[i].addinA); + OPENSSL_free(rdata->data[i].addinB); + OPENSSL_free(rdata->data[i].pr_entropyA); + OPENSSL_free(rdata->data[i].pr_entropyB); + OPENSSL_free(rdata->data[i].output); + } + EVP_RAND_CTX_free(rdata->ctx); + EVP_RAND_CTX_free(rdata->parent); +} + +static int rand_test_parse(EVP_TEST *t, + const char *keyword, const char *value) +{ + RAND_DATA *rdata = t->data; + RAND_DATA_PASS *item; + const char *p; + int n; + + if ((p = strchr(keyword, '.')) != NULL) { + n = atoi(++p); + if (n >= MAX_RAND_REPEATS) + return 0; + if (n > rdata->n) + rdata->n = n; + item = rdata->data + n; + if (strncmp(keyword, "Entropy.", sizeof("Entropy")) == 0) + return parse_bin(value, &item->entropy, &item->entropy_len); + if (strncmp(keyword, "ReseedEntropy.", sizeof("ReseedEntropy")) == 0) + return parse_bin(value, &item->reseed_entropy, + &item->reseed_entropy_len); + if (strncmp(keyword, "Nonce.", sizeof("Nonce")) == 0) + return parse_bin(value, &item->nonce, &item->nonce_len); + if (strncmp(keyword, "PersonalisationString.", + sizeof("PersonalisationString")) == 0) + return parse_bin(value, &item->pers, &item->pers_len); + if (strncmp(keyword, "ReseedAdditionalInput.", + sizeof("ReseedAdditionalInput")) == 0) + return parse_bin(value, &item->reseed_addin, + &item->reseed_addin_len); + if (strncmp(keyword, "AdditionalInputA.", + sizeof("AdditionalInputA")) == 0) + return parse_bin(value, &item->addinA, &item->addinA_len); + if (strncmp(keyword, "AdditionalInputB.", + sizeof("AdditionalInputB")) == 0) + return parse_bin(value, &item->addinB, &item->addinB_len); + if (strncmp(keyword, "EntropyPredictionResistanceA.", + sizeof("EntropyPredictionResistanceA")) == 0) + return parse_bin(value, &item->pr_entropyA, &item->pr_entropyA_len); + if (strncmp(keyword, "EntropyPredictionResistanceB.", + sizeof("EntropyPredictionResistanceB")) == 0) + return parse_bin(value, &item->pr_entropyB, &item->pr_entropyB_len); + if (strncmp(keyword, "Output.", sizeof("Output")) == 0) + return parse_bin(value, &item->output, &item->output_len); + } else { + if (strcmp(keyword, "Cipher") == 0) + return TEST_ptr(rdata->cipher = OPENSSL_strdup(value)); + if (strcmp(keyword, "Digest") == 0) + return TEST_ptr(rdata->digest = OPENSSL_strdup(value)); + if (strcmp(keyword, "DerivationFunction") == 0) { + rdata->use_df = atoi(value) != 0; + return 1; + } + if (strcmp(keyword, "GenerateBits") == 0) { + if ((n = atoi(value)) <= 0 || n % 8 != 0) + return 0; + rdata->generate_bits = (unsigned int)n; + return 1; + } + if (strcmp(keyword, "PredictionResistance") == 0) { + rdata->prediction_resistance = atoi(value) != 0; + return 1; + } + } + return 0; +} + +static int rand_test_run(EVP_TEST *t) +{ + RAND_DATA *expected = t->data; + RAND_DATA_PASS *item; + unsigned char *got; + size_t got_len = expected->generate_bits / 8; + OSSL_PARAM params[5], *p = params; + int i = -1, ret = 0; + unsigned int strength; + unsigned char *z; + + if (!TEST_ptr(got = OPENSSL_malloc(got_len))) + return 0; + + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &expected->use_df); + if (expected->cipher != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, + expected->cipher, 0); + if (expected->digest != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, + expected->digest, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, "HMAC", 0); + *p = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->ctx, params))) + goto err; + + strength = EVP_RAND_strength(expected->ctx); + for (i = 0; i <= expected->n; i++) { + item = expected->data + i; + + p = params; + z = item->entropy != NULL ? item->entropy : (unsigned char *)""; + *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, + z, item->entropy_len); + z = item->nonce != NULL ? item->nonce : (unsigned char *)""; + *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_NONCE, + z, item->nonce_len); + *p = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params)) + || !TEST_true(EVP_RAND_instantiate(expected->parent, strength, + 0, NULL, 0))) + goto err; + + z = item->pers != NULL ? item->pers : (unsigned char *)""; + if (!TEST_true(EVP_RAND_instantiate + (expected->ctx, strength, + expected->prediction_resistance, z, + item->pers_len))) + goto err; + + if (item->reseed_entropy != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->reseed_entropy, + item->reseed_entropy_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + goto err; + + if (!TEST_true(EVP_RAND_reseed + (expected->ctx, expected->prediction_resistance, + NULL, 0, item->reseed_addin, + item->reseed_addin_len))) + goto err; + } + if (item->pr_entropyA != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->pr_entropyA, + item->pr_entropyA_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + goto err; + } + if (!TEST_true(EVP_RAND_generate + (expected->ctx, got, got_len, + strength, expected->prediction_resistance, + item->addinA, item->addinA_len))) + goto err; + + if (item->pr_entropyB != NULL) { + params[0] = OSSL_PARAM_construct_octet_string + (OSSL_RAND_PARAM_TEST_ENTROPY, item->pr_entropyB, + item->pr_entropyB_len); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_RAND_set_ctx_params(expected->parent, params))) + return 0; + } + if (!TEST_true(EVP_RAND_generate + (expected->ctx, got, got_len, + strength, expected->prediction_resistance, + item->addinB, item->addinB_len))) + goto err; + if (!TEST_mem_eq(got, got_len, item->output, item->output_len)) + goto err; + if (!TEST_true(EVP_RAND_uninstantiate(expected->ctx)) + || !TEST_true(EVP_RAND_uninstantiate(expected->parent)) + || !TEST_true(EVP_RAND_verify_zeroization(expected->ctx)) + || !TEST_int_eq(EVP_RAND_state(expected->ctx), + EVP_RAND_STATE_UNINITIALISED)) + goto err; + } + t->err = NULL; + ret = 1; + + err: + if (ret == 0 && i >= 0) + TEST_info("Error in test case %d of %d\n", i, expected->n + 1); + OPENSSL_free(got); + return ret; +} + +static const EVP_TEST_METHOD rand_test_method = { + "RAND", + rand_test_init, + rand_test_cleanup, + rand_test_parse, + rand_test_run +}; + + /** *** KDF TESTS **/ @@ -2819,6 +3104,7 @@ static const EVP_TEST_METHOD oneshot_digestverify_test_method = { **/ static const EVP_TEST_METHOD *evp_test_list[] = { + &rand_test_method, &cipher_test_method, &digest_test_method, &digestsign_test_method, diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t index 5f7585cc79..27b3781f27 100644 --- a/test/recipes/30-test_evp.t +++ b/test/recipes/30-test_evp.t @@ -31,7 +31,8 @@ my @configs = ( $defaultcnf ); # Only add the FIPS config if the FIPS module has been built push @configs, 'fips.cnf' unless $no_fips; -my @files = qw( evpciph.txt evpdigest.txt evppkey.txt evppkey_ecc.txt); +my @files = qw( evprand.txt evpciph.txt evpdigest.txt evppkey.txt + evppkey_ecc.txt ); my @defltfiles = qw( evpencod.txt evpkdf.txt evppkey_kdf.txt evpmac.txt evppbe.txt evpcase.txt evpccmcavs.txt ); my @ideafiles = qw( evpciph_idea.txt ); diff --git a/test/testutil.h b/test/testutil.h index bacb6bb939..69869e2601 100644 --- a/test/testutil.h +++ b/test/testutil.h @@ -496,7 +496,7 @@ void test_output_memory(const char *name, const unsigned char *m, size_t l); /* * Utilities to parse a test file. */ -#define TESTMAXPAIRS 20 +#define TESTMAXPAIRS 150 typedef struct pair_st { char *key; -- 2.25.1