1 /* 2 * Copyright 2019-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 /* 11 * This is a very simple provider that does absolutely nothing except respond 12 * to provider global parameter requests. It does this by simply echoing back 13 * a parameter request it makes to the loading library. 14 */ 15 16 #include <string.h> 17 #include <stdio.h> 18 19 #include <stdarg.h> 20 21 /* 22 * When built as an object file to link the application with, we get the 23 * init function name through the macro PROVIDER_INIT_FUNCTION_NAME. If 24 * not defined, we use the standard init function name for the shared 25 * object form. 26 */ 27 #ifdef PROVIDER_INIT_FUNCTION_NAME 28 # define OSSL_provider_init PROVIDER_INIT_FUNCTION_NAME 29 #endif 30 31 #include "e_os.h" 32 #include <openssl/core.h> 33 #include <openssl/core_dispatch.h> 34 #include <openssl/err.h> 35 #include <openssl/evp.h> 36 #include <openssl/crypto.h> 37 #include <openssl/provider.h> 38 39 typedef struct p_test_ctx { 40 char *thisfile; 41 char *thisfunc; 42 const OSSL_CORE_HANDLE *handle; 43 OSSL_LIB_CTX *libctx; 44 } P_TEST_CTX; 45 46 static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; 47 static OSSL_FUNC_core_get_params_fn *c_get_params = NULL; 48 static OSSL_FUNC_core_new_error_fn *c_new_error; 49 static OSSL_FUNC_core_set_error_debug_fn *c_set_error_debug; 50 static OSSL_FUNC_core_vset_error_fn *c_vset_error; 51 static OSSL_FUNC_BIO_vsnprintf_fn *c_BIO_vsnprintf; 52 53 /* Tell the core what params we provide and what type they are */ 54 static const OSSL_PARAM p_param_types[] = { 55 { "greeting", OSSL_PARAM_UTF8_STRING, NULL, 0, 0 }, 56 { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0}, 57 { NULL, 0, NULL, 0, 0 } 58 }; 59 60 /* This is a trick to ensure we define the provider functions correctly */ 61 static OSSL_FUNC_provider_gettable_params_fn p_gettable_params; 62 static OSSL_FUNC_provider_get_params_fn p_get_params; 63 static OSSL_FUNC_provider_get_reason_strings_fn p_get_reason_strings; 64 static OSSL_FUNC_provider_teardown_fn p_teardown; 65 66 static int local_snprintf(char *buf, size_t n, const char *format, ...) 67 { 68 va_list args; 69 int ret; 70 71 va_start(args, format); 72 ret = (*c_BIO_vsnprintf)(buf, n, format, args); 73 va_end(args); 74 return ret; 75 } 76 77 static void p_set_error(int lib, int reason, const char *file, int line, 78 const char *func, const char *fmt, ...) 79 { 80 va_list ap; 81 82 va_start(ap, fmt); 83 c_new_error(NULL); 84 c_set_error_debug(NULL, file, line, func); 85 c_vset_error(NULL, ERR_PACK(lib, 0, reason), fmt, ap); 86 va_end(ap); 87 } 88 89 static const OSSL_PARAM *p_gettable_params(void *_) 90 { 91 return p_param_types; 92 } 93 94 static int p_get_params(void *provctx, OSSL_PARAM params[]) 95 { 96 P_TEST_CTX *ctx = (P_TEST_CTX *)provctx; 97 const OSSL_CORE_HANDLE *hand = ctx->handle; 98 OSSL_PARAM *p = params; 99 int ok = 1; 100 101 for (; ok && p->key != NULL; p++) { 102 if (strcmp(p->key, "greeting") == 0) { 103 static char *opensslv; 104 static char *provname; 105 static char *greeting; 106 static OSSL_PARAM counter_request[] = { 107 /* Known libcrypto provided parameters */ 108 { "openssl-version", OSSL_PARAM_UTF8_PTR, 109 &opensslv, sizeof(&opensslv), 0 }, 110 { "provider-name", OSSL_PARAM_UTF8_PTR, 111 &provname, sizeof(&provname), 0}, 112 113 /* This might be present, if there's such a configuration */ 114 { "greeting", OSSL_PARAM_UTF8_PTR, 115 &greeting, sizeof(&greeting), 0 }, 116 117 { NULL, 0, NULL, 0, 0 } 118 }; 119 char buf[256]; 120 size_t buf_l; 121 122 opensslv = provname = greeting = NULL; 123 124 if (c_get_params(hand, counter_request)) { 125 if (greeting) { 126 strcpy(buf, greeting); 127 } else { 128 const char *versionp = *(void **)counter_request[0].data; 129 const char *namep = *(void **)counter_request[1].data; 130 131 local_snprintf(buf, sizeof(buf), "Hello OpenSSL %.20s, greetings from %s!", 132 versionp, namep); 133 } 134 } else { 135 local_snprintf(buf, sizeof(buf), "Howdy stranger..."); 136 } 137 138 p->return_size = buf_l = strlen(buf) + 1; 139 if (p->data_size >= buf_l) 140 strcpy(p->data, buf); 141 else 142 ok = 0; 143 } else if (strcmp(p->key, "digest-check") == 0) { 144 unsigned int digestsuccess = 0; 145 146 /* 147 * Test we can use an algorithm from another provider. We're using 148 * legacy to check that legacy is actually available and we haven't 149 * just fallen back to default. 150 */ 151 #ifdef PROVIDER_INIT_FUNCTION_NAME 152 EVP_MD *md4 = EVP_MD_fetch(ctx->libctx, "MD4", NULL); 153 EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); 154 const char *msg = "Hello world"; 155 unsigned char out[16]; 156 OSSL_PROVIDER *deflt; 157 158 /* 159 * "default" has not been loaded into the parent libctx. We should be able 160 * to explicitly load it as a non-child provider. 161 */ 162 deflt = OSSL_PROVIDER_load(ctx->libctx, "default"); 163 if (deflt == NULL 164 || !OSSL_PROVIDER_available(ctx->libctx, "default")) { 165 /* We set error "3" for a failure to load the default provider */ 166 p_set_error(ERR_LIB_PROV, 3, ctx->thisfile, OPENSSL_LINE, 167 ctx->thisfunc, NULL); 168 ok = 0; 169 } 170 171 /* 172 * We should have the default provider available that we loaded 173 * ourselves, and the base and legacy providers which we inherit 174 * from the parent libctx. We should also have "this" provider 175 * available. 176 */ 177 if (ok 178 && OSSL_PROVIDER_available(ctx->libctx, "default") 179 && OSSL_PROVIDER_available(ctx->libctx, "base") 180 && OSSL_PROVIDER_available(ctx->libctx, "legacy") 181 && OSSL_PROVIDER_available(ctx->libctx, "p_test") 182 && md4 != NULL 183 && mdctx != NULL) { 184 if (EVP_DigestInit_ex(mdctx, md4, NULL) 185 && EVP_DigestUpdate(mdctx, (const unsigned char *)msg, 186 strlen(msg)) 187 && EVP_DigestFinal(mdctx, out, NULL)) 188 digestsuccess = 1; 189 } 190 EVP_MD_CTX_free(mdctx); 191 EVP_MD_free(md4); 192 OSSL_PROVIDER_unload(deflt); 193 #endif 194 if (p->data_size >= sizeof(digestsuccess)) { 195 *(unsigned int *)p->data = digestsuccess; 196 p->return_size = sizeof(digestsuccess); 197 } else { 198 ok = 0; 199 } 200 } else if (strcmp(p->key, "stop-property-mirror") == 0) { 201 /* 202 * Setting the default properties explicitly should stop mirroring 203 * of properties from the parent libctx. 204 */ 205 unsigned int stopsuccess = 0; 206 207 #ifdef PROVIDER_INIT_FUNCTION_NAME 208 stopsuccess = EVP_set_default_properties(ctx->libctx, NULL); 209 #endif 210 if (p->data_size >= sizeof(stopsuccess)) { 211 *(unsigned int *)p->data = stopsuccess; 212 p->return_size = sizeof(stopsuccess); 213 } else { 214 ok = 0; 215 } 216 } 217 } 218 return ok; 219 } 220 221 static const OSSL_ITEM *p_get_reason_strings(void *_) 222 { 223 static const OSSL_ITEM reason_strings[] = { 224 {1, "dummy reason string"}, 225 {2, "Can't create child library context"}, 226 {3, "Can't load default provider"}, 227 {0, NULL} 228 }; 229 230 return reason_strings; 231 } 232 233 static const OSSL_ALGORITHM *p_query(OSSL_PROVIDER *prov, 234 int operation_id, 235 int *no_cache) 236 { 237 *no_cache = 1; 238 return NULL; 239 } 240 241 static const OSSL_DISPATCH p_test_table[] = { 242 { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))p_gettable_params }, 243 { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))p_get_params }, 244 { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, 245 (void (*)(void))p_get_reason_strings}, 246 { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p_teardown }, 247 { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))p_query }, 248 { 0, NULL } 249 }; 250 251 int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, 252 const OSSL_DISPATCH *oin, 253 const OSSL_DISPATCH **out, 254 void **provctx) 255 { 256 P_TEST_CTX *ctx; 257 const OSSL_DISPATCH *in = oin; 258 259 for (; in->function_id != 0; in++) { 260 switch (in->function_id) { 261 case OSSL_FUNC_CORE_GETTABLE_PARAMS: 262 c_gettable_params = OSSL_FUNC_core_gettable_params(in); 263 break; 264 case OSSL_FUNC_CORE_GET_PARAMS: 265 c_get_params = OSSL_FUNC_core_get_params(in); 266 break; 267 case OSSL_FUNC_CORE_NEW_ERROR: 268 c_new_error = OSSL_FUNC_core_new_error(in); 269 break; 270 case OSSL_FUNC_CORE_SET_ERROR_DEBUG: 271 c_set_error_debug = OSSL_FUNC_core_set_error_debug(in); 272 break; 273 case OSSL_FUNC_CORE_VSET_ERROR: 274 c_vset_error = OSSL_FUNC_core_vset_error(in); 275 break; 276 case OSSL_FUNC_BIO_VSNPRINTF: 277 c_BIO_vsnprintf = OSSL_FUNC_BIO_vsnprintf(in); 278 break; 279 default: 280 /* Just ignore anything we don't understand */ 281 break; 282 } 283 } 284 285 /* 286 * We want to test that libcrypto doesn't use the file and func pointers 287 * that we provide to it via c_set_error_debug beyond the time that they 288 * are valid for. Therefore we dynamically allocate these strings now and 289 * free them again when the provider is torn down. If anything tries to 290 * use those strings after that point there will be a use-after-free and 291 * asan will complain (and hence the tests will fail). 292 * This file isn't linked against libcrypto, so we use malloc and strdup 293 * instead of OPENSSL_malloc and OPENSSL_strdup 294 */ 295 ctx = malloc(sizeof(*ctx)); 296 if (ctx == NULL) 297 return 0; 298 ctx->thisfile = strdup(OPENSSL_FILE); 299 ctx->thisfunc = strdup(OPENSSL_FUNC); 300 ctx->handle = handle; 301 #ifdef PROVIDER_INIT_FUNCTION_NAME 302 /* We only do this if we are linked with libcrypto */ 303 ctx->libctx = OSSL_LIB_CTX_new_child(handle, oin); 304 if (ctx->libctx == NULL) { 305 /* We set error "2" for a failure to create the child libctx*/ 306 p_set_error(ERR_LIB_PROV, 2, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc, 307 NULL); 308 p_teardown(ctx); 309 return 0; 310 } 311 /* 312 * The default provider is loaded - but the default properties should not 313 * allow its use. 314 */ 315 { 316 EVP_MD *sha256 = EVP_MD_fetch(ctx->libctx, "SHA2-256", NULL); 317 if (sha256 != NULL) { 318 EVP_MD_free(sha256); 319 p_teardown(ctx); 320 return 0; 321 } 322 } 323 #endif 324 325 /* 326 * Set a spurious error to check error handling works correctly. This will 327 * be ignored 328 */ 329 p_set_error(ERR_LIB_PROV, 1, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc, NULL); 330 331 *provctx = (void *)ctx; 332 *out = p_test_table; 333 return 1; 334 } 335 336 static void p_teardown(void *provctx) 337 { 338 P_TEST_CTX *ctx = (P_TEST_CTX *)provctx; 339 340 #ifdef PROVIDER_INIT_FUNCTION_NAME 341 OSSL_LIB_CTX_free(ctx->libctx); 342 #endif 343 free(ctx->thisfile); 344 free(ctx->thisfunc); 345 free(ctx); 346 } 347