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"
9 static void fbsd_ossl_provider_unload(void);
10 static void print_dlerror(char *);
11 static OSSL_PROVIDER *legacy;
12 static OSSL_PROVIDER *deflt;
13 static int providers_loaded = 0;
14 static OSSL_PROVIDER * (*ossl_provider_load)(OSSL_LIB_CTX *, const char*) = NULL;
15 static int (*ossl_provider_unload)(OSSL_PROVIDER *) = NULL;
16 static void *crypto_lib_handle = NULL;
17 
18 static void
fbsd_ossl_provider_unload(void)19 fbsd_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 
34 static void
print_dlerror(char * message)35 print_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 
45 int
fbsd_ossl_provider_load(void)46 fbsd_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