xref: /freebsd/crypto/openssl/apps/lib/app_provider.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "apps.h"
11 #include <ctype.h>
12 #include <string.h>
13 #include <openssl/err.h>
14 #include <openssl/provider.h>
15 #include <openssl/safestack.h>
16 
17 /* Non-zero if any of the provider options have been seen */
18 static int provider_option_given = 0;
19 
20 DEFINE_STACK_OF(OSSL_PROVIDER)
21 
22 /*
23  * See comments in opt_verify for explanation of this.
24  */
25 enum prov_range { OPT_PROV_ENUM };
26 
27 static STACK_OF(OSSL_PROVIDER) *app_providers = NULL;
28 
provider_free(OSSL_PROVIDER * prov)29 static void provider_free(OSSL_PROVIDER *prov)
30 {
31     OSSL_PROVIDER_unload(prov);
32 }
33 
app_provider_load(OSSL_LIB_CTX * libctx,const char * provider_name)34 int app_provider_load(OSSL_LIB_CTX *libctx, const char *provider_name)
35 {
36     OSSL_PROVIDER *prov;
37 
38     prov = OSSL_PROVIDER_load(libctx, provider_name);
39     if (prov == NULL) {
40         opt_printf_stderr("%s: unable to load provider %s\n"
41                           "Hint: use -provider-path option or OPENSSL_MODULES environment variable.\n",
42                           opt_getprog(), provider_name);
43         ERR_print_errors(bio_err);
44         return 0;
45     }
46     if (app_providers == NULL)
47         app_providers = sk_OSSL_PROVIDER_new_null();
48     if (app_providers == NULL
49         || !sk_OSSL_PROVIDER_push(app_providers, prov)) {
50         app_providers_cleanup();
51         return 0;
52     }
53     return 1;
54 }
55 
app_providers_cleanup(void)56 void app_providers_cleanup(void)
57 {
58     sk_OSSL_PROVIDER_pop_free(app_providers, provider_free);
59     app_providers = NULL;
60 }
61 
opt_provider_path(const char * path)62 static int opt_provider_path(const char *path)
63 {
64     if (path != NULL && *path == '\0')
65         path = NULL;
66     return OSSL_PROVIDER_set_default_search_path(app_get0_libctx(), path);
67 }
68 
69 struct prov_param_st {
70     char *name;
71     char *key;
72     char *val;
73     int found;
74 };
75 
set_prov_param(OSSL_PROVIDER * prov,void * vp)76 static int set_prov_param(OSSL_PROVIDER *prov, void *vp)
77 {
78     struct prov_param_st *p = (struct prov_param_st *)vp;
79 
80     if (p->name != NULL && strcmp(OSSL_PROVIDER_get0_name(prov), p->name) != 0)
81         return 1;
82     p->found = 1;
83     return OSSL_PROVIDER_add_conf_parameter(prov, p->key, p->val);
84 }
85 
opt_provider_param(const char * arg)86 static int opt_provider_param(const char *arg)
87 {
88     struct prov_param_st p;
89     char *copy, *tmp;
90     int ret = 0;
91 
92     if ((copy = OPENSSL_strdup(arg)) == NULL
93         || (p.val = strchr(copy, '=')) == NULL) {
94         opt_printf_stderr("%s: malformed '-provparam' option value: '%s'\n",
95                           opt_getprog(), arg);
96         goto end;
97     }
98 
99     /* Drop whitespace on both sides of the '=' sign */
100     *(tmp = p.val++) = '\0';
101     while (tmp > copy && isspace(_UC(*--tmp)))
102         *tmp = '\0';
103     while (isspace(_UC(*p.val)))
104         ++p.val;
105 
106     /*
107      * Split the key on ':', to get the optional provider, empty or missing
108      * means all.
109      */
110     if ((p.key = strchr(copy, ':')) != NULL) {
111         *p.key++ = '\0';
112         p.name = *copy != '\0' ? copy : NULL;
113     } else {
114         p.name = NULL;
115         p.key = copy;
116     }
117 
118     /* The key must not be empty */
119     if (*p.key == '\0') {
120         opt_printf_stderr("%s: malformed '-provparam' option value: '%s'\n",
121                           opt_getprog(), arg);
122         goto end;
123     }
124 
125     p.found = 0;
126     ret = OSSL_PROVIDER_do_all(app_get0_libctx(), set_prov_param, (void *)&p);
127     if (ret == 0) {
128         opt_printf_stderr("%s: Error setting provider '%s' parameter '%s'\n",
129                           opt_getprog(), p.name, p.key);
130     } else if (p.found == 0) {
131         opt_printf_stderr("%s: No provider named '%s' is loaded\n",
132                           opt_getprog(), p.name);
133         ret = 0;
134     }
135 
136  end:
137     OPENSSL_free(copy);
138     return ret;
139 }
140 
opt_provider(int opt)141 int opt_provider(int opt)
142 {
143     const int given = provider_option_given;
144 
145     provider_option_given = 1;
146     switch ((enum prov_range)opt) {
147     case OPT_PROV__FIRST:
148     case OPT_PROV__LAST:
149         return 1;
150     case OPT_PROV_PROVIDER:
151         return app_provider_load(app_get0_libctx(), opt_arg());
152     case OPT_PROV_PROVIDER_PATH:
153         return opt_provider_path(opt_arg());
154     case OPT_PROV_PARAM:
155         return opt_provider_param(opt_arg());
156     case OPT_PROV_PROPQUERY:
157         return app_set_propq(opt_arg());
158     }
159     /* Should never get here but if we do, undo what we did earlier */
160     provider_option_given = given;
161     return 0;
162 }
163 
opt_provider_option_given(void)164 int opt_provider_option_given(void)
165 {
166     return provider_option_given;
167 }
168