diff options
author | Hugo Landau <hlandau@openssl.org> | 2022-04-08 13:20:44 +0100 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2022-09-14 14:10:18 +0100 |
commit | 606e0426a148034c8c131de9f31f7d3e38be99ea (patch) | |
tree | 2d91031e79f6b5bb2f83076924e4f1de54655d7e /providers | |
parent | 021859bf810a3614758c2f4871b9cd7202fac9b2 (diff) |
Add support for loading root CAs from Windows crypto API
Fixes #18020.
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18070)
Diffstat (limited to 'providers')
-rw-r--r-- | providers/implementations/include/prov/implementations.h | 1 | ||||
-rw-r--r-- | providers/implementations/storemgmt/build.info | 3 | ||||
-rw-r--r-- | providers/implementations/storemgmt/winstore_store.c | 327 | ||||
-rw-r--r-- | providers/stores.inc | 3 |
4 files changed, 334 insertions, 0 deletions
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 288808bb6f..a6ac602d41 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -526,3 +526,4 @@ extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_function extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[]; extern const OSSL_DISPATCH ossl_file_store_functions[]; +extern const OSSL_DISPATCH ossl_winstore_store_functions[]; diff --git a/providers/implementations/storemgmt/build.info b/providers/implementations/storemgmt/build.info index 8e6445a4e7..d0b1174926 100644 --- a/providers/implementations/storemgmt/build.info +++ b/providers/implementations/storemgmt/build.info @@ -4,3 +4,6 @@ $STORE_GOAL=../../libdefault.a SOURCE[$STORE_GOAL]=file_store.c file_store_any2obj.c +IF[{- !$disabled{winstore} -}] + SOURCE[$STORE_GOAL]=winstore_store.c +ENDIF diff --git a/providers/implementations/storemgmt/winstore_store.c b/providers/implementations/storemgmt/winstore_store.c new file mode 100644 index 0000000000..f686517f74 --- /dev/null +++ b/providers/implementations/storemgmt/winstore_store.c @@ -0,0 +1,327 @@ +/* + * Copyright 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 <openssl/store.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/core_object.h> +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/params.h> +#include <openssl/decoder.h> +#include <openssl/proverr.h> +#include <openssl/store.h> /* The OSSL_STORE_INFO type numbers */ +#include "internal/cryptlib.h" +#include "internal/o_dir.h" +#include "crypto/decoder.h" +#include "crypto/ctype.h" /* ossl_isdigit() */ +#include "prov/implementations.h" +#include "prov/bio.h" +#include "file_store_local.h" + +#include <wincrypt.h> + +enum { + STATE_IDLE, + STATE_READ, + STATE_EOF, +}; + +struct winstore_ctx_st { + void *provctx; + char *propq; + unsigned char *subject; + size_t subject_len; + + HCERTSTORE win_store; + const CERT_CONTEXT *win_ctx; + int state; + + OSSL_DECODER_CTX *dctx; +}; + +static void winstore_win_reset(struct winstore_ctx_st *ctx) +{ + if (ctx->win_ctx != NULL) { + CertFreeCertificateContext(ctx->win_ctx); + ctx->win_ctx = NULL; + } + + ctx->state = STATE_IDLE; +} + +static void winstore_win_advance(struct winstore_ctx_st *ctx) +{ + CERT_NAME_BLOB name = {0}; + + if (ctx->state == STATE_EOF) + return; + + name.cbData = ctx->subject_len; + name.pbData = ctx->subject; + + ctx->win_ctx = (name.cbData == 0 ? NULL : + CertFindCertificateInStore(ctx->win_store, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_NAME, + &name, ctx->win_ctx)); + + ctx->state = (ctx->win_ctx == NULL) ? STATE_EOF : STATE_READ; +} + +static void *winstore_open(void *provctx, const char *uri) +{ + struct winstore_ctx_st *ctx = NULL; + + if (!HAS_CASE_PREFIX(uri, "org.openssl.winstore:")) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->provctx = provctx; + ctx->win_store = CertOpenSystemStoreW(0, L"ROOT"); + if (ctx->win_store == NULL) { + OPENSSL_free(ctx); + return NULL; + } + + winstore_win_reset(ctx); + return ctx; +} + +static void *winstore_attach(void *provctx, OSSL_CORE_BIO *cin) +{ + return NULL; /* not supported */ +} + +static const OSSL_PARAM *winstore_settable_ctx_params(void *loaderctx, const OSSL_PARAM params[]) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int winstore_set_ctx_params(void *loaderctx, const OSSL_PARAM params[]) +{ + struct winstore_ctx_st *ctx = loaderctx; + const OSSL_PARAM *p; + int do_reset = 0; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES); + if (p != NULL) { + do_reset = 1; + OPENSSL_free(ctx->propq); + ctx->propq = NULL; + if (!OSSL_PARAM_get_utf8_string(p, &ctx->propq, 0)) + return 0; + } + + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT); + if (p != NULL) { + const unsigned char *der = NULL; + size_t der_len = 0; + + if (!OSSL_PARAM_get_octet_string_ptr(p, (const void **)&der, &der_len)) + return 0; + + do_reset = 1; + + OPENSSL_free(ctx->subject); + + ctx->subject = OPENSSL_malloc(der_len); + if (ctx->subject == NULL) { + ctx->subject_len = 0; + return 0; + } + + ctx->subject_len = der_len; + memcpy(ctx->subject, der, der_len); + } + + if (do_reset) { + winstore_win_reset(ctx); + winstore_win_advance(ctx); + } + + return 1; +} + +struct load_data_st { + OSSL_CALLBACK *object_cb; + void *object_cbarg; +}; + +static int load_construct(OSSL_DECODER_INSTANCE *decoder_inst, + const OSSL_PARAM *params, void *construct_data) +{ + struct load_data_st *data = construct_data; + return data->object_cb(params, data->object_cbarg); +} + +static void load_cleanup(void *construct_data) +{ + /* No-op. */ +} + +static int setup_decoder(struct winstore_ctx_st *ctx) +{ + OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(ctx->provctx); + const OSSL_ALGORITHM *to_algo = NULL; + + if (ctx->dctx != NULL) + return 1; + + ctx->dctx = OSSL_DECODER_CTX_new(); + if (ctx->dctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!OSSL_DECODER_CTX_set_input_type(ctx->dctx, "DER")) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + if (!OSSL_DECODER_CTX_set_input_structure(ctx->dctx, "Certificate")) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + for (to_algo = ossl_any_to_obj_algorithm; + to_algo->algorithm_names != NULL; + to_algo++) { + OSSL_DECODER *to_obj = NULL; + OSSL_DECODER_INSTANCE *to_obj_inst = NULL; + + /* + * Create the internal last resort decoder implementation + * together with a "decoder instance". + * The decoder doesn't need any identification or to be + * attached to any provider, since it's only used locally. + */ + to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL); + if (to_obj != NULL) + to_obj_inst = ossl_decoder_instance_new(to_obj, ctx->provctx); + + OSSL_DECODER_free(to_obj); + if (to_obj_inst == NULL) + goto err; + + if (!ossl_decoder_ctx_add_decoder_inst(ctx->dctx, + to_obj_inst)) { + ossl_decoder_instance_free(to_obj_inst); + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + } + + if (!OSSL_DECODER_CTX_add_extra(ctx->dctx, libctx, ctx->propq)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + if (!OSSL_DECODER_CTX_set_construct(ctx->dctx, load_construct)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + if (!OSSL_DECODER_CTX_set_cleanup(ctx->dctx, load_cleanup)) { + ERR_raise(ERR_LIB_PROV, ERR_R_OSSL_DECODER_LIB); + goto err; + } + + return 1; + +err: + OSSL_DECODER_CTX_free(ctx->dctx); + ctx->dctx = NULL; + return 0; +} + +static int winstore_load_using(struct winstore_ctx_st *ctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, + const void *der, size_t der_len) +{ + struct load_data_st data; + const unsigned char *der_ = der; + size_t der_len_ = der_len; + + if (setup_decoder(ctx) == 0) + return 0; + + data.object_cb = object_cb; + data.object_cbarg = object_cbarg; + + OSSL_DECODER_CTX_set_construct_data(ctx->dctx, &data); + OSSL_DECODER_CTX_set_passphrase_cb(ctx->dctx, pw_cb, pw_cbarg); + + if (OSSL_DECODER_from_data(ctx->dctx, &der_, &der_len_) == 0) + return 0; + + return 1; +} + +static int winstore_load(void *loaderctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + int ret = 0; + struct winstore_ctx_st *ctx = loaderctx; + + if (ctx->state != STATE_READ) + return 0; + + ret = winstore_load_using(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg, + ctx->win_ctx->pbCertEncoded, + ctx->win_ctx->cbCertEncoded); + + if (ret == 1) + winstore_win_advance(ctx); + + return ret; +} + +static int winstore_eof(void *loaderctx) +{ + struct winstore_ctx_st *ctx = loaderctx; + + return ctx->state != STATE_READ; +} + +static int winstore_close(void *loaderctx) +{ + struct winstore_ctx_st *ctx = loaderctx; + + winstore_win_reset(ctx); + CertCloseStore(ctx->win_store, 0); + OSSL_DECODER_CTX_free(ctx->dctx); + OPENSSL_free(ctx->propq); + OPENSSL_free(ctx->subject); + OPENSSL_free(ctx); + return 1; +} + +const OSSL_DISPATCH ossl_winstore_store_functions[] = { + { OSSL_FUNC_STORE_OPEN, (void (*)(void))winstore_open }, + { OSSL_FUNC_STORE_ATTACH, (void (*)(void))winstore_attach }, + { OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS, (void (*)(void))winstore_settable_ctx_params }, + { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void (*)(void))winstore_set_ctx_params }, + { OSSL_FUNC_STORE_LOAD, (void (*)(void))winstore_load }, + { OSSL_FUNC_STORE_EOF, (void (*)(void))winstore_eof }, + { OSSL_FUNC_STORE_CLOSE, (void (*)(void))winstore_close }, + { 0, NULL }, +}; diff --git a/providers/stores.inc b/providers/stores.inc index 4c1ec8f287..526532759e 100644 --- a/providers/stores.inc +++ b/providers/stores.inc @@ -12,3 +12,6 @@ #endif STORE("file", "yes", ossl_file_store_functions) +#ifndef OPENSSL_NO_WINSTORE +STORE("org.openssl.winstore", "yes", ossl_winstore_store_functions) +#endif |