From 63b671626e32a8760872790aa2efc3455401ac9e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 14 Oct 2024 13:23:33 -0400 Subject: [PATCH] Make ossl_trace_param_values an official api function lots of people may want to print params to a buffer. Make it part of our api Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/25630) --- crypto/params_from_text.c | 106 +++++++++++++++++++ crypto/property/property.c | 16 +-- crypto/provider_core.c | 152 ++++++++++----------------- doc/build.info | 6 ++ doc/man3/OSSL_PARAM_print_to_bio.pod | 42 ++++++++ include/openssl/params.h | 3 + util/libcrypto.num | 1 + 7 files changed, 222 insertions(+), 104 deletions(-) create mode 100644 doc/man3/OSSL_PARAM_print_to_bio.pod diff --git a/crypto/params_from_text.c b/crypto/params_from_text.c index e603dfec64..7532d4d439 100644 --- a/crypto/params_from_text.c +++ b/crypto/params_from_text.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * When processing text to params, we're trying to be smart with numbers. @@ -197,6 +198,111 @@ static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef, return 1; } +/** + * OSSL_PARAM_print_to_bio - Print OSSL_PARAM array to a bio + * + * @p: Array of OSSL_PARAM structures containing keys and values. + * @bio: Pointer to bio where the formatted output will be written. + * @print_values: If non-zero, prints both keys and values. If zero, only keys + * are printed. + * + * This function iterates through the given array of OSSL_PARAM structures, + * printing each key to an in-memory buffer, and optionally printing its + * value based on the provided data type. Supported types include integers, + * strings, octet strings, and real numbers. + * + * Return: 1 on success, 0 on failure. + */ +int OSSL_PARAM_print_to_bio(const OSSL_PARAM *p, BIO *bio, int print_values) +{ + int64_t i; + uint64_t u; + BIGNUM *bn; +#ifndef OPENSSL_SYS_UEFI + double d; +#endif + int ok = -1; + int dok; + + /* + * Iterate through each key in the array printing its key and value + */ + for (; p->key != NULL; p++) { + ok = -1; + ok = BIO_printf(bio, "%s: ", p->key); + + if (ok == -1) + goto end; + + /* + * if printing of values was not requested, just move on + * to the next param, after adding a newline to the buffer + */ + if (print_values == 0) { + BIO_printf(bio, "\n"); + continue; + } + + switch (p->data_type) { + case OSSL_PARAM_UNSIGNED_INTEGER: + if (p->data_size > sizeof(int64_t)) { + if (OSSL_PARAM_get_BN(p, &bn)) + ok = BN_print(bio, bn); + else + ok = BIO_printf(bio, "error getting value\n"); + } else { + if (OSSL_PARAM_get_uint64(p, &u)) + ok = BIO_printf(bio, "%llu\n", (unsigned long long int)u); + else + ok = BIO_printf(bio, "error getting value\n"); + } + break; + case OSSL_PARAM_INTEGER: + if (p->data_size > sizeof(int64_t)) { + if (OSSL_PARAM_get_BN(p, &bn)) + ok = BN_print(bio, bn); + else + ok = BIO_printf(bio, "error getting value\n"); + } else { + if (OSSL_PARAM_get_int64(p, &i)) + ok = BIO_printf(bio, "%lld\n", (long long int)i); + else + ok = BIO_printf(bio, "error getting value\n"); + } + break; + case OSSL_PARAM_UTF8_PTR: + ok = BIO_dump(bio, p->data, p->data_size); + break; + case OSSL_PARAM_UTF8_STRING: + ok = BIO_dump(bio, (char *)p->data, p->data_size); + break; + case OSSL_PARAM_OCTET_PTR: + case OSSL_PARAM_OCTET_STRING: + ok = BIO_dump(bio, (char *)p->data, p->data_size); + break; + case OSSL_PARAM_REAL: + dok = 0; +#ifndef OPENSSL_SYS_UEFI + dok = OSSL_PARAM_get_double(p, &d); +#endif + if (dok == 1) + ok = BIO_printf(bio, "%f\n", d); + else + ok = BIO_printf(bio, "error getting value\n"); + break; + default: + ok = BIO_printf(bio, "unknown type (%u) of %zu bytes\n", + p->data_type, p->data_size); + break; + } + if (ok == -1) + goto end; + } + +end: + return ok == -1 ? 0 : 1; +} + int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdefs, const char *key, const char *value, diff --git a/crypto/property/property.c b/crypto/property/property.c index 18c71bd446..4916ea450d 100644 --- a/crypto/property/property.c +++ b/crypto/property/property.c @@ -297,7 +297,7 @@ static int ossl_method_store_insert(OSSL_METHOD_STORE *store, ALGORITHM *alg) * reference count and destruction callbacks. * * @param store Pointer to the OSSL_METHOD_STORE where the method will be added. - * must be non-null. + * Must be non-null. * @param prov Pointer to the OSSL_PROVIDER for the provider of the method. * Must be non-null. * @param nid (identifier) associated with the method, must be > 0 @@ -402,10 +402,11 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov, if (tmpimpl->provider == impl->provider && tmpimpl->properties == impl->properties) - goto err; + break; } - if (sk_IMPLEMENTATION_push(alg->impls, impl)) { + if (i == sk_IMPLEMENTATION_num(alg->impls) + && sk_IMPLEMENTATION_push(alg->impls, impl)) { ret = 1; OSSL_TRACE_BEGIN(QUERY) { BIO_printf(trc_out, "Adding to method store " @@ -503,7 +504,8 @@ alg_cleanup_by_provider(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) char buf[512]; size_t size; - size = ossl_property_list_to_string(NULL, impl->properties, buf, 512); + size = ossl_property_list_to_string(NULL, impl->properties, buf, + sizeof(buf)); BIO_printf(trc_out, "Removing implementation from " "query cache\nproperties %s\nprovider %s\n", size == 0 ? "none" : buf, @@ -597,7 +599,7 @@ void ossl_method_store_do_all(OSSL_METHOD_STORE *store, * successful, it returns the method and its associated provider. * * @param store Pointer to the OSSL_METHOD_STORE from which to fetch the method. - * Must be non-null + * Must be non-null. * @param nid (identifier) of the method to be fetched. Must be > 0 * @param prop_query String containing the property query to match against. * @param prov_rw Pointer to the OSSL_PROVIDER to restrict the search to, or @@ -669,7 +671,7 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, /* * Search for a provider that provides this implementation. - * if the requested provider is NULL, then any provider will do, + * If the requested provider is NULL, then any provider will do, * otherwise we should try to find the one that matches the requested * provider. Note that providers are given implicit preference via the * ordering of the implementation stack @@ -688,7 +690,7 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, /* * If there are optional properties specified - * the search again, and select the provider that matches the + * then run the search again, and select the provider that matches the * most options */ optional = ossl_property_has_optional(pq); diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 8ae357d1e2..1b16b27905 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -1618,74 +1618,6 @@ OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov) return prov != NULL ? prov->libctx : NULL; } -/** - * @brief Prints the parameter values of an OSSL_PARAM array to a BIO. - * - * This function iterates over an array of OSSL_PARAM structures and prints the - * value of each parameter to the specified BIO stream. The parameter type is - * detected, and the value is printed accordingly. - * - * @param p Array of OSSL_PARAM structures to be printed. - * @param b BIO stream to print the parameter values to. - * - * The supported parameter types are: - * - OSSL_PARAM_UNSIGNED_INTEGER: Unsigned integer values. - * - OSSL_PARAM_INTEGER: Signed integer values. - * - OSSL_PARAM_UTF8_PTR: Pointer to a UTF-8 string. - * - OSSL_PARAM_UTF8_STRING: UTF-8 string. - * - OSSL_PARAM_OCTET_PTR/OCTET_STRING: Binary data (size in bytes). - */ -#ifndef FIPS_MODULE -static void trace_print_param_values(const OSSL_PARAM p[], BIO *b) -{ - int64_t i; - uint64_t u; -# ifndef OPENSSL_SYS_UEFI - double d; -# endif - - for (; p->key != NULL; p++) { - BIO_printf(b, "%s: ", p->key); - switch (p->data_type) { - case OSSL_PARAM_UNSIGNED_INTEGER: - if (OSSL_PARAM_get_uint64(p, &u)) - BIO_printf(b, "%llu\n", (unsigned long long int)u); - else - BIO_printf(b, "error getting value\n"); - break; - case OSSL_PARAM_INTEGER: - if (OSSL_PARAM_get_int64(p, &i)) - BIO_printf(b, "%lld\n", (long long int)i); - else - BIO_printf(b, "error getting value\n"); - break; - case OSSL_PARAM_UTF8_PTR: - BIO_printf(b, "'%s'\n", *(char **)(p->data)); - break; - case OSSL_PARAM_UTF8_STRING: - BIO_printf(b, "'%s'\n", (char *)p->data); - break; - case OSSL_PARAM_OCTET_PTR: - case OSSL_PARAM_OCTET_STRING: - BIO_printf(b, "<%zu bytes>\n", p->data_size); - break; -# ifndef OPENSSL_SYS_UEFI - case OSSL_PARAM_REAL: - if (OSSL_PARAM_get_double(p, &d)) - BIO_printf(b, "%f\n", d); - else - BIO_printf(b, "error getting value\n"); - break; -# endif - default: - BIO_printf(b, "unknown type (%u) of %zu bytes\n", - p->data_type, p->data_size); - break; - } - } -} -#endif - /** * @brief Tears down the given provider. * @@ -1732,16 +1664,26 @@ const OSSL_PARAM *ossl_provider_gettable_params(const OSSL_PROVIDER *prov) { const OSSL_PARAM *ret = NULL; - if (prov->gettable_params != NULL) { + if (prov->gettable_params != NULL) ret = prov->gettable_params(prov->provctx); + #ifndef FIPS_MODULE - OSSL_TRACE_BEGIN(PROVIDER) { - BIO_printf(trc_out, "(provider %s) gettable params\n", - ossl_provider_name(prov)); - trace_print_param_values(ret, trc_out); - } OSSL_TRACE_END(PROVIDER); + OSSL_TRACE_BEGIN(PROVIDER) { + char *buf = NULL; + + BIO_printf(trc_out, "(provider %s) gettable params\n", + ossl_provider_name(prov)); + BIO_printf(trc_out, "Parameters:\n"); + if (prov->gettable_params != NULL) { + if (!OSSL_PARAM_print_to_bio(ret, trc_out, 0)) + BIO_printf(trc_out, "Failed to parse param values\n"); + OPENSSL_free(buf); + } else { + BIO_printf(trc_out, "Provider doesn't implement gettable_params\n"); + } + } OSSL_TRACE_END(PROVIDER); #endif - } + return ret; } @@ -1768,13 +1710,18 @@ int ossl_provider_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]) ret = prov->get_params(prov->provctx, params); #ifndef FIPS_MODULE - if (ret == 1) { - OSSL_TRACE_BEGIN(PROVIDER) { - BIO_printf(trc_out, - "(provider %s) calling get_params\n", prov->name); - trace_print_param_values(params, trc_out); - } OSSL_TRACE_END(PROVIDER); - } + OSSL_TRACE_BEGIN(PROVIDER) { + + BIO_printf(trc_out, + "(provider %s) calling get_params\n", prov->name); + if (ret == 1) { + BIO_printf(trc_out, "Parameters:\n"); + if (!OSSL_PARAM_print_to_bio(params, trc_out, 1)) + BIO_printf(trc_out, "Failed to parse param values\n"); + } else { + BIO_printf(trc_out, "get_params call failed\n"); + } + } OSSL_TRACE_END(PROVIDER); #endif return ret; } @@ -1795,18 +1742,21 @@ int ossl_provider_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]) */ int ossl_provider_self_test(const OSSL_PROVIDER *prov) { - int ret; + int ret = 1; - if (prov->self_test == NULL) - return 1; - - ret = prov->self_test(prov->provctx); + if (prov->self_test != NULL) + ret = prov->self_test(prov->provctx); #ifndef FIPS_MODULE OSSL_TRACE_BEGIN(PROVIDER) { - BIO_printf(trc_out, - "(provider %s) Calling self_test, ret = %d\n", - prov->name, ret); + if (prov->self_test != NULL) + BIO_printf(trc_out, + "(provider %s) Calling self_test, ret = %d\n", + prov->name, ret); + else + BIO_printf(trc_out, + "(provider %s) doesn't implement self_test\n", + prov->name); } OSSL_TRACE_END(PROVIDER); #endif if (ret == 0) @@ -1875,15 +1825,21 @@ const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, { const OSSL_ALGORITHM *res; - if (prov->query_operation == NULL) + if (prov->query_operation == NULL) { +#ifndef FIPS_MODULE + OSSL_TRACE_BEGIN(PROVIDER) { + BIO_printf(trc_out, "provider %s lacks query operation!\n", + prov->name); + } OSSL_TRACE_END(PROVIDER); +#endif return NULL; + } res = prov->query_operation(prov->provctx, operation_id, no_cache); #ifndef FIPS_MODULE - if (res != NULL) { - OSSL_TRACE_BEGIN(PROVIDER) { - const OSSL_ALGORITHM *idx; - + OSSL_TRACE_BEGIN(PROVIDER) { + const OSSL_ALGORITHM *idx; + if (res != NULL) { BIO_printf(trc_out, "(provider %s) Calling query, available algs are:\n", prov->name); @@ -1898,8 +1854,10 @@ const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, res->algorithm_description == NULL ? "none" : res->algorithm_description); } - } OSSL_TRACE_END(PROVIDER); - } + } else { + BIO_printf(trc_out, "(provider %s) query_operation failed\n", prov->name); + } + } OSSL_TRACE_END(PROVIDER); #endif #if defined(OPENSSL_NO_CACHED_FETCH) diff --git a/doc/build.info b/doc/build.info index 490422b559..6ad291201d 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1787,6 +1787,10 @@ DEPEND[html/man3/OSSL_PARAM_int.html]=man3/OSSL_PARAM_int.pod GENERATE[html/man3/OSSL_PARAM_int.html]=man3/OSSL_PARAM_int.pod DEPEND[man/man3/OSSL_PARAM_int.3]=man3/OSSL_PARAM_int.pod GENERATE[man/man3/OSSL_PARAM_int.3]=man3/OSSL_PARAM_int.pod +DEPEND[html/man3/OSSL_PARAM_print_to_bio.html]=man3/OSSL_PARAM_print_to_bio.pod +GENERATE[html/man3/OSSL_PARAM_print_to_bio.html]=man3/OSSL_PARAM_print_to_bio.pod +DEPEND[man/man3/OSSL_PARAM_print_to_bio.3]=man3/OSSL_PARAM_print_to_bio.pod +GENERATE[man/man3/OSSL_PARAM_print_to_bio.3]=man3/OSSL_PARAM_print_to_bio.pod DEPEND[html/man3/OSSL_PROVIDER.html]=man3/OSSL_PROVIDER.pod GENERATE[html/man3/OSSL_PROVIDER.html]=man3/OSSL_PROVIDER.pod DEPEND[man/man3/OSSL_PROVIDER.3]=man3/OSSL_PROVIDER.pod @@ -3450,6 +3454,7 @@ html/man3/OSSL_PARAM_BLD.html \ html/man3/OSSL_PARAM_allocate_from_text.html \ html/man3/OSSL_PARAM_dup.html \ html/man3/OSSL_PARAM_int.html \ +html/man3/OSSL_PARAM_print_to_bio.html \ html/man3/OSSL_PROVIDER.html \ html/man3/OSSL_QUIC_client_method.html \ html/man3/OSSL_SELF_TEST_new.html \ @@ -4113,6 +4118,7 @@ man/man3/OSSL_PARAM_BLD.3 \ man/man3/OSSL_PARAM_allocate_from_text.3 \ man/man3/OSSL_PARAM_dup.3 \ man/man3/OSSL_PARAM_int.3 \ +man/man3/OSSL_PARAM_print_to_bio.3 \ man/man3/OSSL_PROVIDER.3 \ man/man3/OSSL_QUIC_client_method.3 \ man/man3/OSSL_SELF_TEST_new.3 \ diff --git a/doc/man3/OSSL_PARAM_print_to_bio.pod b/doc/man3/OSSL_PARAM_print_to_bio.pod new file mode 100644 index 0000000000..8822f6fa0f --- /dev/null +++ b/doc/man3/OSSL_PARAM_print_to_bio.pod @@ -0,0 +1,42 @@ +=pod + +=head1 NAME + +OSSL_PARAM_print_to_bio +- OSSL_PARAM interrogation utilities + +=head1 SYNOPSIS + + #include + + int OSSL_PARAM_print_to_bio(const OSSL_PARAM *p, BIO *bio, + int print_values); + +=head1 DESCRIPTION + +OSSL_PARAM_print_to_bio() formats each parameter contained in the +passed in array of B values I

, and prints both the key, +and optionally its value, to a provided B. +I

must be a non-null array of OSSL_PARAM values, terminated +with a value containing a null I member. +I is a control parameter, indicating that key values should be +printed, in addition to key names. + +=head1 RETURN VALUES + +OSSL_PARAM_print_to_bio() returns 1 on success, and 0 on failure + +=head1 HISTORY + +OSSL_PARAM_print_to_bio() was added in OpenSSL 3.5 + +=head1 COPYRIGHT + +Copyright 2024 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/include/openssl/params.h b/include/openssl/params.h index d75eab0764..d4b855dffb 100644 --- a/include/openssl/params.h +++ b/include/openssl/params.h @@ -100,6 +100,9 @@ int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to, const char *key, const char *value, size_t value_n, int *found); +int OSSL_PARAM_print_to_bio(const OSSL_PARAM *params, BIO *bio, + int print_values); + int OSSL_PARAM_get_int(const OSSL_PARAM *p, int *val); int OSSL_PARAM_get_uint(const OSSL_PARAM *p, unsigned int *val); int OSSL_PARAM_get_long(const OSSL_PARAM *p, long int *val); diff --git a/util/libcrypto.num b/util/libcrypto.num index 25cf30781c..88765ed9da 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5775,3 +5775,4 @@ d2i_OSSL_PRIVILEGE_POLICY_ID ? 3_5_0 EXIST::FUNCTION: i2d_OSSL_PRIVILEGE_POLICY_ID ? 3_5_0 EXIST::FUNCTION: OSSL_PRIVILEGE_POLICY_ID_free ? 3_5_0 EXIST::FUNCTION: OSSL_PRIVILEGE_POLICY_ID_new ? 3_5_0 EXIST::FUNCTION: +OSSL_PARAM_print_to_bio ? 3_5_0 EXIST::FUNCTION: