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