How to set my seed provider openssl default?

119 Views Asked by At

I want to use my seed provider in openssl v3. I implemented provider but api only allows to use "EVP_RAND_generate" function.

I want to inject my seed provider into openssl default. When i use "RAND_bytes" it must use my seed provider.

How can i do this?


#include <openssl/rand.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 <openssl/proverr.h>
#include <openssl/provider.h>

#include <cstring>

#include <unistd.h>

const int RandomNumberBlockSize = 32;
const int OsslRandStrength = 1024;
const int OsslRandMaxRequest = 128;

OSSL_FUNC_rand_newctx_fn seedSrcNew;
OSSL_FUNC_rand_freectx_fn seedSrcFree;
OSSL_FUNC_rand_instantiate_fn seedSrcInstantiate;
OSSL_FUNC_rand_uninstantiate_fn seedSrcUninstantiate;
OSSL_FUNC_rand_generate_fn seedSrcGenerate;
OSSL_FUNC_rand_reseed_fn seedSrcReseed;
OSSL_FUNC_rand_gettable_ctx_params_fn seedSrcGettableCtxParams;
OSSL_FUNC_rand_get_ctx_params_fn seedSrcGetCtxParams;
OSSL_FUNC_rand_verify_zeroization_fn seedSrcVerifyZeroization;
OSSL_FUNC_rand_enable_locking_fn seedSrcEnableLocking;
OSSL_FUNC_rand_lock_fn seedSrcLock;
OSSL_FUNC_rand_unlock_fn seedSrcUnlock;
OSSL_FUNC_rand_get_seed_fn seedGetSeed;
OSSL_FUNC_rand_clear_seed_fn seedClearSeed;

typedef struct {
    void* provCtx;
    int state;
} ProvSeedSrc;

void* seedSrcNew(void* provCtx, void* parent, const OSSL_DISPATCH*)
{
    printf("TRNG-SEED: seedSrcNew\n");
    ProvSeedSrc *seedSrc;

    if (parent != nullptr) {
        ERR_raise(ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT);
        return nullptr;
    }

    seedSrc = reinterpret_cast<ProvSeedSrc*>(OPENSSL_zalloc(sizeof(*seedSrc)));
    if (!seedSrc) {
        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
        return nullptr;
    }

    seedSrc->provCtx = provCtx;
    seedSrc->state = EVP_RAND_STATE_UNINITIALISED;

    return seedSrc;
}

void seedSrcFree(void* seed)
{
    printf("TRNG-SEED: seedSrcFree\n");
    OPENSSL_free(seed);
}

int seedSrcInstantiate(void* seed, unsigned int, int, const unsigned char*, size_t, ossl_unused const OSSL_PARAM[])
{
    printf("TRNG-SEED: seedSrcInstantiate\n");
    ProvSeedSrc *seedSrc = (ProvSeedSrc*)seed;

    seedSrc->state = EVP_RAND_STATE_READY;

    return 1;
}

int seedSrcUninstantiate(void* seed)
{
    printf("TRNG-SEED: seedSrcUninstantiate\n");
    ProvSeedSrc *seedSrc = (ProvSeedSrc*)seed;

    seedSrc->state = EVP_RAND_STATE_UNINITIALISED;

    return 1;
}

int seedSrcGenerate(void* seed, unsigned char* out, size_t outlen, unsigned int strength, ossl_unused int predictionResistance, ossl_unused const unsigned char* adin, ossl_unused size_t adinLength)
{
    printf("TRNG-SEED: seedSrcGenerate - %d\n", outlen);

    srand(time(nullptr));

    for (size_t i = 0; i < outlen; i++)
        out[i] = rand() % 255;

    return 1;
}

int seedSrcReseed(void* seed, ossl_unused int, ossl_unused const unsigned char*, ossl_unused size_t, ossl_unused const unsigned char*, ossl_unused size_t)
{
    printf("TRNG-SEED: seedSrcReseed\n");
    ProvSeedSrc *seedSrc = (ProvSeedSrc*)seed;

    if (seedSrc->state != EVP_RAND_STATE_READY) {
        ERR_raise(ERR_LIB_PROV, seedSrc->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE : PROV_R_NOT_INSTANTIATED);
        return 0;
    }

    return 1;
}

int seedSrcGetCtxParams(void* seed, OSSL_PARAM params[])
{
    // printf("TRNG-SEED: seedSrcGetCtxParams\n");
    ProvSeedSrc *seedSrc = (ProvSeedSrc*)seed;

    OSSL_PARAM* p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);
    if (p != nullptr && !OSSL_PARAM_set_int(p, seedSrc->state))
        return 0;

    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH);
    if (p != nullptr && !OSSL_PARAM_set_int(p, OsslRandStrength))
        return 0;

    p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
    if (p != nullptr && !OSSL_PARAM_set_size_t(p, OsslRandMaxRequest))
        return 0;

    return 1;
}

const OSSL_PARAM *seedSrcGettableCtxParams(ossl_unused void* seed, ossl_unused void*)
{
    printf("TRNG-SEED: seedSrcGettableCtxParams\n");
    static const OSSL_PARAM known_gettable_ctx_params[] = {
        OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, nullptr),
        OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, nullptr),
        OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, nullptr),
        OSSL_PARAM_END
    };

    return known_gettable_ctx_params;
}

int seedSrcVerifyZeroization(ossl_unused void* seed)
{
    printf("TRNG-SEED: seedSrcVerifyZeroization\n");
    return 1;
}

size_t seedGetSeed(void* seed, unsigned char** pout, int entropy, size_t minLength, size_t maxLength, int predictionResistance, const unsigned char* adin, size_t adinLength)
{
    printf("TRNG-SEED: seedGetSeed\n");

    size_t bytesNeeded;
    unsigned char *buffer;

    bytesNeeded = entropy >= 0 ? (entropy + 7) / 8 : 0;
    if (bytesNeeded < minLength)
        bytesNeeded = minLength;

    if (bytesNeeded > maxLength) {
        ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK);
        return 0;
    }

    buffer = reinterpret_cast<unsigned char *>(OPENSSL_secure_malloc(bytesNeeded));
    if (!buffer) {
        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
        return 0;
    }
    if (seedSrcGenerate(seed, buffer, bytesNeeded, 0, predictionResistance, adin, adinLength) != 0) {
        *pout = buffer;
        return bytesNeeded;
    }

    OPENSSL_secure_clear_free(buffer, bytesNeeded);
    return 0;
}

void seedClearSeed(ossl_unused void*, unsigned char* out, size_t outlen)
{
    printf("TRNG-SEED: seedClearSeed\n");
    OPENSSL_secure_clear_free(out, outlen);
}

int seedSrcEnableLocking(ossl_unused void*)
{
    printf("TRNG-SEED: seedSrcEnableLocking\n");
    return 1;
}

int seedSrcLock(ossl_unused void*)
{
    printf("TRNG-SEED: seedSrcLock\n");
    return 1;
}

void seedSrcUnlock(ossl_unused void*)
{
    printf("TRNG-SEED: seedSrcUnlock\n");
}

const OSSL_DISPATCH seedSrcFunctions[] = {
    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))seedSrcNew },
    { OSSL_FUNC_RAND_FREECTX, (void(*)(void))seedSrcFree },
    { OSSL_FUNC_RAND_INSTANTIATE, (void(*)(void))seedSrcInstantiate },
    { OSSL_FUNC_RAND_UNINSTANTIATE, (void(*)(void))seedSrcUninstantiate },
    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))seedSrcGenerate },
    { OSSL_FUNC_RAND_RESEED, (void(*)(void))seedSrcReseed },
    // { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))seedSrcEnableLocking },
    // { OSSL_FUNC_RAND_LOCK, (void(*)(void))seedSrcLock },
    // { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))seedSrcUnlock },
    { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, (void(*)(void))seedSrcGettableCtxParams },
    { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))seedSrcGetCtxParams },
    { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, (void(*)(void))seedSrcVerifyZeroization },
    { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))seedGetSeed },
    { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))seedClearSeed },
    { 0, nullptr }
};

const OSSL_ALGORITHM seedProviderAlgorithm[] = {
    { "TRNG-SEED", "provider=trng-seed", seedSrcFunctions },
    { nullptr, nullptr, nullptr }
};

const OSSL_ALGORITHM* seedProviderOperation(void* provCtx, int operationId, int* noCache)
{
    printf("TRNG-SEED: seedProviderOperation\n");

    *noCache = 0;
    switch (operationId) {
    case OSSL_OP_RAND:
        return seedProviderAlgorithm;
    }
    return nullptr;
}

/* The function that tears down this provider */
void seedTeardown(void *provCtx)
{
    printf("TRNG-SEED: seedTeardown\n");
    seedSrcFree(provCtx);
}

/* The base dispatch table */
const OSSL_DISPATCH providerFunctions[] = {
    { OSSL_FUNC_PROVIDER_TEARDOWN, (void(*)(void))seedTeardown },
    { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void(*)(void))seedProviderOperation },
    { 0, nullptr }
};

int seedProviderInit(const OSSL_CORE_HANDLE*, const OSSL_DISPATCH* in, const OSSL_DISPATCH** out, void** provCtx)
{
    if ((*provCtx = seedSrcNew(provCtx, nullptr, in)) == nullptr)
        return 0;

    printf("TRNG-SEED: Seed source trng is initialized successfully\n");

    *out = providerFunctions;
    return 1;
}

int main(){

    const char* name = "trng-seed";

    OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_new();
    OSSL_PROVIDER_add_builtin(ctx, name, seedProviderInit);

    //RAND_set_seed_source_type(ctx, "fake", nullptr);
    OSSL_PROVIDER* seedProvider = OSSL_PROVIDER_load(ctx, name);
    if(seedProvider == nullptr){
        printf("TRNG-SEED: DRBG set trng seed provider error\n");
        return 0;
    }

    if(OSSL_PROVIDER_available(ctx, name) != 1){
        printf("TRNG-SEED: DRBG trng seed provider is not available\n");
        return 0;
    }

    if(OSSL_PROVIDER_self_test(seedProvider) != 1){
        printf("TRNG-SEED: DRBG trng seed provider selftest failed\n");
        return 0;
    }

    /* Create a seed source */
    EVP_RAND* rand = EVP_RAND_fetch(ctx, name, nullptr);
    EVP_RAND_CTX* seed = EVP_RAND_CTX_new(rand, nullptr);
    EVP_RAND_free(rand);

    /* Feed this into a DRBG */
    rand = EVP_RAND_fetch(nullptr, "CTR-DRBG", nullptr);
    EVP_RAND_CTX* rctx = EVP_RAND_CTX_new(rand, seed);
    EVP_RAND_free(rand);

    OSSL_PARAM params[2], *p = params;
    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, SN_aes_256_ctr, 0);
    *p = OSSL_PARAM_construct_end();

    unsigned int strength = 128;
    EVP_RAND_instantiate(rctx, strength, 0, nullptr, 0, params);

    uint8_t bytes[1000000];

    EVP_RAND* rand2 = EVP_RAND_fetch(ctx, name, nullptr);
    const OSSL_PROVIDER* prov = EVP_RAND_get0_provider(rand2);

    // char provName[100];
    // const char* pProvName = provName;
    // pProvName = OSSL_PROVIDER_get0_name(prov);

    // printf("Provider Name: %s\n", pProvName);

    while(1){
        RAND_bytes(bytes, sizeof(bytes));
        //RAND_priv_bytes(bytes, sizeof(bytes));
        //EVP_RAND_generate(rctx, bytes, sizeof(bytes), 0, 0, nullptr, 0);
        //sleep(1);
    }
    
    // std::cout << "Random bytes: ";
    // for(auto byte : bytes)
    //     std::cout << std::hex << std::setfill('0') << std::setw(2) << (unsigned)byte;
    // std::cout << "\n");
    
    EVP_RAND_CTX_free(seed);
    EVP_RAND_CTX_free(rctx);

    OSSL_PROVIDER_unload(seedProvider);

    return 0;
}

If i use "EVP_RAND_generate" i can use my seed provider.

1

There are 1 best solutions below

2
Matt Caswell On

The name of the default seed source can be set via the RAND_set_seed_source_type function:

https://www.openssl.org/docs/man3.2/man3/RAND_set_seed_source_type.html

If your application calls this function and specifies the type to be your "TRNG-SEED" implementation, then OpenSSL will use that instead of the default implementation.

It is also possible to specify the name of the seed source type in the config file. See the "seed" value in the "random" section of the config file:

https://www.openssl.org/docs/man3.2/man5/config.html

The default implementation is called "SEED-SRC", so an alternative approach is to also call your implementation "SEED-SRC" and ensure your provider implementation of it is used in preference to the default implementation via the global properties, e.g. by setting the global properties to "?provider=myprov" then OpenSSL will prefer implementations from your "myprov" provider over implementations from anywhere else (the "?" indicates a preference).