test: update EVP tests to include DRBG testing
authorPauli <paul.dale@oracle.com>
Fri, 5 Jun 2020 03:47:55 +0000 (13:47 +1000)
committerPauli <paul.dale@oracle.com>
Wed, 24 Jun 2020 10:07:46 +0000 (20:07 +1000)
[extended tests]

Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
(Merged from https://github.com/openssl/openssl/pull/11682)

test/evp_test.c
test/recipes/30-test_evp.t
test/testutil.h

index ef5d9500187ccc7d26588232339fd8bc5906f988..c0b7b6f50fa37387fa08e4e4d06d120a576b65bc 100644 (file)
@@ -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,
index 5f7585cc790f057c782d6935219db82eded2f9ec..27b3781f27935bbbc0871613cd2cddd3880ebf37 100644 (file)
@@ -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 );
index bacb6bb939e5adbd80cba5afaf49ee0e3e8b9598..69869e260138ddad23c0efea453f882871b3ce40 100644 (file)
@@ -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;