Closed Syllinia closed 3 months ago
$ /inst/bin/openssl rand -provider-path . -provider rng -propquery "provider=rng,fips=no" 4
80927D044D7F0000:error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported:crypto/evp/evp_fetch.c:341:Global default library context, Algorithm (CTR-DRBG : 117), Properties (<null>)
80927D044D7F0000:error:12000090:random number generator:rand_new_drbg:unable to fetch drbg:crypto/rand/rand_lib.c:647:
provider_init_fn = dlsym(handle, "OSSL_provider_init");
if (NULL == provider_init_fn) {
ERR_RND("Failed to load func(%s)\n", dlerror());
goto out;
}
if (OSSL_PROVIDER_add_builtin(NULL, "rng", provider_init_fn) == 0) {
ERR_RND("Failed to add rng provider\n");
goto out;
}
This is a little odd. Your rng.so seems to have an exported OSSL_provider_init
function - but you are adding it as a "built-in". Why not just load it as a regular provider?
The binary crashed. Any constructive suggestions are highly welcomed.
We really need to see the code from your provider. Can you share that?
@mattcaswell Thanks Matt. I use dlopen/dlsym/OSSL_PROVIDER_add_builtin for legacy.so which is NOT in the default location indicated by "openssl version -d". So I thought the same method may work for rng.so.
Code from rng provider is as follows.
static const char RNG_FIPS_PROPERTIES[] = "provider=rng,fips=yes";
static const char RNG_NON_FIPS_PROPERTIES[] = "provider=rng,fips=no";
const OSSL_DISPATCH rng_fips_drbg_ctr_functions[] = {
{ OSSL_FUNC_RAND_NEWCTX, (void(*)(void))rng_newctx },
{ OSSL_FUNC_RAND_FREECTX, (void(*)(void))rng_freectx },
{ OSSL_FUNC_RAND_INSTANTIATE, (void(*)(void))rng_drbg_ctr_instantiate },
{ OSSL_FUNC_RAND_UNINSTANTIATE, (void(*)(void))rng_drbg_ctr_uninstantiate },
{ OSSL_FUNC_RAND_GENERATE, (void(*)(void))rng_fips_drbg_ctr_generate },
//{ OSSL_FUNC_RAND_RESEED, (void(*)(void))rng_drbg_ctr_reseed },
/*{ OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking },
{ OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock },
{ OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock },
{ OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, (void(*)(void))drbg_ctr_settable_ctx_params },
{ OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params },
{ OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, (void(*)(void))drbg_ctr_gettable_ctx_params },
{ OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params },*/
{ OSSL_FUNC_RAND_VERIFY_ZEROIZATION, (void(*)(void))rng_drbg_ctr_verify_zeroization },
/*{ OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed },
{ OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))rng_drbg_clear_seed },*/
{ 0, NULL }
};
const OSSL_DISPATCH rng_non_fips_drbg_ctr_functions[] = {
{ OSSL_FUNC_RAND_NEWCTX, (void(*)(void))rng_newctx },
{ OSSL_FUNC_RAND_FREECTX, (void(*)(void))rng_freectx },
{ OSSL_FUNC_RAND_INSTANTIATE, (void(*)(void))rng_drbg_ctr_instantiate },
{ OSSL_FUNC_RAND_UNINSTANTIATE, (void(*)(void))rng_drbg_ctr_uninstantiate },
{ OSSL_FUNC_RAND_GENERATE, (void(*)(void))rng_non_fips_drbg_ctr_generate },
//{ OSSL_FUNC_RAND_RESEED, (void(*)(void))rng_drbg_ctr_reseed },
/*{ OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))ossl_drbg_enable_locking },
{ OSSL_FUNC_RAND_LOCK, (void(*)(void))ossl_drbg_lock },
{ OSSL_FUNC_RAND_UNLOCK, (void(*)(void))ossl_drbg_unlock },
{ OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, (void(*)(void))drbg_ctr_settable_ctx_params },
{ OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params },
{ OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, (void(*)(void))drbg_ctr_gettable_ctx_params },
{ OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params },*/
{ OSSL_FUNC_RAND_VERIFY_ZEROIZATION, (void(*)(void))rng_drbg_ctr_verify_zeroization },
/*{ OSSL_FUNC_RAND_GET_SEED, (void(*)(void))ossl_drbg_get_seed },
{ OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))rng_drbg_clear_seed },*/
{ 0, NULL }
};
/* The table of rands this provider offers */
static const OSSL_ALGORITHM rng_rands[] = {
{ "CTR-DRBG", RNG_FIPS_PROPERTIES, rng_fips_drbg_ctr_functions },
{ "CTR-DRBG", RNG_NON_FIPS_PROPERTIES, rng_non_fips_drbg_ctr_functions },
/*{ PROV_NAMES_HASH_DRBG, RNG_DEFAULT_PROPERTIES, ossl_drbg_hash_functions },
{ PROV_NAMES_HMAC_DRBG, RNG_DEFAULT_PROPERTIES, ossl_drbg_ossl_hmac_functions },
{ PROV_NAMES_TEST_RAND, RNG_UNAPPROVED_PROPERTIES, ossl_test_rng_functions },*/
{ NULL, NULL, NULL }
};
/* The function that returns the appropriate algorithm table per operation */
static const OSSL_ALGORITHM *rng_prov_operation(void *vprovctx,
int operation_id,
int *no_cache)
{
*no_cache = 0;
switch (operation_id) {
case OSSL_OP_RAND:
return rng_rands;
}
return NULL;
}
typedef void (*funcptr_t)(void);
/* The base dispatch table */
static const OSSL_DISPATCH provider_functions[] = {
{ OSSL_FUNC_PROVIDER_TEARDOWN, (funcptr_t)rng_prov_teardown },
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (funcptr_t)rng_prov_operation },
{ OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, (funcptr_t)rng_prov_get_reason_strings },
//{ OSSL_FUNC_PROVIDER_GET_PARAMS, (funcptr_t)vigenere_prov_get_params },
{ 0, NULL }
};
int OSSL_provider_init(const OSSL_CORE_HANDLE *core,
const OSSL_DISPATCH *in,
const OSSL_DISPATCH **out,
void **vprovctx)
{
if ((*vprovctx = provider_ctx_new(core, in)) == NULL)
return 0;
*out = provider_functions;
return 1;
}
I rewrite rng_provider_load() and don't use dlopen/dlsym.
int rng_provider_load(void)
{
...
rng_provider = OSSL_PROVIDER_load(NULL, "/lib/librng.so");
if (NULL == rng_provider) {
ERR_RND("Failed to load rng provider\n");
goto out;
}
...
}
Then I run the binary test_get_rnd_bytes and there's no SEGV caused core any more. But I got error "failed to fetch EVP_RAND" in get_rnd_bytes().
int get_rnd_bytes(u_char *buffer, int length)
{
EVP_RAND *rand = NULL;
EVP_RAND_CTX *ctx = NULL;
int ret = 0;
if (openssl_init_rng()) {
ERR_RND("openssl_init_rng failed\n");
goto end;
}
rand = EVP_RAND_fetch(NULL, "CTR-DRBG", "provider=rng,fips=no");
if (!rand) {
ERR_RND("failed to fetch EVP_RAND\n");
goto end;
}
...
Then I made the following change.
int rng_provider_load(void)
{
...
rng_provider = OSSL_PROVIDER_load(NULL, "/lib/rng.so");
Move rng.so to OpenSSL 3.1.4 installation directory /openssl-3.1.4/inst/lib64/ossl-modules but I still get the error "failed to fetch EVP_RAND".
You can use the environment variables OPENSSL_MODULES
to tell the OpenSSL library an alternative place to look for providers.
static const OSSL_ALGORITHM rng_rands[] = {
{ "CTR-DRBG", RNG_FIPS_PROPERTIES, rng_fips_drbg_ctr_functions },
{ "CTR-DRBG", RNG_NON_FIPS_PROPERTIES, rng_non_fips_drbg_ctr_functions },
...
Oh, two implementations with the same name in the same array? ........ Does OpenSSL support that? What happens if you try with the property query string "provider=rng,fips=yes"?
If it turns out that it works with "provider=rng,fips=yes", it's time to file an issue with OpenSSL
Calling ERR_print_errors_fp(stderr)
or similar after the failed fetch call might give some additional hints as to what the problem is.
OSSL_ALGORITHM
/*
Both algorithm_names and property_definition have comment "key". So I think their combination is the key.
You can use the environment variables
OPENSSL_MODULES
to tell the OpenSSL library an alternative place to look for providers.
In my scenario it's not feasible to use environment variables.
ERR_print_errors_fp
./test_get_rnd_bytes Case 1: length = 4
80B23E572D7F0000:error:030000C1:digital envelope routines:evp_rand_from_algorithm:invalid provider functions:crypto/evp/evp_rand.c:271:
This happens because something is missing in your OSSL_DISPATCH tables. I had a look at the code, and from what I can see, it requires OSSL_FUNC_RAND_GET_CTX_PARAMS to be present. Perhaps others too, i haven't checked very deeply.
80B23E572D7F0000:error:030000C1:digital envelope routines:evp_rand_from_algorithm:invalid provider functions:crypto/evp/evp_rand.c:271:
This happens because something is missing in your OSSL_DISPATCH tables. I had a look at the code, and from what I can see, it requires OSSL_FUNC_RAND_GET_CTX_PARAMS to be present. Perhaps others too, i haven't checked very deeply.
Thanks so much. Let me add more functions including OSSL_FUNC_RAND_GET_CTX_PARAMS.
After adding 3 new functions for OSSL_FUNC_RAND_ENABLE_LOCKING, OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS and OSSL_FUNC_RAND_GET_CTX_PARAMS. Now the binary works. Thanks so much for your help.
$ ./test_get_rnd_bytes Case 1: length = 4 test succeeded. random bytes are as follows: 15 b2 38 b4 Case 2: length = 16 test succeeded. random bytes are as follows: 92 d0 46 e2 78 ea 38 87 eb 48 b9 a2 68 67 61 90 Case 3: length = 32 test succeeded. random bytes are as follows: 46 4a 77 5f f3 da 25 24 95 c6 7b 81 66 f9 4a ec 1e 71 e5 f5 a c9 b8 5b 14 c0 dd a8 f0 b e9 34
$ openssl-3.1.4-quic1/inst/bin/openssl rand -provider-path . -provider rng -propquery "provider=rng,fips=no" 4|od -tx1 0000000 9e 3b 47 19 0000004 $ openssl-3.1.4-quic1/inst/bin/openssl rand -provider-path . -provider rng -propquery "provider=rng,fips=yes" 4|od -tx1 0000000 43 bc 52 57 0000004 $ openssl-3.1.4-quic1/inst/bin/openssl rand -provider-path . -provider rng 4|od -tx1 0000000 3c 61 43 65 0000004
Congrats!
I wrote a rand provider and compiled it into rng.so using fips_rands in fipsprov.c as an example. Then in librnd.so I load and link shared library rng.so using dlopen() and dlsym(). In the binary test_get_rnd_bytes I link librnd.so and run some test cases.
code in librnd.so.
The binary crashed. Any constructive suggestions are highly welcomed.