.ctags.d is previous, include it in our tarballs
[openssl.git] / providers / implementations / rands / test_rng.c
index 7303d36f2f6aa18f5ce97ba9a02fb9b3fc525dce..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
  */
 
 #include <string.h>
+#include <stdlib.h>
 #include <openssl/core_dispatch.h>
 #include <openssl/e_os2.h>
 #include <openssl/params.h>
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/randerr.h>
 #include "prov/providercommon.h"
 #include "prov/provider_ctx.h"
 #include "prov/provider_util.h"
 #include "prov/implementations.h"
-#include "drbg_local.h"
 
-static OSSL_FUNC_rand_newctx_fn test_rng_new_wrapper;
+static OSSL_FUNC_rand_newctx_fn test_rng_new;
 static OSSL_FUNC_rand_freectx_fn test_rng_free;
-static OSSL_FUNC_rand_instantiate_fn test_rng_instantiate_wrapper;
-static OSSL_FUNC_rand_uninstantiate_fn test_rng_uninstantiate_wrapper;
-static OSSL_FUNC_rand_generate_fn test_rng_generate_wrapper;
-static OSSL_FUNC_rand_reseed_fn test_rng_reseed_wrapper;
+static OSSL_FUNC_rand_instantiate_fn test_rng_instantiate;
+static OSSL_FUNC_rand_uninstantiate_fn test_rng_uninstantiate;
+static OSSL_FUNC_rand_generate_fn test_rng_generate;
+static OSSL_FUNC_rand_reseed_fn test_rng_reseed;
 static OSSL_FUNC_rand_nonce_fn test_rng_nonce;
 static OSSL_FUNC_rand_settable_ctx_params_fn test_rng_settable_ctx_params;
 static OSSL_FUNC_rand_set_ctx_params_fn test_rng_set_ctx_params;
 static OSSL_FUNC_rand_gettable_ctx_params_fn test_rng_gettable_ctx_params;
 static OSSL_FUNC_rand_get_ctx_params_fn test_rng_get_ctx_params;
 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;
-    unsigned int strength;
+    CRYPTO_RWLOCK *lock;
+    uint32_t seed;
 } PROV_TEST_RNG;
 
-static int test_rng_new(PROV_DRBG *ctx)
+static void *test_rng_new(void *provctx, void *parent,
+                          const OSSL_DISPATCH *parent_dispatch)
 {
     PROV_TEST_RNG *t;
 
     t = OPENSSL_zalloc(sizeof(*t));
     if (t == NULL)
-        return 0;
-    ctx->data = t;
-    ctx->seedlen = INT_MAX;
-    ctx->max_entropylen = INT_MAX;
-    ctx->max_noncelen = INT_MAX;
-    ctx->max_perslen = INT_MAX;
-    ctx->max_adinlen = INT_MAX;
-    ctx->max_request = INT_MAX;
-    return 1;
+        return NULL;
+
+    t->max_request = INT_MAX;
+    t->provctx = provctx;
+    t->state = EVP_RAND_STATE_UNINITIALISED;
+    return t;
 }
 
-static void test_rng_free(void *vdrbg)
+static void test_rng_free(void *vtest)
 {
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
 
+    if (t == NULL)
+        return;
     OPENSSL_free(t->entropy);
     OPENSSL_free(t->nonce);
-    OPENSSL_free(drbg->data);
-    prov_rand_drbg_free(drbg);
+    CRYPTO_THREAD_lock_free(t->lock);
+    OPENSSL_free(t);
 }
 
-static int test_rng_instantiate(PROV_DRBG *drbg,
-                                const unsigned char *ent, size_t ent_len,
-                                const unsigned char *nonce, size_t nonce_len,
-                                const unsigned char *pstr, size_t pstr_len)
+static int test_rng_instantiate(void *vtest, unsigned int strength,
+                                int prediction_resistance,
+                                const unsigned char *pstr, size_t pstr_len,
+                                const OSSL_PARAM params[])
 {
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
 
-    if (ent != NULL && (ent_len < drbg->min_entropylen
-                        || ent_len >= drbg->max_entropylen))
-        return 0;
-    if (nonce != NULL && (nonce_len < drbg->min_noncelen
-                        || nonce_len >= drbg->max_noncelen))
-        return 0;
-    if (pstr != NULL && pstr_len >= drbg->max_perslen)
+    if (!test_rng_set_ctx_params(t, params) || strength > t->strength)
         return 0;
 
+    t->state = EVP_RAND_STATE_READY;
     t->entropy_pos = 0;
-    return 1;
-}
-
-static int test_rng_instantiate_wrapper(void *vdrbg, unsigned int strength,
-                                        int prediction_resistance,
-                                        const unsigned char *pstr,
-                                        size_t pstr_len)
-{
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
-
-    if (pstr != NULL && pstr_len >= drbg->max_perslen)
-        return 0;
+    t->seed = 221953166;    /* Value doesn't matter, so long as it isn't zero */
 
-    return PROV_DRBG_instantiate(drbg, strength, prediction_resistance,
-                                 pstr, pstr_len);
+    return 1;
 }
 
-static int test_rng_uninstantiate(PROV_DRBG *drbg)
+static int test_rng_uninstantiate(void *vtest)
 {
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
 
     t->entropy_pos = 0;
-    return PROV_DRBG_uninstantiate(drbg);
+    t->state = EVP_RAND_STATE_UNINITIALISED;
+    return 1;
 }
 
-static int test_rng_uninstantiate_wrapper(void *vdrbg)
+static unsigned char gen_byte(PROV_TEST_RNG *t)
 {
-    return test_rng_uninstantiate((PROV_DRBG *)vdrbg);
+    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(PROV_DRBG *drbg,
-                             unsigned char *out, size_t outlen,
+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)
 {
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
     size_t i;
 
-    if (t->entropy == NULL || (adin != NULL && adin_len >= drbg->max_adinlen))
+    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;
 }
 
-static int test_rng_generate_wrapper
-    (void *vdrbg, unsigned char *out, size_t outlen,
-      unsigned int strength, int prediction_resistance,
-      const unsigned char *adin, size_t adin_len)
+static int test_rng_reseed(ossl_unused void *vtest,
+                           ossl_unused int prediction_resistance,
+                           ossl_unused const unsigned char *ent,
+                           ossl_unused size_t ent_len,
+                           ossl_unused const unsigned char *adin,
+                           ossl_unused size_t adin_len)
 {
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
-
-    if (strength > drbg->strength)
-        return 0;
-    return test_rng_generate(drbg, out, outlen, adin, adin_len);
-}
-
-static int test_rng_reseed(PROV_DRBG *drbg,
-                            const unsigned char *ent, size_t ent_len,
-                            const unsigned char *adin, size_t adin_len)
-{
-    if (ent != NULL && (ent_len < drbg->min_entropylen
-                        || ent_len >= drbg->max_entropylen))
-        return 0;
-    if (adin != NULL && adin_len >= drbg->max_adinlen)
-        return 0;
-
     return 1;
 }
 
-static int test_rng_reseed_wrapper(void *vdrbg, int prediction_resistance,
-                                   const unsigned char *ent, size_t ent_len,
-                                   const unsigned char *adin, size_t adin_len)
-{
-    return test_rng_reseed((PROV_DRBG *)vdrbg, ent, ent_len, adin, adin_len);
-}
-
-static size_t test_rng_nonce(void *vdrbg, unsigned char *out,
+static size_t test_rng_nonce(void *vtest, unsigned char *out,
                              unsigned int strength, size_t min_noncelen,
-                             size_t max_noncelen)
+                             ossl_unused size_t max_noncelen)
 {
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+    size_t i;
 
-    if (t->nonce == NULL
-            || strength > drbg->strength
-            || min_noncelen > t->nonce_len
-            || max_noncelen < t->nonce_len)
+    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;
 }
 
-static int test_rng_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
+static int test_rng_get_ctx_params(void *vtest, OSSL_PARAM params[])
 {
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+    OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);
+    if (p != NULL && !OSSL_PARAM_set_int(p, t->state))
+        return 0;
 
-    return drbg_get_ctx_params(drbg, params);
+    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH);
+    if (p != NULL && !OSSL_PARAM_set_int(p, t->strength))
+        return 0;
+
+    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(void)
+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_DRBG_GETABLE_CTX_COMMON,
+        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;
 }
 
-static int set_size_t(const OSSL_PARAM *params, const char *name,
-                            size_t *val)
+static int test_rng_set_ctx_params(void *vtest, const OSSL_PARAM params[])
 {
-    const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, name);
-
-    return p == NULL || OSSL_PARAM_get_size_t(p, val);
-}
-
-static int test_rng_set_ctx_params(void *vdrbg, const OSSL_PARAM params[])
-{
-    PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
-    PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data;
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
     const OSSL_PARAM *p;
     void *ptr = NULL;
     size_t size = 0;
-    unsigned int uint;
+
+    if (params == NULL)
+        return 1;
 
     p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_STRENGTH);
-    if (p != NULL && !OSSL_PARAM_get_uint(p, &drbg->strength))
+    if (p != NULL && !OSSL_PARAM_get_uint(p, &t->strength))
         return 0;
 
     p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_TEST_ENTROPY);
@@ -236,82 +248,91 @@ static int test_rng_set_ctx_params(void *vdrbg, const OSSL_PARAM params[])
         t->nonce_len = size;
     }
 
-    p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_CTR);
-    if (p != NULL) {
-        if (!OSSL_PARAM_get_uint(p, &uint))
-            return 0;
-        tsan_store(&drbg->reseed_counter, uint);
-    }
-
-    p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME);
-    if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time))
+    p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_MAX_REQUEST);
+    if (p != NULL && !OSSL_PARAM_get_size_t(p, &t->max_request))
         return 0;
 
-    if (!set_size_t(params, OSSL_DRBG_PARAM_MAX_REQUEST, &drbg->max_request)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MIN_ENTROPYLEN,
-                           &drbg->min_entropylen)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MAX_ENTROPYLEN,
-                           &drbg->max_entropylen)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MIN_NONCELEN,
-                           &drbg->min_noncelen)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MAX_NONCELEN,
-                           &drbg->max_noncelen)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MAX_PERSLEN,
-                           &drbg->max_perslen)
-            || !set_size_t(params, OSSL_DRBG_PARAM_MAX_ADINLEN,
-                           &drbg->max_adinlen))
+    p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_GENERATE);
+    if (p != NULL && !OSSL_PARAM_get_uint(p, &t->generate))
         return 0;
-    return drbg_set_ctx_params(drbg, params);
+    return 1;
 }
 
-static const OSSL_PARAM *test_rng_settable_ctx_params(void)
+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_DRBG_PARAM_MAX_REQUEST, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_ENTROPYLEN, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ENTROPYLEN, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_NONCELEN, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_NONCELEN, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_PERSLEN, NULL),
-        OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ADINLEN, NULL),
-        OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_CTR, NULL),
-        OSSL_PARAM_time_t(OSSL_DRBG_PARAM_RESEED_TIME, NULL),
-        OSSL_PARAM_DRBG_SETABLE_CTX_COMMON,
+        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;
 }
 
-static int test_rng_verify_zeroization(void *vdrbg)
+static int test_rng_verify_zeroization(ossl_unused void *vtest)
 {
     return 1;
 }
 
-static void *test_rng_new_wrapper(void *provctx, void *parent,
-                                   const OSSL_DISPATCH *parent_dispatch)
+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)
 {
-    return prov_rand_drbg_new(provctx, parent, parent_dispatch,
-                              &test_rng_new, &test_rng_instantiate,
-                              &test_rng_uninstantiate, &test_rng_reseed,
-                              &test_rng_generate);
+    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;
+
+    if (t != NULL && t->lock == NULL) {
+        t->lock = CRYPTO_THREAD_lock_new();
+        if (t->lock == NULL) {
+            ERR_raise(ERR_LIB_PROV, RAND_R_FAILED_TO_CREATE_LOCK);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int test_rng_lock(void *vtest)
+{
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+
+    if (t == NULL || t->lock == NULL)
+        return 1;
+    return CRYPTO_THREAD_write_lock(t->lock);
+}
+
+static void test_rng_unlock(void *vtest)
+{
+    PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest;
+
+    if (t != NULL && t->lock != NULL)
+        CRYPTO_THREAD_unlock(t->lock);
 }
 
-const OSSL_DISPATCH test_rng_functions[] = {
-    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))test_rng_new_wrapper },
+const OSSL_DISPATCH ossl_test_rng_functions[] = {
+    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))test_rng_new },
     { OSSL_FUNC_RAND_FREECTX, (void(*)(void))test_rng_free },
     { OSSL_FUNC_RAND_INSTANTIATE,
-      (void(*)(void))test_rng_instantiate_wrapper },
+      (void(*)(void))test_rng_instantiate },
     { OSSL_FUNC_RAND_UNINSTANTIATE,
-      (void(*)(void))test_rng_uninstantiate_wrapper },
-    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))test_rng_generate_wrapper },
-    { OSSL_FUNC_RAND_RESEED, (void(*)(void))test_rng_reseed_wrapper },
+      (void(*)(void))test_rng_uninstantiate },
+    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))test_rng_generate },
+    { OSSL_FUNC_RAND_RESEED, (void(*)(void))test_rng_reseed },
     { OSSL_FUNC_RAND_NONCE, (void(*)(void))test_rng_nonce },
-    { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking },
-    { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock },
-    { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock },
+    { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))test_rng_enable_locking },
+    { OSSL_FUNC_RAND_LOCK, (void(*)(void))test_rng_lock },
+    { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))test_rng_unlock },
     { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS,
       (void(*)(void))test_rng_settable_ctx_params },
     { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))test_rng_set_ctx_params },
@@ -320,5 +341,6 @@ const OSSL_DISPATCH 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
 };