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