1476d63e0SCy Schubert #include <dlfcn.h>
2476d63e0SCy Schubert #include <errno.h>
3476d63e0SCy Schubert #include <stdio.h>
4476d63e0SCy Schubert #include <stdlib.h>
5476d63e0SCy Schubert #include <openssl/provider.h>
6476d63e0SCy Schubert 
7476d63e0SCy Schubert #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
80990136eSCy Schubert #define CRYPTO_LIBRARY "/lib/libcrypto.so.30"
9476d63e0SCy Schubert static void fbsd_ossl_provider_unload(void);
10476d63e0SCy Schubert static void print_dlerror(char *);
11476d63e0SCy Schubert static OSSL_PROVIDER *legacy;
12476d63e0SCy Schubert static OSSL_PROVIDER *deflt;
13476d63e0SCy Schubert static int providers_loaded = 0;
14476d63e0SCy Schubert static OSSL_PROVIDER * (*ossl_provider_load)(OSSL_LIB_CTX *, const char*) = NULL;
15476d63e0SCy Schubert static int (*ossl_provider_unload)(OSSL_PROVIDER *) = NULL;
16476d63e0SCy Schubert static void *crypto_lib_handle = NULL;
17476d63e0SCy Schubert 
18476d63e0SCy Schubert static void
fbsd_ossl_provider_unload(void)19476d63e0SCy Schubert fbsd_ossl_provider_unload(void)
20476d63e0SCy Schubert {
21476d63e0SCy Schubert 	if (ossl_provider_unload == NULL) {
22476d63e0SCy Schubert 		if (!(ossl_provider_unload = (int (*)(OSSL_PROVIDER*)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_unload"))) {
23476d63e0SCy Schubert 			print_dlerror("Unable to link OSSL_PROVIDER_unload");
24476d63e0SCy Schubert 			return;
25476d63e0SCy Schubert 		}
26476d63e0SCy Schubert 	}
27476d63e0SCy Schubert 	if (providers_loaded == 1) {
28476d63e0SCy Schubert 		(*ossl_provider_unload)(legacy);
29476d63e0SCy Schubert 		(*ossl_provider_unload)(deflt);
30476d63e0SCy Schubert 		providers_loaded = 0;
31476d63e0SCy Schubert 	}
32476d63e0SCy Schubert }
33476d63e0SCy Schubert 
34476d63e0SCy Schubert static void
print_dlerror(char * message)35476d63e0SCy Schubert print_dlerror(char *message)
36476d63e0SCy Schubert {
37476d63e0SCy Schubert 	char *errstr;
38476d63e0SCy Schubert 
39476d63e0SCy Schubert 	if ((errstr = dlerror()) != NULL)
40476d63e0SCy Schubert 		fprintf(stderr, "%s: %s\n",
41476d63e0SCy Schubert 			message, errstr);
42476d63e0SCy Schubert }
43476d63e0SCy Schubert #endif
44476d63e0SCy Schubert 
45476d63e0SCy Schubert int
fbsd_ossl_provider_load(void)46476d63e0SCy Schubert fbsd_ossl_provider_load(void)
47476d63e0SCy Schubert {
48476d63e0SCy Schubert #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
49476d63e0SCy Schubert 	if (crypto_lib_handle == NULL) {
500990136eSCy Schubert 		if (!(crypto_lib_handle = dlopen(CRYPTO_LIBRARY,
51476d63e0SCy Schubert 		    RTLD_LAZY|RTLD_GLOBAL))) {
52476d63e0SCy Schubert 			print_dlerror("Unable to load libcrypto.so");
53476d63e0SCy Schubert 			return (EINVAL);
54476d63e0SCy Schubert 		}
55476d63e0SCy Schubert 	}
56476d63e0SCy Schubert 	if (ossl_provider_load == NULL) {
57476d63e0SCy Schubert 		if (!(ossl_provider_load = (OSSL_PROVIDER * (*)(OSSL_LIB_CTX*, const char *)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_load"))) {
58476d63e0SCy Schubert 			print_dlerror("Unable to link OSSL_PROVIDER_load");
59476d63e0SCy Schubert 			return(ENOENT);
60476d63e0SCy Schubert 		}
61476d63e0SCy Schubert 	}
62476d63e0SCy Schubert 
63476d63e0SCy Schubert 	if (providers_loaded == 0) {
64476d63e0SCy Schubert 		if ((legacy = (*ossl_provider_load)(NULL, "legacy")) == NULL)
65476d63e0SCy Schubert 			return (EINVAL);
66476d63e0SCy Schubert 		if ((deflt = (*ossl_provider_load)(NULL, "default")) == NULL) {
67476d63e0SCy Schubert 			(*ossl_provider_unload)(legacy);
68476d63e0SCy Schubert 			return (EINVAL);
69476d63e0SCy Schubert 		}
70476d63e0SCy Schubert 		if (atexit(fbsd_ossl_provider_unload)) {
71476d63e0SCy Schubert 			fbsd_ossl_provider_unload();
72476d63e0SCy Schubert 			return (errno);
73476d63e0SCy Schubert 		}
74476d63e0SCy Schubert 		providers_loaded = 1;
75476d63e0SCy Schubert 	}
76476d63e0SCy Schubert #endif
77476d63e0SCy Schubert 	return (0);
78476d63e0SCy Schubert }
79