1#include <dlfcn.h>
2#include <errno.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <openssl/provider.h>
6
7#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
8#define CRYPTO_LIBRARY "/lib/libcrypto.so.30"
9static void fbsd_ossl_provider_unload(void);
10static void print_dlerror(char *);
11static OSSL_PROVIDER *legacy;
12static OSSL_PROVIDER *deflt;
13static int providers_loaded = 0;
14static OSSL_PROVIDER * (*ossl_provider_load)(OSSL_LIB_CTX *, const char*) = NULL;
15static int (*ossl_provider_unload)(OSSL_PROVIDER *) = NULL;
16static void *crypto_lib_handle = NULL;
17
18static void
19fbsd_ossl_provider_unload(void)
20{
21	if (ossl_provider_unload == NULL) {
22		if (!(ossl_provider_unload = (int (*)(OSSL_PROVIDER*)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_unload"))) {
23			print_dlerror("Unable to link OSSL_PROVIDER_unload");
24			return;
25		}
26	}
27	if (providers_loaded == 1) {
28		(*ossl_provider_unload)(legacy);
29		(*ossl_provider_unload)(deflt);
30		providers_loaded = 0;
31	}
32}
33
34static void
35print_dlerror(char *message)
36{
37	char *errstr;
38
39	if ((errstr = dlerror()) != NULL)
40		fprintf(stderr, "%s: %s\n",
41			message, errstr);
42}
43#endif
44
45int
46fbsd_ossl_provider_load(void)
47{
48#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
49	if (crypto_lib_handle == NULL) {
50		if (!(crypto_lib_handle = dlopen(CRYPTO_LIBRARY,
51		    RTLD_LAZY|RTLD_GLOBAL))) {
52			print_dlerror("Unable to load libcrypto.so");
53			return (EINVAL);
54		}
55	}
56	if (ossl_provider_load == NULL) {
57		if (!(ossl_provider_load = (OSSL_PROVIDER * (*)(OSSL_LIB_CTX*, const char *)) dlsym(crypto_lib_handle, "OSSL_PROVIDER_load"))) {
58			print_dlerror("Unable to link OSSL_PROVIDER_load");
59			return(ENOENT);
60		}
61	}
62
63	if (providers_loaded == 0) {
64		if ((legacy = (*ossl_provider_load)(NULL, "legacy")) == NULL)
65			return (EINVAL);
66		if ((deflt = (*ossl_provider_load)(NULL, "default")) == NULL) {
67			(*ossl_provider_unload)(legacy);
68			return (EINVAL);
69		}
70		if (atexit(fbsd_ossl_provider_unload)) {
71			fbsd_ossl_provider_unload();
72			return (errno);
73		}
74		providers_loaded = 1;
75	}
76#endif
77	return (0);
78}
79