hkdf: when HMAC key is all zeros, still set a valid key length
[openssl.git] / providers / implementations / rands / test_rng.c
index 3f3ab236f9c94a756dca82ed99920ce636abb177..57b36469caa58e560f3e68f4cdc744f4bc7c3417 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -8,6 +8,7 @@
  */
 
 #include <string.h>
+#include <stdlib.h>
 #include <openssl/core_dispatch.h>
 #include <openssl/e_os2.h>
 #include <openssl/params.h>
@@ -35,15 +36,18 @@ static OSSL_FUNC_rand_verify_zeroization_fn test_rng_verify_zeroization;
 static OSSL_FUNC_rand_enable_locking_fn test_rng_enable_locking;
 static OSSL_FUNC_rand_lock_fn test_rng_lock;
 static OSSL_FUNC_rand_unlock_fn test_rng_unlock;
+static OSSL_FUNC_rand_get_seed_fn test_rng_get_seed;
 
 typedef struct {
     void *provctx;
+    unsigned int generate;
     int state;
     unsigned int strength;
     size_t max_request;
     unsigned char *entropy, *nonce;
     size_t entropy_len, entropy_pos, nonce_len;
     CRYPTO_RWLOCK *lock;
+    uint32_t seed;
 } PROV_TEST_RNG;
 
 static void *test_rng_new(void *provctx, void *parent,
@@ -51,9 +55,6 @@ static void *test_rng_new(void *provctx, void *parent,
 {
     PROV_TEST_RNG *t;
 
-    if (parent != NULL)
-        return NULL;
-
     t = OPENSSL_zalloc(sizeof(*t));
     if (t == NULL)
         return NULL;
@@ -78,15 +79,17 @@ static void test_rng_free(void *vtest)
 
 static int test_rng_instantiate(void *vtest, unsigned int strength,
                                 int prediction_resistance,
-                                const unsigned char *pstr, size_t pstr_len)
+                                const unsigned char *pstr, size_t pstr_len,
+                                const OSSL_PARAM params[])
 {
     PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
 
-    if (strength > t->strength)
+    if (!test_rng_set_ctx_params(t, params) || strength > t->strength)
         return 0;
 
     t->state = EVP_RAND_STATE_READY;
     t->entropy_pos = 0;
+    t->seed = 221953166;    /* Value doesn't matter, so long as it isn't zero */
 
     return 1;
 }
@@ -96,9 +99,30 @@ static int test_rng_uninstantiate(void *vtest)
     PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
 
     t->entropy_pos = 0;
+    t->state = EVP_RAND_STATE_UNINITIALISED;
     return 1;
 }
 
+static unsigned char gen_byte(PROV_TEST_RNG *t)
+{
+    uint32_t n;
+
+    /*
+     * Implement the 32 bit xorshift as suggested by George Marsaglia in:
+     *      https://doi.org/10.18637/jss.v008.i14
+     *
+     * This is a very fast PRNG so there is no need to extract bytes one at a
+     * time and use the entire value each time.
+     */
+    n = t->seed;
+    n ^= n << 13;
+    n ^= n >> 17;
+    n ^= n << 5;
+    t->seed = n;
+
+    return n & 0xff;
+}
+
 static int test_rng_generate(void *vtest, unsigned char *out, size_t outlen,
                              unsigned int strength, int prediction_resistance,
                              const unsigned char *adin, size_t adin_len)
@@ -108,11 +132,15 @@ static int test_rng_generate(void *vtest, unsigned char *out, size_t outlen,
 
     if (strength > t->strength)
         return 0;
+    if (t->generate) {
+        for (i = 0; i < outlen; i++)
+            out[i] = gen_byte(t);
+    } else {
+        if (t->entropy_len - t->entropy_pos < outlen)
+            return 0;
 
-    for (i = 0; i < outlen; i++) {
-        out[i] = t->entropy[t->entropy_pos++];
-        if (t->entropy_pos >= t->entropy_len)
-            break;
+        memcpy(out, t->entropy + t->entropy_pos, outlen);
+        t->entropy_pos += outlen;
     }
     return 1;
 }
@@ -128,15 +156,23 @@ static int test_rng_reseed(ossl_unused void *vtest,
 }
 
 static size_t test_rng_nonce(void *vtest, unsigned char *out,
-                             unsigned int strength,
-                             ossl_unused size_t min_noncelen,
+                             unsigned int strength, size_t min_noncelen,
                              ossl_unused size_t max_noncelen)
 {
     PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+    size_t i;
 
-    if (t->nonce == NULL || strength > t->strength)
+    if (strength > t->strength)
         return 0;
 
+    if (t->generate) {
+        for (i = 0; i < min_noncelen; i++)
+            out[i] = gen_byte(t);
+        return min_noncelen;
+    }
+
+    if (t->nonce == NULL)
+        return 0;
     if (out != NULL)
         memcpy(out, t->nonce, t->nonce_len);
     return t->nonce_len;
@@ -158,15 +194,21 @@ static int test_rng_get_ctx_params(void *vtest, OSSL_PARAM params[])
     p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
     if (p != NULL && !OSSL_PARAM_set_size_t(p, t->max_request))
         return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_GENERATE);
+    if (p != NULL && OSSL_PARAM_set_uint(p, t->generate))
+        return 0;
     return 1;
 }
 
-static const OSSL_PARAM *test_rng_gettable_ctx_params(ossl_unused void *provctx)
+static const OSSL_PARAM *test_rng_gettable_ctx_params(ossl_unused void *vtest,
+                                                      ossl_unused void *provctx)
 {
     static const OSSL_PARAM known_gettable_ctx_params[] = {
         OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL),
         OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL),
         OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL),
+        OSSL_PARAM_uint(OSSL_RAND_PARAM_GENERATE, NULL),
         OSSL_PARAM_END
     };
     return known_gettable_ctx_params;
@@ -179,6 +221,9 @@ static int test_rng_set_ctx_params(void *vtest, const OSSL_PARAM params[])
     void *ptr = NULL;
     size_t size = 0;
 
+    if (params == NULL)
+        return 1;
+
     p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_STRENGTH);
     if (p != NULL && !OSSL_PARAM_get_uint(p, &t->strength))
         return 0;
@@ -204,19 +249,24 @@ static int test_rng_set_ctx_params(void *vtest, const OSSL_PARAM params[])
     }
 
     p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_MAX_REQUEST);
-    if (p != NULL  && !OSSL_PARAM_get_size_t(p, &t->max_request))
+    if (p != NULL && !OSSL_PARAM_get_size_t(p, &t->max_request))
         return 0;
 
+    p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_GENERATE);
+    if (p != NULL && !OSSL_PARAM_get_uint(p, &t->generate))
+        return 0;
     return 1;
 }
 
-static const OSSL_PARAM *test_rng_settable_ctx_params(ossl_unused void *provctx)
+static const OSSL_PARAM *test_rng_settable_ctx_params(ossl_unused void *vtest,
+                                                      ossl_unused void *provctx)
 {
     static const OSSL_PARAM known_settable_ctx_params[] = {
         OSSL_PARAM_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, NULL, 0),
         OSSL_PARAM_octet_string(OSSL_RAND_PARAM_TEST_NONCE, NULL, 0),
         OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL),
         OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL),
+        OSSL_PARAM_uint(OSSL_RAND_PARAM_GENERATE, NULL),
         OSSL_PARAM_END
     };
     return known_settable_ctx_params;
@@ -227,6 +277,18 @@ static int test_rng_verify_zeroization(ossl_unused void *vtest)
     return 1;
 }
 
+static size_t test_rng_get_seed(void *vtest, unsigned char **pout,
+                                int entropy, size_t min_len, size_t max_len,
+                                ossl_unused int prediction_resistance,
+                                ossl_unused const unsigned char *adin,
+                                ossl_unused size_t adin_len)
+{
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+
+    *pout = t->entropy;
+    return  t->entropy_len > max_len ? max_len : t->entropy_len;
+}
+
 static int test_rng_enable_locking(void *vtest)
 {
     PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
@@ -279,5 +341,6 @@ const OSSL_DISPATCH ossl_test_rng_functions[] = {
     { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))test_rng_get_ctx_params },
     { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
       (void(*)(void))test_rng_verify_zeroization },
-    { 0, NULL }
+    { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))test_rng_get_seed },
+    OSSL_DISPATCH_END
 };