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