| /* |
| * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * Licensed under the Apache License 2.0 (the "License"). You may not use |
| * this file except in compliance with the License. You can obtain a copy |
| * in the file LICENSE in the source distribution or at |
| * https://www.openssl.org/source/license.html |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.h> |
| |
| /* We need to use some STORE deprecated APIs */ |
| #define OPENSSL_SUPPRESS_DEPRECATED |
| |
| #include "internal/e_os.h" |
| |
| #include <openssl/crypto.h> |
| #include <openssl/err.h> |
| #include <openssl/trace.h> |
| #include <openssl/core_names.h> |
| #include <openssl/provider.h> |
| #include <openssl/param_build.h> |
| #include <openssl/store.h> |
| #include "internal/thread_once.h" |
| #include "internal/cryptlib.h" |
| #include "internal/provider.h" |
| #include "internal/bio.h" |
| #include "crypto/store.h" |
| #include "store_local.h" |
| |
| static int ossl_store_close_it(OSSL_STORE_CTX *ctx); |
| |
| static int loader_set_params(OSSL_STORE_LOADER *loader, |
| OSSL_STORE_LOADER_CTX *loader_ctx, |
| const OSSL_PARAM params[], const char *propq) |
| { |
| if (params != NULL) { |
| if (!loader->p_set_ctx_params(loader_ctx, params)) |
| return 0; |
| } |
| |
| if (propq != NULL) { |
| OSSL_PARAM propp[2]; |
| |
| if (OSSL_PARAM_locate_const(params, |
| OSSL_STORE_PARAM_PROPERTIES) != NULL) |
| /* use the propq from params */ |
| return 1; |
| |
| propp[0] = OSSL_PARAM_construct_utf8_string(OSSL_STORE_PARAM_PROPERTIES, |
| (char *)propq, 0); |
| propp[1] = OSSL_PARAM_construct_end(); |
| |
| if (!loader->p_set_ctx_params(loader_ctx, propp)) |
| return 0; |
| } |
| return 1; |
| } |
| |
| OSSL_STORE_CTX * |
| OSSL_STORE_open_ex(const char *uri, OSSL_LIB_CTX *libctx, const char *propq, |
| const UI_METHOD *ui_method, void *ui_data, |
| const OSSL_PARAM params[], |
| OSSL_STORE_post_process_info_fn post_process, |
| void *post_process_data) |
| { |
| const OSSL_STORE_LOADER *loader = NULL; |
| OSSL_STORE_LOADER *fetched_loader = NULL; |
| OSSL_STORE_LOADER_CTX *loader_ctx = NULL; |
| OSSL_STORE_CTX *ctx = NULL; |
| char *propq_copy = NULL; |
| int no_loader_found = 1; |
| char scheme_copy[256], *p, *schemes[2], *scheme = NULL; |
| size_t schemes_n = 0; |
| size_t i; |
| |
| /* |
| * Put the file scheme first. If the uri does represent an existing file, |
| * possible device name and all, then it should be loaded. Only a failed |
| * attempt at loading a local file should have us try something else. |
| */ |
| schemes[schemes_n++] = "file"; |
| |
| /* |
| * Now, check if we have something that looks like a scheme, and add it |
| * as a second scheme. However, also check if there's an authority start |
| * (://), because that will invalidate the previous file scheme. Also, |
| * check that this isn't actually the file scheme, as there's no point |
| * going through that one twice! |
| */ |
| OPENSSL_strlcpy(scheme_copy, uri, sizeof(scheme_copy)); |
| if ((p = strchr(scheme_copy, ':')) != NULL) { |
| *p++ = '\0'; |
| if (OPENSSL_strcasecmp(scheme_copy, "file") != 0) { |
| if (HAS_PREFIX(p, "//")) |
| schemes_n--; /* Invalidate the file scheme */ |
| schemes[schemes_n++] = scheme_copy; |
| } |
| } |
| |
| ERR_set_mark(); |
| |
| /* |
| * Try each scheme until we find one that could open the URI. |
| * |
| * For each scheme, we look for the engine implementation first, and |
| * failing that, we then try to fetch a provided implementation. |
| * This is consistent with how we handle legacy / engine implementations |
| * elsewhere. |
| */ |
| for (i = 0; loader_ctx == NULL && i < schemes_n; i++) { |
| scheme = schemes[i]; |
| OSSL_TRACE1(STORE, "Looking up scheme %s\n", scheme); |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| ERR_set_mark(); |
| if ((loader = ossl_store_get0_loader_int(scheme)) != NULL) { |
| ERR_clear_last_mark(); |
| no_loader_found = 0; |
| if (loader->open_ex != NULL) |
| loader_ctx = loader->open_ex(loader, uri, libctx, propq, |
| ui_method, ui_data); |
| else |
| loader_ctx = loader->open(loader, uri, ui_method, ui_data); |
| } else { |
| ERR_pop_to_mark(); |
| } |
| #endif |
| if (loader == NULL |
| && (fetched_loader = |
| OSSL_STORE_LOADER_fetch(libctx, scheme, propq)) != NULL) { |
| const OSSL_PROVIDER *provider = |
| OSSL_STORE_LOADER_get0_provider(fetched_loader); |
| void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider); |
| |
| no_loader_found = 0; |
| loader_ctx = fetched_loader->p_open(provctx, uri); |
| if (loader_ctx == NULL) { |
| OSSL_STORE_LOADER_free(fetched_loader); |
| fetched_loader = NULL; |
| } else if (!loader_set_params(fetched_loader, loader_ctx, |
| params, propq)) { |
| (void)fetched_loader->p_close(loader_ctx); |
| OSSL_STORE_LOADER_free(fetched_loader); |
| fetched_loader = NULL; |
| } |
| loader = fetched_loader; |
| } |
| } |
| |
| if (no_loader_found) |
| /* |
| * It's assumed that ossl_store_get0_loader_int() and |
| * OSSL_STORE_LOADER_fetch() report their own errors |
| */ |
| goto err; |
| |
| OSSL_TRACE1(STORE, "Found loader for scheme %s\n", scheme); |
| |
| if (loader_ctx == NULL) |
| /* |
| * It's assumed that the loader's open() method reports its own |
| * errors |
| */ |
| goto err; |
| |
| OSSL_TRACE2(STORE, "Opened %s => %p\n", uri, (void *)loader_ctx); |
| |
| if ((propq != NULL && (propq_copy = OPENSSL_strdup(propq)) == NULL) |
| || (ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| |
| if (ui_method != NULL |
| && (!ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data) |
| || !ossl_pw_enable_passphrase_caching(&ctx->pwdata))) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB); |
| goto err; |
| } |
| ctx->properties = propq_copy; |
| ctx->fetched_loader = fetched_loader; |
| ctx->loader = loader; |
| ctx->loader_ctx = loader_ctx; |
| ctx->post_process = post_process; |
| ctx->post_process_data = post_process_data; |
| |
| /* |
| * If the attempt to open with the 'file' scheme loader failed and the |
| * other scheme loader succeeded, the failure to open with the 'file' |
| * scheme loader leaves an error on the error stack. Let's remove it. |
| */ |
| ERR_pop_to_mark(); |
| |
| return ctx; |
| |
| err: |
| ERR_clear_last_mark(); |
| if (loader_ctx != NULL) { |
| /* |
| * Temporary structure so OSSL_STORE_close() can work even when |
| * |ctx| couldn't be allocated properly |
| */ |
| OSSL_STORE_CTX tmpctx = { NULL, }; |
| |
| tmpctx.fetched_loader = fetched_loader; |
| tmpctx.loader = loader; |
| tmpctx.loader_ctx = loader_ctx; |
| |
| /* |
| * We ignore a returned error because we will return NULL anyway in |
| * this case, so if something goes wrong when closing, that'll simply |
| * just add another entry on the error stack. |
| */ |
| (void)ossl_store_close_it(&tmpctx); |
| } |
| OSSL_STORE_LOADER_free(fetched_loader); |
| OPENSSL_free(propq_copy); |
| OPENSSL_free(ctx); |
| return NULL; |
| } |
| |
| OSSL_STORE_CTX *OSSL_STORE_open(const char *uri, |
| const UI_METHOD *ui_method, void *ui_data, |
| OSSL_STORE_post_process_info_fn post_process, |
| void *post_process_data) |
| { |
| return OSSL_STORE_open_ex(uri, NULL, NULL, ui_method, ui_data, NULL, |
| post_process, post_process_data); |
| } |
| |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| int OSSL_STORE_ctrl(OSSL_STORE_CTX *ctx, int cmd, ...) |
| { |
| va_list args; |
| int ret; |
| |
| va_start(args, cmd); |
| ret = OSSL_STORE_vctrl(ctx, cmd, args); |
| va_end(args); |
| |
| return ret; |
| } |
| |
| int OSSL_STORE_vctrl(OSSL_STORE_CTX *ctx, int cmd, va_list args) |
| { |
| if (ctx->fetched_loader != NULL) { |
| if (ctx->fetched_loader->p_set_ctx_params != NULL) { |
| OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; |
| |
| switch (cmd) { |
| case OSSL_STORE_C_USE_SECMEM: |
| { |
| int on = *(va_arg(args, int *)); |
| |
| params[0] = OSSL_PARAM_construct_int("use_secmem", &on); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx, |
| params); |
| } |
| } else if (ctx->loader->ctrl != NULL) { |
| return ctx->loader->ctrl(ctx->loader_ctx, cmd, args); |
| } |
| |
| /* |
| * If the fetched loader doesn't have a set_ctx_params or a ctrl, it's as |
| * if there was one that ignored our params, which usually returns 1. |
| */ |
| return 1; |
| } |
| #endif |
| |
| int OSSL_STORE_expect(OSSL_STORE_CTX *ctx, int expected_type) |
| { |
| int ret = 1; |
| |
| if (ctx == NULL |
| || expected_type < 0 || expected_type > OSSL_STORE_INFO_CRL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT); |
| return 0; |
| } |
| if (ctx->loading) { |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED); |
| return 0; |
| } |
| |
| ctx->expected_type = expected_type; |
| if (ctx->fetched_loader != NULL |
| && ctx->fetched_loader->p_set_ctx_params != NULL) { |
| OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; |
| |
| params[0] = |
| OSSL_PARAM_construct_int(OSSL_STORE_PARAM_EXPECT, &expected_type); |
| ret = ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx, params); |
| } |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL |
| && ctx->loader->expect != NULL) { |
| ret = ctx->loader->expect(ctx->loader_ctx, expected_type); |
| } |
| #endif |
| return ret; |
| } |
| |
| int OSSL_STORE_find(OSSL_STORE_CTX *ctx, const OSSL_STORE_SEARCH *search) |
| { |
| int ret = 1; |
| |
| if (ctx->loading) { |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED); |
| return 0; |
| } |
| if (search == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); |
| return 0; |
| } |
| |
| if (ctx->fetched_loader != NULL) { |
| OSSL_PARAM_BLD *bld; |
| OSSL_PARAM *params; |
| /* OSSL_STORE_SEARCH_BY_NAME, OSSL_STORE_SEARCH_BY_ISSUER_SERIAL*/ |
| void *name_der = NULL; |
| int name_der_sz; |
| /* OSSL_STORE_SEARCH_BY_ISSUER_SERIAL */ |
| BIGNUM *number = NULL; |
| |
| if (ctx->fetched_loader->p_set_ctx_params == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION); |
| return 0; |
| } |
| |
| if ((bld = OSSL_PARAM_BLD_new()) == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return 0; |
| } |
| |
| ret = 0; /* Assume the worst */ |
| |
| switch (search->search_type) { |
| case OSSL_STORE_SEARCH_BY_NAME: |
| if ((name_der_sz = i2d_X509_NAME(search->name, |
| (unsigned char **)&name_der)) > 0 |
| && OSSL_PARAM_BLD_push_octet_string(bld, |
| OSSL_STORE_PARAM_SUBJECT, |
| name_der, name_der_sz)) |
| ret = 1; |
| break; |
| case OSSL_STORE_SEARCH_BY_ISSUER_SERIAL: |
| if ((name_der_sz = i2d_X509_NAME(search->name, |
| (unsigned char **)&name_der)) > 0 |
| && (number = ASN1_INTEGER_to_BN(search->serial, NULL)) != NULL |
| && OSSL_PARAM_BLD_push_octet_string(bld, |
| OSSL_STORE_PARAM_ISSUER, |
| name_der, name_der_sz) |
| && OSSL_PARAM_BLD_push_BN(bld, OSSL_STORE_PARAM_SERIAL, |
| number)) |
| ret = 1; |
| break; |
| case OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT: |
| if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_STORE_PARAM_DIGEST, |
| EVP_MD_get0_name(search->digest), |
| 0) |
| && OSSL_PARAM_BLD_push_octet_string(bld, |
| OSSL_STORE_PARAM_FINGERPRINT, |
| search->string, |
| search->stringlength)) |
| ret = 1; |
| break; |
| case OSSL_STORE_SEARCH_BY_ALIAS: |
| if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_STORE_PARAM_ALIAS, |
| (char *)search->string, |
| search->stringlength)) |
| ret = 1; |
| break; |
| } |
| if (ret) { |
| params = OSSL_PARAM_BLD_to_param(bld); |
| ret = ctx->fetched_loader->p_set_ctx_params(ctx->loader_ctx, |
| params); |
| OSSL_PARAM_free(params); |
| } |
| OSSL_PARAM_BLD_free(bld); |
| OPENSSL_free(name_der); |
| BN_free(number); |
| } else { |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| /* legacy loader section */ |
| if (ctx->loader->find == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION); |
| return 0; |
| } |
| ret = ctx->loader->find(ctx->loader_ctx, search); |
| #endif |
| } |
| |
| return ret; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_load(OSSL_STORE_CTX *ctx) |
| { |
| OSSL_STORE_INFO *v = NULL; |
| |
| ctx->loading = 1; |
| again: |
| if (OSSL_STORE_eof(ctx)) |
| return NULL; |
| |
| if (ctx->loader != NULL) |
| OSSL_TRACE(STORE, "Loading next object\n"); |
| |
| if (ctx->cached_info != NULL |
| && sk_OSSL_STORE_INFO_num(ctx->cached_info) == 0) { |
| sk_OSSL_STORE_INFO_free(ctx->cached_info); |
| ctx->cached_info = NULL; |
| } |
| |
| if (ctx->cached_info != NULL) { |
| v = sk_OSSL_STORE_INFO_shift(ctx->cached_info); |
| } else { |
| if (ctx->fetched_loader != NULL) { |
| struct ossl_load_result_data_st load_data; |
| |
| load_data.v = NULL; |
| load_data.ctx = ctx; |
| |
| if (!ctx->fetched_loader->p_load(ctx->loader_ctx, |
| ossl_store_handle_load_result, |
| &load_data, |
| ossl_pw_passphrase_callback_dec, |
| &ctx->pwdata)) { |
| if (!OSSL_STORE_eof(ctx)) |
| ctx->error_flag = 1; |
| return NULL; |
| } |
| v = load_data.v; |
| } |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL) |
| v = ctx->loader->load(ctx->loader_ctx, |
| ctx->pwdata._.ui_method.ui_method, |
| ctx->pwdata._.ui_method.ui_method_data); |
| #endif |
| } |
| |
| if (ctx->post_process != NULL && v != NULL) { |
| v = ctx->post_process(v, ctx->post_process_data); |
| |
| /* |
| * By returning NULL, the callback decides that this object should |
| * be ignored. |
| */ |
| if (v == NULL) |
| goto again; |
| } |
| |
| /* Clear any internally cached passphrase */ |
| (void)ossl_pw_clear_passphrase_cache(&ctx->pwdata); |
| |
| if (v != NULL && ctx->expected_type != 0) { |
| int returned_type = OSSL_STORE_INFO_get_type(v); |
| |
| if (returned_type != OSSL_STORE_INFO_NAME && returned_type != 0) { |
| if (ctx->expected_type != returned_type) { |
| OSSL_STORE_INFO_free(v); |
| goto again; |
| } |
| } |
| } |
| |
| if (v != NULL) |
| OSSL_TRACE1(STORE, "Got a %s\n", |
| OSSL_STORE_INFO_type_string(OSSL_STORE_INFO_get_type(v))); |
| |
| return v; |
| } |
| |
| int OSSL_STORE_error(OSSL_STORE_CTX *ctx) |
| { |
| int ret = 1; |
| |
| if (ctx->fetched_loader != NULL) |
| ret = ctx->error_flag; |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL) |
| ret = ctx->loader->error(ctx->loader_ctx); |
| #endif |
| return ret; |
| } |
| |
| int OSSL_STORE_eof(OSSL_STORE_CTX *ctx) |
| { |
| int ret = 1; |
| |
| if (ctx->fetched_loader != NULL) |
| ret = ctx->loader->p_eof(ctx->loader_ctx); |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL) |
| ret = ctx->loader->eof(ctx->loader_ctx); |
| #endif |
| return ret != 0; |
| } |
| |
| static int ossl_store_close_it(OSSL_STORE_CTX *ctx) |
| { |
| int ret = 0; |
| |
| if (ctx == NULL) |
| return 1; |
| OSSL_TRACE1(STORE, "Closing %p\n", (void *)ctx->loader_ctx); |
| |
| if (ctx->fetched_loader != NULL) |
| ret = ctx->loader->p_close(ctx->loader_ctx); |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL) |
| ret = ctx->loader->closefn(ctx->loader_ctx); |
| #endif |
| |
| sk_OSSL_STORE_INFO_pop_free(ctx->cached_info, OSSL_STORE_INFO_free); |
| OSSL_STORE_LOADER_free(ctx->fetched_loader); |
| OPENSSL_free(ctx->properties); |
| ossl_pw_clear_passphrase_data(&ctx->pwdata); |
| return ret; |
| } |
| |
| int OSSL_STORE_close(OSSL_STORE_CTX *ctx) |
| { |
| int ret = ossl_store_close_it(ctx); |
| |
| OPENSSL_free(ctx); |
| return ret; |
| } |
| |
| /* |
| * Functions to generate OSSL_STORE_INFOs, one function for each type we |
| * support having in them as well as a generic constructor. |
| * |
| * In all cases, ownership of the object is transferred to the OSSL_STORE_INFO |
| * and will therefore be freed when the OSSL_STORE_INFO is freed. |
| */ |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new(int type, void *data) |
| { |
| OSSL_STORE_INFO *info = OPENSSL_zalloc(sizeof(*info)); |
| |
| if (info == NULL) |
| return NULL; |
| |
| info->type = type; |
| info->_.data = data; |
| return info; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_NAME(char *name) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_NAME, NULL); |
| |
| if (info == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| info->_.name.name = name; |
| info->_.name.desc = NULL; |
| |
| return info; |
| } |
| |
| int OSSL_STORE_INFO_set0_NAME_description(OSSL_STORE_INFO *info, char *desc) |
| { |
| if (info->type != OSSL_STORE_INFO_NAME) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT); |
| return 0; |
| } |
| |
| info->_.name.desc = desc; |
| |
| return 1; |
| } |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_PARAMS(EVP_PKEY *params) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PARAMS, params); |
| |
| if (info == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return info; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_PUBKEY(EVP_PKEY *pkey) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PUBKEY, pkey); |
| |
| if (info == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return info; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_PKEY(EVP_PKEY *pkey) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_PKEY, pkey); |
| |
| if (info == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return info; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_CERT(X509 *x509) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_CERT, x509); |
| |
| if (info == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return info; |
| } |
| |
| OSSL_STORE_INFO *OSSL_STORE_INFO_new_CRL(X509_CRL *crl) |
| { |
| OSSL_STORE_INFO *info = OSSL_STORE_INFO_new(OSSL_STORE_INFO_CRL, crl); |
| |
| if (info == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return info; |
| } |
| |
| /* |
| * Functions to try to extract data from a OSSL_STORE_INFO. |
| */ |
| int OSSL_STORE_INFO_get_type(const OSSL_STORE_INFO *info) |
| { |
| return info->type; |
| } |
| |
| void *OSSL_STORE_INFO_get0_data(int type, const OSSL_STORE_INFO *info) |
| { |
| if (info->type == type) |
| return info->_.data; |
| return NULL; |
| } |
| |
| const char *OSSL_STORE_INFO_get0_NAME(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_NAME) |
| return info->_.name.name; |
| return NULL; |
| } |
| |
| char *OSSL_STORE_INFO_get1_NAME(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_NAME) { |
| char *ret = OPENSSL_strdup(info->_.name.name); |
| |
| if (ret == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return ret; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME); |
| return NULL; |
| } |
| |
| const char *OSSL_STORE_INFO_get0_NAME_description(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_NAME) |
| return info->_.name.desc; |
| return NULL; |
| } |
| |
| char *OSSL_STORE_INFO_get1_NAME_description(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_NAME) { |
| char *ret = OPENSSL_strdup(info->_.name.desc |
| ? info->_.name.desc : ""); |
| |
| if (ret == NULL) |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return ret; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME); |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get0_PARAMS(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PARAMS) |
| return info->_.params; |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get1_PARAMS(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PARAMS) { |
| EVP_PKEY_up_ref(info->_.params); |
| return info->_.params; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_PARAMETERS); |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get0_PUBKEY(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PUBKEY) |
| return info->_.pubkey; |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get1_PUBKEY(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PUBKEY) { |
| EVP_PKEY_up_ref(info->_.pubkey); |
| return info->_.pubkey; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PUBLIC_KEY); |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get0_PKEY(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PKEY) |
| return info->_.pkey; |
| return NULL; |
| } |
| |
| EVP_PKEY *OSSL_STORE_INFO_get1_PKEY(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_PKEY) { |
| EVP_PKEY_up_ref(info->_.pkey); |
| return info->_.pkey; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PRIVATE_KEY); |
| return NULL; |
| } |
| |
| X509 *OSSL_STORE_INFO_get0_CERT(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_CERT) |
| return info->_.x509; |
| return NULL; |
| } |
| |
| X509 *OSSL_STORE_INFO_get1_CERT(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_CERT) { |
| X509_up_ref(info->_.x509); |
| return info->_.x509; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CERTIFICATE); |
| return NULL; |
| } |
| |
| X509_CRL *OSSL_STORE_INFO_get0_CRL(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_CRL) |
| return info->_.crl; |
| return NULL; |
| } |
| |
| X509_CRL *OSSL_STORE_INFO_get1_CRL(const OSSL_STORE_INFO *info) |
| { |
| if (info->type == OSSL_STORE_INFO_CRL) { |
| X509_CRL_up_ref(info->_.crl); |
| return info->_.crl; |
| } |
| ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CRL); |
| return NULL; |
| } |
| |
| /* |
| * Free the OSSL_STORE_INFO |
| */ |
| void OSSL_STORE_INFO_free(OSSL_STORE_INFO *info) |
| { |
| if (info != NULL) { |
| switch (info->type) { |
| case OSSL_STORE_INFO_NAME: |
| OPENSSL_free(info->_.name.name); |
| OPENSSL_free(info->_.name.desc); |
| break; |
| case OSSL_STORE_INFO_PARAMS: |
| EVP_PKEY_free(info->_.params); |
| break; |
| case OSSL_STORE_INFO_PUBKEY: |
| EVP_PKEY_free(info->_.pubkey); |
| break; |
| case OSSL_STORE_INFO_PKEY: |
| EVP_PKEY_free(info->_.pkey); |
| break; |
| case OSSL_STORE_INFO_CERT: |
| X509_free(info->_.x509); |
| break; |
| case OSSL_STORE_INFO_CRL: |
| X509_CRL_free(info->_.crl); |
| break; |
| } |
| OPENSSL_free(info); |
| } |
| } |
| |
| int OSSL_STORE_supports_search(OSSL_STORE_CTX *ctx, int search_type) |
| { |
| int ret = 0; |
| |
| if (ctx->fetched_loader != NULL) { |
| void *provctx = |
| ossl_provider_ctx(OSSL_STORE_LOADER_get0_provider(ctx->fetched_loader)); |
| const OSSL_PARAM *params; |
| const OSSL_PARAM *p_subject = NULL; |
| const OSSL_PARAM *p_issuer = NULL; |
| const OSSL_PARAM *p_serial = NULL; |
| const OSSL_PARAM *p_fingerprint = NULL; |
| const OSSL_PARAM *p_alias = NULL; |
| |
| if (ctx->fetched_loader->p_settable_ctx_params == NULL) |
| return 0; |
| |
| params = ctx->fetched_loader->p_settable_ctx_params(provctx); |
| p_subject = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT); |
| p_issuer = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ISSUER); |
| p_serial = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SERIAL); |
| p_fingerprint = |
| OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_FINGERPRINT); |
| p_alias = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ALIAS); |
| |
| switch (search_type) { |
| case OSSL_STORE_SEARCH_BY_NAME: |
| ret = (p_subject != NULL); |
| break; |
| case OSSL_STORE_SEARCH_BY_ISSUER_SERIAL: |
| ret = (p_issuer != NULL && p_serial != NULL); |
| break; |
| case OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT: |
| ret = (p_fingerprint != NULL); |
| break; |
| case OSSL_STORE_SEARCH_BY_ALIAS: |
| ret = (p_alias != NULL); |
| break; |
| } |
| } |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if (ctx->fetched_loader == NULL) { |
| OSSL_STORE_SEARCH tmp_search; |
| |
| if (ctx->loader->find == NULL) |
| return 0; |
| tmp_search.search_type = search_type; |
| ret = ctx->loader->find(NULL, &tmp_search); |
| } |
| #endif |
| return ret; |
| } |
| |
| /* Search term constructors */ |
| OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_name(X509_NAME *name) |
| { |
| OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search)); |
| |
| if (search == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| search->search_type = OSSL_STORE_SEARCH_BY_NAME; |
| search->name = name; |
| return search; |
| } |
| |
| OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_issuer_serial(X509_NAME *name, |
| const ASN1_INTEGER *serial) |
| { |
| OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search)); |
| |
| if (search == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| search->search_type = OSSL_STORE_SEARCH_BY_ISSUER_SERIAL; |
| search->name = name; |
| search->serial = serial; |
| return search; |
| } |
| |
| OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_key_fingerprint(const EVP_MD *digest, |
| const unsigned char |
| *bytes, size_t len) |
| { |
| OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search)); |
| |
| if (search == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| if (digest != NULL && len != (size_t)EVP_MD_get_size(digest)) { |
| ERR_raise_data(ERR_LIB_OSSL_STORE, |
| OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST, |
| "%s size is %d, fingerprint size is %zu", |
| EVP_MD_get0_name(digest), EVP_MD_get_size(digest), len); |
| OPENSSL_free(search); |
| return NULL; |
| } |
| |
| search->search_type = OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT; |
| search->digest = digest; |
| search->string = bytes; |
| search->stringlength = len; |
| return search; |
| } |
| |
| OSSL_STORE_SEARCH *OSSL_STORE_SEARCH_by_alias(const char *alias) |
| { |
| OSSL_STORE_SEARCH *search = OPENSSL_zalloc(sizeof(*search)); |
| |
| if (search == NULL) { |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| search->search_type = OSSL_STORE_SEARCH_BY_ALIAS; |
| search->string = (const unsigned char *)alias; |
| search->stringlength = strlen(alias); |
| return search; |
| } |
| |
| /* Search term destructor */ |
| void OSSL_STORE_SEARCH_free(OSSL_STORE_SEARCH *search) |
| { |
| OPENSSL_free(search); |
| } |
| |
| /* Search term accessors */ |
| int OSSL_STORE_SEARCH_get_type(const OSSL_STORE_SEARCH *criterion) |
| { |
| return criterion->search_type; |
| } |
| |
| X509_NAME *OSSL_STORE_SEARCH_get0_name(const OSSL_STORE_SEARCH *criterion) |
| { |
| return criterion->name; |
| } |
| |
| const ASN1_INTEGER *OSSL_STORE_SEARCH_get0_serial(const OSSL_STORE_SEARCH |
| *criterion) |
| { |
| return criterion->serial; |
| } |
| |
| const unsigned char *OSSL_STORE_SEARCH_get0_bytes(const OSSL_STORE_SEARCH |
| *criterion, size_t *length) |
| { |
| *length = criterion->stringlength; |
| return criterion->string; |
| } |
| |
| const char *OSSL_STORE_SEARCH_get0_string(const OSSL_STORE_SEARCH *criterion) |
| { |
| return (const char *)criterion->string; |
| } |
| |
| const EVP_MD *OSSL_STORE_SEARCH_get0_digest(const OSSL_STORE_SEARCH *criterion) |
| { |
| return criterion->digest; |
| } |
| |
| OSSL_STORE_CTX *OSSL_STORE_attach(BIO *bp, const char *scheme, |
| OSSL_LIB_CTX *libctx, const char *propq, |
| const UI_METHOD *ui_method, void *ui_data, |
| const OSSL_PARAM params[], |
| OSSL_STORE_post_process_info_fn post_process, |
| void *post_process_data) |
| { |
| const OSSL_STORE_LOADER *loader = NULL; |
| OSSL_STORE_LOADER *fetched_loader = NULL; |
| OSSL_STORE_LOADER_CTX *loader_ctx = NULL; |
| OSSL_STORE_CTX *ctx = NULL; |
| |
| if (scheme == NULL) |
| scheme = "file"; |
| |
| OSSL_TRACE1(STORE, "Looking up scheme %s\n", scheme); |
| ERR_set_mark(); |
| #ifndef OPENSSL_NO_DEPRECATED_3_0 |
| if ((loader = ossl_store_get0_loader_int(scheme)) != NULL) |
| loader_ctx = loader->attach(loader, bp, libctx, propq, |
| ui_method, ui_data); |
| #endif |
| if (loader == NULL |
| && (fetched_loader = |
| OSSL_STORE_LOADER_fetch(libctx, scheme, propq)) != NULL) { |
| const OSSL_PROVIDER *provider = |
| OSSL_STORE_LOADER_get0_provider(fetched_loader); |
| void *provctx = OSSL_PROVIDER_get0_provider_ctx(provider); |
| OSSL_CORE_BIO *cbio = ossl_core_bio_new_from_bio(bp); |
| |
| if (cbio == NULL |
| || (loader_ctx = fetched_loader->p_attach(provctx, cbio)) == NULL) { |
| OSSL_STORE_LOADER_free(fetched_loader); |
| fetched_loader = NULL; |
| } else if (!loader_set_params(fetched_loader, loader_ctx, |
| params, propq)) { |
| (void)fetched_loader->p_close(loader_ctx); |
| OSSL_STORE_LOADER_free(fetched_loader); |
| fetched_loader = NULL; |
| } |
| loader = fetched_loader; |
| ossl_core_bio_free(cbio); |
| } |
| |
| if (loader_ctx == NULL) { |
| ERR_clear_last_mark(); |
| return NULL; |
| } |
| |
| if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { |
| ERR_clear_last_mark(); |
| ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| if (ui_method != NULL |
| && !ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data)) { |
| ERR_clear_last_mark(); |
| OPENSSL_free(ctx); |
| return NULL; |
| } |
| |
| ctx->fetched_loader = fetched_loader; |
| ctx->loader = loader; |
| ctx->loader_ctx = loader_ctx; |
| ctx->post_process = post_process; |
| ctx->post_process_data = post_process_data; |
| |
| /* |
| * ossl_store_get0_loader_int will raise an error if the loader for the |
| * the scheme cannot be retrieved. But if a loader was successfully |
| * fetched then we remove this error from the error stack. |
| */ |
| ERR_pop_to_mark(); |
| |
| return ctx; |
| } |