From: Shane Lontis Date: Fri, 20 Mar 2020 10:25:39 +0000 (+1000) Subject: Add support for passing the libctx to the config loader X-Git-Tag: openssl-3.0.0-alpha1~234 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=22e27978b29b2cdc1db79659ed653d6cf31834ab;p=oweals%2Fopenssl.git Add support for passing the libctx to the config loader The self tests for the fips module are triggered on startup and they need to know the core's libctx in order to function correctly. As the provider can be autoloaded via configuration it then needs to propagate the callers libctx down to the provider via the config load. Note that OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, ..) is still called, but will only load the default configuration if the OPENSSL_CONF environment variable is set. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/11240) --- diff --git a/crypto/conf/conf_lib.c b/crypto/conf/conf_lib.c index 833b7a6551..c06718d249 100644 --- a/crypto/conf/conf_lib.c +++ b/crypto/conf/conf_lib.c @@ -174,7 +174,7 @@ int CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out) * the "CONF classic" functions, for consistency. */ -CONF *NCONF_new(CONF_METHOD *meth) +CONF *NCONF_new_with_libctx(OPENSSL_CTX *libctx, CONF_METHOD *meth) { CONF *ret; @@ -183,13 +183,19 @@ CONF *NCONF_new(CONF_METHOD *meth) ret = meth->create(meth); if (ret == NULL) { - CONFerr(CONF_F_NCONF_NEW, ERR_R_MALLOC_FAILURE); + CONFerr(0, ERR_R_MALLOC_FAILURE); return NULL; } + ret->libctx = libctx; return ret; } +CONF *NCONF_new(CONF_METHOD *meth) +{ + return NCONF_new_with_libctx(NULL, meth); +} + void NCONF_free(CONF *conf) { if (conf == NULL) diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index 86924c1bff..2bbf43b908 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2020 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 @@ -13,8 +13,10 @@ #include #include "internal/conf.h" #include "internal/dso.h" +#include "internal/thread_once.h" #include #include +#include #define DSO_mod_init_name "OPENSSL_init" #define DSO_mod_finish_name "OPENSSL_finish" @@ -55,6 +57,8 @@ struct conf_imodule_st { static STACK_OF(CONF_MODULE) *supported_modules = NULL; static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; +static CRYPTO_ONCE load_builtin_modules = CRYPTO_ONCE_STATIC_INIT; + static void module_free(CONF_MODULE *md); static void module_finish(CONF_IMODULE *imod); static int module_run(const CONF *cnf, const char *name, const char *value, @@ -113,22 +117,25 @@ int CONF_modules_load(const CONF *cnf, const char *appname, } -int CONF_modules_load_file(const char *filename, const char *appname, - unsigned long flags) +int CONF_modules_load_file_with_libctx(OPENSSL_CTX *libctx, + const char *filename, + const char *appname, unsigned long flags) { char *file = NULL; CONF *conf = NULL; int ret = 0; - conf = NCONF_new(NULL); + + conf = NCONF_new_with_libctx(libctx, NULL); if (conf == NULL) goto err; if (filename == NULL) { file = CONF_get1_default_config_file(); - if (!file) + if (file == NULL) goto err; - } else + } else { file = (char *)filename; + } if (NCONF_load(conf, file, NULL) <= 0) { if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) && @@ -152,12 +159,32 @@ int CONF_modules_load_file(const char *filename, const char *appname, return ret; } +int CONF_modules_load_file(const char *filename, + const char *appname, unsigned long flags) +{ + return CONF_modules_load_file_with_libctx(NULL, filename, appname, flags); +} + +DEFINE_RUN_ONCE_STATIC(do_load_builtin_modules) +{ + OPENSSL_load_builtin_modules(); +#ifndef OPENSSL_NO_ENGINE + /* Need to load ENGINEs */ + ENGINE_load_builtin_engines(); +#endif + ERR_clear_error(); + return 1; +} + static int module_run(const CONF *cnf, const char *name, const char *value, unsigned long flags) { CONF_MODULE *md; int ret; + if (!RUN_ONCE(&load_builtin_modules, do_load_builtin_modules)) + return -1; + md = module_find(name); /* Module not found: try to load DSO */ diff --git a/crypto/conf/conf_sap.c b/crypto/conf/conf_sap.c index 2c5ee2a131..f628896222 100644 --- a/crypto/conf/conf_sap.c +++ b/crypto/conf/conf_sap.c @@ -59,12 +59,6 @@ int openssl_config_int(const OPENSSL_INIT_SETTINGS *settings) filename, appname, flags); #endif - OPENSSL_load_builtin_modules(); -#ifndef OPENSSL_NO_ENGINE - /* Need to load ENGINEs */ - ENGINE_load_builtin_engines(); -#endif - ERR_clear_error(); #ifndef OPENSSL_SYS_UEFI ret = CONF_modules_load_file(filename, appname, flags); #endif diff --git a/crypto/context.c b/crypto/context.c index 02fecf9f35..dcf960bfa7 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -8,6 +8,7 @@ */ #include "crypto/cryptlib.h" +#include #include "internal/thread_once.h" #include "internal/property.h" @@ -145,6 +146,13 @@ OPENSSL_CTX *OPENSSL_CTX_new(void) return ctx; } +#ifndef FIPS_MODE +int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file) +{ + return CONF_modules_load_file_with_libctx(ctx, config_file, NULL, 0) > 0; +} +#endif + void OPENSSL_CTX_free(OPENSSL_CTX *ctx) { if (ctx != NULL) diff --git a/crypto/provider_conf.c b/crypto/provider_conf.c index 9b7a1fff7c..3bf974e974 100644 --- a/crypto/provider_conf.c +++ b/crypto/provider_conf.c @@ -164,7 +164,7 @@ static int provider_conf_init(CONF_IMODULE *md, const CONF *cnf) for (i = 0; i < sk_CONF_VALUE_num(elist); i++) { cval = sk_CONF_VALUE_value(elist, i); - if (!provider_conf_load(NULL, cval->name, cval->value, cnf)) + if (!provider_conf_load(cnf->libctx, cval->name, cval->value, cnf)) return 0; } diff --git a/doc/man3/CONF_modules_free.pod b/doc/man3/CONF_modules_free.pod index 592189d600..1174bfec51 100644 --- a/doc/man3/CONF_modules_free.pod +++ b/doc/man3/CONF_modules_free.pod @@ -39,7 +39,7 @@ None of the functions return a value. =head1 SEE ALSO L, L, -L +L =head1 HISTORY diff --git a/doc/man3/CONF_modules_load_file.pod b/doc/man3/CONF_modules_load_file.pod index c0623eb721..ba2c8b68b5 100644 --- a/doc/man3/CONF_modules_load_file.pod +++ b/doc/man3/CONF_modules_load_file.pod @@ -2,12 +2,16 @@ =head1 NAME -CONF_modules_load_file, CONF_modules_load - OpenSSL configuration functions +CONF_modules_load_file_with_libctx, CONF_modules_load_file, CONF_modules_load +- OpenSSL configuration functions =head1 SYNOPSIS #include + int CONF_modules_load_file_with_libctx(OPENSSL_CTX *libctx, + const char *filename, + const char *appname, unsigned long flags); int CONF_modules_load_file(const char *filename, const char *appname, unsigned long flags); int CONF_modules_load(const CONF *cnf, const char *appname, @@ -15,12 +19,16 @@ CONF_modules_load_file, CONF_modules_load - OpenSSL configuration functions =head1 DESCRIPTION -The function CONF_modules_load_file() configures OpenSSL using file -B and application name B. If B is NULL -the standard OpenSSL configuration file is used. If B is -NULL the standard OpenSSL application name B is used. +The function CONF_modules_load_file_with_libctx() configures OpenSSL using +library context B file B and application name B. +If B is NULL the standard OpenSSL configuration file is used. +If B is NULL the standard OpenSSL application name B is +used. The behaviour can be customized using B. +CONF_modules_load_file() is the same as CONF_modules_load_file_with_libctx() but +has a NULL library context. + CONF_modules_load() is identical to CONF_modules_load_file() except it reads configuration information from B. @@ -40,8 +48,8 @@ returns success. This is used by default in L to ignore any errors in the default system-wide configuration file, as having all OpenSSL applications fail to start when there are potentially minor issues in the file is too risky. -Applications calling B explicitly should not generally -set this flag. +Applications calling B explicitly should not +generally set this flag. If B is set configuration module loading from DSOs is disabled. @@ -53,10 +61,10 @@ return an error. B if set and B is not NULL will use the default section pointed to by B if B does not exist. -By using CONF_modules_load_file() with appropriate flags an application can -customise application configuration to best suit its needs. In some cases the -use of a configuration file is optional and its absence is not an error: in -this case B would be set. +By using CONF_modules_load_file_with_libctx() with appropriate flags an +application can customise application configuration to best suit its needs. +In some cases the use of a configuration file is optional and its absence is not +an error: in this case B would be set. Errors during configuration may also be handled differently by different applications. For example in some cases an error may simply print out a warning @@ -78,7 +86,7 @@ return value of the failing module (this will always be zero or negative). Load a configuration file and print out any errors and exit (missing file considered fatal): - if (CONF_modules_load_file(NULL, NULL, 0) <= 0) { + if (CONF_modules_load_file_with_libctx(libctx, NULL, NULL, 0) <= 0) { fprintf(stderr, "FATAL: error loading configuration file\n"); ERR_print_errors_fp(stderr); exit(1); @@ -87,8 +95,8 @@ considered fatal): Load default configuration file using the section indicated by "myapp", tolerate missing files, but exit on other errors: - if (CONF_modules_load_file(NULL, "myapp", - CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) { + if (CONF_modules_load_file_with_libctx(NULL, NULL, "myapp", + CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) { fprintf(stderr, "FATAL: error loading configuration file\n"); ERR_print_errors_fp(stderr); exit(1); @@ -97,8 +105,8 @@ tolerate missing files, but exit on other errors: Load custom configuration file and section, only print warnings on error, missing configuration file ignored: - if (CONF_modules_load_file("/something/app.cnf", "myapp", - CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) { + if (CONF_modules_load_file_with_libctx(NULL, "/something/app.cnf", "myapp", + CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) { fprintf(stderr, "WARNING: error loading configuration file\n"); ERR_print_errors_fp(stderr); } @@ -114,7 +122,7 @@ Load and parse configuration file manually, custom error handling: fprintf(stderr, "Error opening configuration file\n"); /* Other missing configuration file behaviour */ } else { - cnf = NCONF_new(NULL); + cnf = NCONF_new_with_libctx(libctx, NULL); if (NCONF_load_fp(cnf, fp, &eline) == 0) { fprintf(stderr, "Error on line %ld of configuration file\n", eline); ERR_print_errors_fp(stderr); @@ -130,11 +138,13 @@ Load and parse configuration file manually, custom error handling: =head1 SEE ALSO -L, L +L, +L, +L =head1 COPYRIGHT -Copyright 2004-2017 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2004-2020 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 diff --git a/doc/man3/NCONF_new_with_libctx.pod b/doc/man3/NCONF_new_with_libctx.pod new file mode 100644 index 0000000000..b976d7f74c --- /dev/null +++ b/doc/man3/NCONF_new_with_libctx.pod @@ -0,0 +1,59 @@ +=pod + +=head1 NAME + +NCONF_new_with_libctx, NCONF_new, NCONF_free, NCONF_default, NCONF_load +- functionality to Load and parse configuration files manually + +=head1 SYNOPSIS + + #include + + CONF *NCONF_new_with_libctx(OPENSSL_CTX *libctx, CONF_METHOD *meth); + CONF *NCONF_new(CONF_METHOD *meth); + void NCONF_free(CONF *conf); + CONF_METHOD *NCONF_default(void); + int NCONF_load(CONF *conf, const char *file, long *eline); + +=head1 DESCRIPTION + +NCONF_new_with_libctx() creates a new CONF object in heap memory and assigns to +it a context I that can be used during loading. If the method table +I is set to NULL then the default value of NCONF_default() is used. + +NCONF_new() is similar to NCONF_new_with_libctx() but sets the I to NULL. + +NCONF_free() frees the data associated with I and then frees the I +object. + +NCONF_load() parses the file named I and adds the values found to +I. If an error occurs I and I list the file and line that +the load failed on if they are not NULL. + +NCONF_default() gets the default method table for processing a configuration file. + +=head1 RETURN VALUES + +NCONF_load() returns 1 on success or 0 on error. + +NCONF_new_with_libctx() and NCONF_new() return a newly created I object +or NULL if an error occurs. + +=head1 SEE ALSO + +L, + +=head1 HISTORY + +NCONF_new_with_libctx() was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2020 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 +L. + +=cut diff --git a/doc/man3/OPENSSL_CTX.pod b/doc/man3/OPENSSL_CTX.pod index d574a374d6..3301250756 100644 --- a/doc/man3/OPENSSL_CTX.pod +++ b/doc/man3/OPENSSL_CTX.pod @@ -2,7 +2,8 @@ =head1 NAME -OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free - OpenSSL library context +OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free, OPENSSL_CTX_load_config +- OpenSSL library context =head1 SYNOPSIS @@ -11,6 +12,7 @@ OPENSSL_CTX, OPENSSL_CTX_new, OPENSSL_CTX_free - OpenSSL library context typedef struct openssl_ctx_st OPENSSL_CTX; OPENSSL_CTX *OPENSSL_CTX_new(void); + int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file); void OPENSSL_CTX_free(OPENSSL_CTX *ctx); =head1 DESCRIPTION @@ -26,6 +28,10 @@ multi-threaded applications to properly clean up thread local resources before the OPENSSL_CTX is freed. See L for more information. +OPENSSL_CTX_load_config() loads a configuration file using the given C. +This can be used to associate a libctx with providers that are loaded from +a configuration. + OPENSSL_CTX_free() frees the given C. =head1 RETURN VALUES @@ -37,12 +43,12 @@ OPENSSL_CTX_free() doesn't return any value. =head1 HISTORY -OPENSSL_CTX, OPENSSL_CTX_new() and OPENSSL_CTX_free() +OPENSSL_CTX, OPENSSL_CTX_new(), OPENSSL_CTX_load_config() and OPENSSL_CTX_free() were added in OpenSSL 3.0. =head1 COPYRIGHT -Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2019-2020 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 diff --git a/doc/man5/config.pod b/doc/man5/config.pod index b9ad06b124..98b8cd3317 100644 --- a/doc/man5/config.pod +++ b/doc/man5/config.pod @@ -455,7 +455,7 @@ priority and B used if neither is defined: Simple OpenSSL library configuration example to enter FIPS mode: # Default appname: should match "appname" parameter (if any) - # supplied to CONF_modules_load_file et al. + # supplied to CONF_modules_load_file_with_libctx et al. openssl_conf = openssl_conf_section [openssl_conf_section] @@ -488,7 +488,7 @@ minimum TLS version: More complex OpenSSL library configuration. Add OID and don't enter FIPS mode: # Default appname: should match "appname" parameter (if any) - # supplied to CONF_modules_load_file et al. + # supplied to CONF_modules_load_file_with_libctx et al. openssl_conf = openssl_conf_section [openssl_conf_section] @@ -576,7 +576,7 @@ L, L, L, L =head1 COPYRIGHT -Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-2020 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 diff --git a/include/openssl/conf.h b/include/openssl/conf.h index 438361e7a9..8fbb768f66 100644 --- a/include/openssl/conf.h +++ b/include/openssl/conf.h @@ -111,8 +111,10 @@ struct conf_st { void *meth_data; LHASH_OF(CONF_VALUE) *data; unsigned int flag_dollarid:1; + OPENSSL_CTX *libctx; }; +CONF *NCONF_new_with_libctx(OPENSSL_CTX *libctx, CONF_METHOD *meth); CONF *NCONF_new(CONF_METHOD *meth); CONF_METHOD *NCONF_default(void); DEPRECATEDIN_3_0(CONF_METHOD *NCONF_WIN32(void)) @@ -140,6 +142,8 @@ int NCONF_dump_bio(const CONF *conf, BIO *out); int CONF_modules_load(const CONF *cnf, const char *appname, unsigned long flags); +int CONF_modules_load_file_with_libctx(OPENSSL_CTX *libctx, const char *filename, + const char *appname, unsigned long flags); int CONF_modules_load_file(const char *filename, const char *appname, unsigned long flags); void CONF_modules_unload(int all); diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index a157558a51..3508144b4a 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -493,6 +493,7 @@ CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void); int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b); OPENSSL_CTX *OPENSSL_CTX_new(void); +int OPENSSL_CTX_load_config(OPENSSL_CTX *ctx, const char *config_file); void OPENSSL_CTX_free(OPENSSL_CTX *); # ifdef __cplusplus diff --git a/test/evp_fetch_prov_test.c b/test/evp_fetch_prov_test.c index ca39236cd6..14a3bb778d 100644 --- a/test/evp_fetch_prov_test.c +++ b/test/evp_fetch_prov_test.c @@ -20,6 +20,7 @@ #include #include "testutil.h" +static char *config_file = NULL; static char *alg = "digest"; static int use_default_ctx = 0; static char *fetch_property = NULL; @@ -32,6 +33,7 @@ typedef enum OPTION_choice { OPT_FETCH_PROPERTY, OPT_FETCH_FAILURE, OPT_USE_DEFAULTCTX, + OPT_CONFIG_FILE, OPT_TEST_ENUM } OPTION_CHOICE; @@ -39,6 +41,7 @@ const OPTIONS *test_get_options(void) { static const OPTIONS test_options[] = { OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("[provname...]\n"), + { "config", OPT_CONFIG_FILE, '<', "The configuration file to use for the libctx" }, { "type", OPT_ALG_FETCH_TYPE, 's', "The fetch type to test" }, { "property", OPT_FETCH_PROPERTY, 's', "The fetch property e.g. provider=fips" }, { "fetchfail", OPT_FETCH_FAILURE, '-', "fetch is expected to fail" }, @@ -75,7 +78,7 @@ static int calculate_digest(const EVP_MD *md, const char *msg, size_t len, static int load_providers(OPENSSL_CTX **libctx, OSSL_PROVIDER *prov[]) { - OPENSSL_CTX *ctx; + OPENSSL_CTX *ctx = NULL; int ret = 0; size_t i; @@ -83,6 +86,8 @@ static int load_providers(OPENSSL_CTX **libctx, OSSL_PROVIDER *prov[]) if (!TEST_ptr(ctx)) goto err; + if (!TEST_true(OPENSSL_CTX_load_config(ctx, config_file))) + goto err; if (test_get_argument_count() > 2) goto err; @@ -92,9 +97,12 @@ static int load_providers(OPENSSL_CTX **libctx, OSSL_PROVIDER *prov[]) if (!TEST_ptr(prov[i])) goto err; } + ret = 1; *libctx = ctx; err: + if (ret == 0) + OPENSSL_CTX_free(ctx); return ret; } @@ -231,6 +239,9 @@ int setup_tests(void) while ((o = opt_next()) != OPT_EOF) { switch (o) { + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; case OPT_ALG_FETCH_TYPE: alg = opt_arg(); break; diff --git a/test/recipes/30-test_evp_fetch_prov.t b/test/recipes/30-test_evp_fetch_prov.t index 8ffd2a50d8..36c324eeb3 100644 --- a/test/recipes/30-test_evp_fetch_prov.t +++ b/test/recipes/30-test_evp_fetch_prov.t @@ -121,7 +121,7 @@ foreach my $setup (@setups) { foreach my $alg (@types) { foreach my $testcase (@testdata) { - $ENV{OPENSSL_CONF} = $testcase->{config}; + $ENV{OPENSSL_CONF} = ""; foreach my $test (@{$testcase->{tests}}) { my @testproviders = @{ $test->{providers} // $testcase->{providers} }; @@ -137,6 +137,7 @@ foreach my $alg (@types) { "running evp_fetch_prov_test with $alg$testprovstr$testmsg"; ok(run(test(["evp_fetch_prov_test", "-type", "$alg", + "-config", "$testcase->{config}", @testargs, @testproviders])), $message); } diff --git a/util/libcrypto.num b/util/libcrypto.num index cd1aa75a84..0e275084d1 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4984,3 +4984,6 @@ EVP_PKEY_gen ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_set_rsa_keygen_bits ? 3_0_0 EXIST::FUNCTION:RSA EVP_PKEY_CTX_set_rsa_keygen_pubexp ? 3_0_0 EXIST::FUNCTION:RSA EVP_PKEY_CTX_set_rsa_keygen_primes ? 3_0_0 EXIST::FUNCTION:RSA +NCONF_new_with_libctx ? 3_0_0 EXIST::FUNCTION: +CONF_modules_load_file_with_libctx ? 3_0_0 EXIST::FUNCTION: +OPENSSL_CTX_load_config ? 3_0_0 EXIST::FUNCTION: diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index 956ce7ce6e..4c3af107d9 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -749,18 +749,14 @@ NAME_CONSTRAINTS_check_CN(3) NAME_CONSTRAINTS_it(3) NAMING_AUTHORITY_it(3) NCONF_WIN32(3) -NCONF_default(3) NCONF_dump_bio(3) NCONF_dump_fp(3) -NCONF_free(3) NCONF_free_data(3) NCONF_get_number_e(3) NCONF_get_section(3) NCONF_get_string(3) -NCONF_load(3) NCONF_load_bio(3) NCONF_load_fp(3) -NCONF_new(3) NETSCAPE_CERT_SEQUENCE_it(3) NETSCAPE_SPKAC_it(3) NETSCAPE_SPKI_b64_decode(3)