diff --git a/backport-01-Improve-FIPS-RSA-keygen-performance.patch b/backport-01-Improve-FIPS-RSA-keygen-performance.patch new file mode 100644 index 0000000000000000000000000000000000000000..816c0f7ceeb3da5d6af86bc4a1864949588d183e --- /dev/null +++ b/backport-01-Improve-FIPS-RSA-keygen-performance.patch @@ -0,0 +1,265 @@ +From dd1d7bcb69994d81662e709b0ad838880b943870 Mon Sep 17 00:00:00 2001 +From: slontis +Date: Wed, 2 Nov 2022 12:01:34 +1000 +Subject: [PATCH] Improve FIPS RSA keygen performance. + +FIPS 186-4 has 5 different algorithms for key generation, +and all of them rely on testing GCD(a,n) == 1 many times. + +Cachegrind was showing that during a RSA keygen operation, +the function BN_gcd() was taking a considerable percentage +of the total cycles. + +The default provider uses multiprime keygen, which seemed to +be much faster. This is because it uses BN_mod_inverse() +instead. + +For a 4096 bit key, the entropy of a key that was taking a +long time to generate was recorded and fed back into subsequent +runs. Roughly 40% of the cycle time was BN_gcd() with most of the +remainder in the prime testing. Changing to use the inverse +resulted in the cycle count being 96% in the prime testing. + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/19578) +--- + crypto/bn/bn_gcd.c | 31 +++++++++++++++++++++++++++++++ + crypto/bn/bn_rsa_fips186_4.c | 24 +++++++++++++++--------- + doc/man3/BN_cmp.pod | 14 +++++++++++++- + include/openssl/bn.h | 1 + + test/bntest.c | 26 ++++++++++++++++++++++++-- + util/libcrypto.num | 1 + + 6 files changed, 85 insertions(+), 12 deletions(-) + +diff --git a/crypto/bn/bn_gcd.c b/crypto/bn/bn_gcd.c +index 91ad76a161..519bb4e951 100644 +--- a/crypto/bn/bn_gcd.c ++++ b/crypto/bn/bn_gcd.c +@@ -534,6 +534,37 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, + return rv; + } + ++/* ++ * The numbers a and b are coprime if the only positive integer that is a ++ * divisor of both of them is 1. ++ * i.e. gcd(a,b) = 1. ++ * ++ * Coprimes have the property: b has a multiplicative inverse modulo a ++ * i.e there is some value x such that bx = 1 (mod a). ++ * ++ * Testing the modulo inverse is currently much faster than the constant ++ * time version of BN_gcd(). ++ */ ++int BN_are_coprime(BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) ++{ ++ int ret = 0; ++ BIGNUM *tmp; ++ ++ BN_CTX_start(ctx); ++ tmp = BN_CTX_get(ctx); ++ if (tmp == NULL) ++ goto end; ++ ++ ERR_set_mark(); ++ BN_set_flags(a, BN_FLG_CONSTTIME); ++ ret = (BN_mod_inverse(tmp, a, b, ctx) != NULL); ++ /* Clear any errors (an error is returned if there is no inverse) */ ++ ERR_pop_to_mark(); ++end: ++ BN_CTX_end(ctx); ++ return ret; ++} ++ + /*- + * This function is based on the constant-time GCD work by Bernstein and Yang: + * https://eprint.iacr.org/2019/266 +diff --git a/crypto/bn/bn_rsa_fips186_4.c b/crypto/bn/bn_rsa_fips186_4.c +index 770ae4d1fa..e3a2ad76af 100644 +--- a/crypto/bn/bn_rsa_fips186_4.c ++++ b/crypto/bn/bn_rsa_fips186_4.c +@@ -286,14 +286,20 @@ int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + goto err; + } + ++ /* ++ * (Step 1) GCD(2r1, r2) = 1. ++ * Note: This algorithm was doing a gcd(2r1, r2)=1 test before doing an ++ * mod_inverse(2r1, r2) which are effectively the same operation. ++ * (The algorithm assumed that the gcd test would be faster). Since the ++ * mod_inverse is currently faster than calling the constant time ++ * BN_gcd(), the call to BN_gcd() has been omitted. The inverse result ++ * is used further down. ++ */ + if (!(BN_lshift1(r1x2, r1) +- /* (Step 1) GCD(2r1, r2) = 1 */ +- && BN_gcd(tmp, r1x2, r2, ctx) +- && BN_is_one(tmp) ++ && (BN_mod_inverse(tmp, r1x2, r2, ctx) != NULL) + /* (Step 2) R = ((r2^-1 mod 2r1) * r2) - ((2r1^-1 mod r2)*2r1) */ +- && BN_mod_inverse(R, r2, r1x2, ctx) ++ && (BN_mod_inverse(R, r2, r1x2, ctx) != NULL) + && BN_mul(R, R, r2, ctx) /* R = (r2^-1 mod 2r1) * r2 */ +- && BN_mod_inverse(tmp, r1x2, r2, ctx) + && BN_mul(tmp, tmp, r1x2, ctx) /* tmp = (2r1^-1 mod r2)*2r1 */ + && BN_sub(R, R, tmp) + /* Calculate 2r1r2 */ +@@ -305,7 +311,8 @@ int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + + /* + * In FIPS 186-4 imax was set to 5 * nlen/2. +- * Analysis by Allen Roginsky (See https://csrc.nist.gov/CSRC/media/Publications/fips/186/4/final/documents/comments-received-fips186-4-december-2015.pdf ++ * Analysis by Allen Roginsky ++ * (See https://csrc.nist.gov/CSRC/media/Publications/fips/186/4/final/documents/comments-received-fips186-4-december-2015.pdf + * page 68) indicates this has a 1 in 2 million chance of failure. + * The number has been updated to 20 * nlen/2 as used in + * FIPS186-5 Appendix B.9 Step 9. +@@ -337,10 +344,9 @@ int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + + /* (Step 7) If GCD(Y-1) == 1 & Y is probably prime then return Y */ + if (BN_copy(y1, Y) == NULL +- || !BN_sub_word(y1, 1) +- || !BN_gcd(tmp, y1, e, ctx)) ++ || !BN_sub_word(y1, 1)) + goto err; +- if (BN_is_one(tmp)) { ++ if (BN_are_coprime(y1, e, ctx)) { + int rv = BN_check_prime(Y, ctx, cb); + + if (rv > 0) +diff --git a/doc/man3/BN_cmp.pod b/doc/man3/BN_cmp.pod +index f302818f21..e9ddf8fa2d 100644 +--- a/doc/man3/BN_cmp.pod ++++ b/doc/man3/BN_cmp.pod +@@ -2,7 +2,8 @@ + + =head1 NAME + +-BN_cmp, BN_ucmp, BN_is_zero, BN_is_one, BN_is_word, BN_abs_is_word, BN_is_odd - BIGNUM comparison and test functions ++BN_cmp, BN_ucmp, BN_is_zero, BN_is_one, BN_is_word, BN_abs_is_word, BN_is_odd, BN_are_coprime ++- BIGNUM comparison and test functions + + =head1 SYNOPSIS + +@@ -17,6 +18,8 @@ BN_cmp, BN_ucmp, BN_is_zero, BN_is_one, BN_is_word, BN_abs_is_word, BN_is_odd - + int BN_abs_is_word(const BIGNUM *a, const BN_ULONG w); + int BN_is_odd(const BIGNUM *a); + ++ int BN_are_coprime(BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); ++ + =head1 DESCRIPTION + + BN_cmp() compares the numbers I and I. BN_ucmp() compares their +@@ -26,6 +29,10 @@ BN_is_zero(), BN_is_one(), BN_is_word() and BN_abs_is_word() test if + I equals 0, 1, I, or EIE respectively. + BN_is_odd() tests if I is odd. + ++BN_are_coprime() determines if B and B are coprime. ++B is used internally for storing temporary variables. ++The values of B and B and B must not be NULL. ++ + =head1 RETURN VALUES + + BN_cmp() returns -1 if I E I, 0 if I == I and 1 if +@@ -35,11 +42,16 @@ of I and I. + BN_is_zero(), BN_is_one() BN_is_word(), BN_abs_is_word() and + BN_is_odd() return 1 if the condition is true, 0 otherwise. + ++BN_are_coprime() returns 1 if the B's are coprime, otherwise it ++returns 0. ++ + =head1 HISTORY + + Prior to OpenSSL 1.1.0, BN_is_zero(), BN_is_one(), BN_is_word(), + BN_abs_is_word() and BN_is_odd() were macros. + ++The function BN_are_coprime() was added in OpenSSL 3.1. ++ + =head1 COPYRIGHT + + Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. +diff --git a/include/openssl/bn.h b/include/openssl/bn.h +index 333e201eae..ea706dca7f 100644 +--- a/include/openssl/bn.h ++++ b/include/openssl/bn.h +@@ -350,6 +350,7 @@ int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); + int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); /* returns + * -2 for + * error */ ++int BN_are_coprime(BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); + BIGNUM *BN_mod_inverse(BIGNUM *ret, + const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx); + BIGNUM *BN_mod_sqrt(BIGNUM *ret, +diff --git a/test/bntest.c b/test/bntest.c +index 85445b701b..b35b53df7e 100644 +--- a/test/bntest.c ++++ b/test/bntest.c +@@ -41,6 +41,7 @@ typedef struct mpitest_st { + + static const int NUM0 = 100; /* number of tests */ + static const int NUM1 = 50; /* additional tests for some functions */ ++static const int NUM_PRIME_TESTS = 20; + static BN_CTX *ctx; + + /* +@@ -2722,6 +2723,25 @@ static int test_ctx_consttime_flag(void) + return st; + } + ++static int test_coprime(void) ++{ ++ BIGNUM *a = NULL, *b = NULL; ++ int ret = 0; ++ ++ ret = TEST_ptr(a = BN_new()) ++ && TEST_ptr(b = BN_new()) ++ && TEST_true(BN_set_word(a, 66)) ++ && TEST_true(BN_set_word(b, 99)) ++ && TEST_int_eq(BN_are_coprime(a, b, ctx), 0) ++ && TEST_int_eq(BN_are_coprime(b, a, ctx), 0) ++ && TEST_true(BN_set_word(a, 67)) ++ && TEST_int_eq(BN_are_coprime(a, b, ctx), 1) ++ && TEST_int_eq(BN_are_coprime(b, a, ctx), 1); ++ BN_free(a); ++ BN_free(b); ++ return ret; ++} ++ + static int test_gcd_prime(void) + { + BIGNUM *a = NULL, *b = NULL, *gcd = NULL; +@@ -2734,11 +2754,12 @@ static int test_gcd_prime(void) + + if (!TEST_true(BN_generate_prime_ex(a, 1024, 0, NULL, NULL, NULL))) + goto err; +- for (i = 0; i < NUM0; i++) { ++ for (i = 0; i < NUM_PRIME_TESTS; i++) { + if (!TEST_true(BN_generate_prime_ex(b, 1024, 0, + NULL, NULL, NULL)) + || !TEST_true(BN_gcd(gcd, a, b, ctx)) +- || !TEST_true(BN_is_one(gcd))) ++ || !TEST_true(BN_is_one(gcd)) ++ || !TEST_true(BN_are_coprime(a, b, ctx))) + goto err; + } + +@@ -3216,6 +3237,7 @@ int setup_tests(void) + ADD_ALL_TESTS(test_is_prime, (int)OSSL_NELEM(primes)); + ADD_ALL_TESTS(test_not_prime, (int)OSSL_NELEM(not_primes)); + ADD_TEST(test_gcd_prime); ++ ADD_TEST(test_coprime); + ADD_ALL_TESTS(test_mod_exp, (int)OSSL_NELEM(ModExpTests)); + ADD_ALL_TESTS(test_mod_exp_consttime, (int)OSSL_NELEM(ModExpTests)); + ADD_TEST(test_mod_exp2_mont); +diff --git a/util/libcrypto.num b/util/libcrypto.num +index 0f6f30b..4a20709 100644 +--- a/util/libcrypto.num ++++ b/util/libcrypto.num +@@ -5429,3 +5429,4 @@ OPENSSL_strcasecmp 5556 3_0_3 EXIST::FUNCTION: + OPENSSL_strncasecmp 5557 3_0_3 EXIST::FUNCTION: + OSSL_CMP_CTX_reset_geninfo_ITAVs 5558 3_0_8 EXIST::FUNCTION:CMP + OSSL_CMP_MSG_update_recipNonce 5559 3_0_9 EXIST::FUNCTION:CMP ++BN_are_coprime 5560 3_0_12 EXIST::FUNCTION: +-- +2.33.0 + diff --git a/backport-02-Improve-FIPS-RSA-keygen-performance.patch b/backport-02-Improve-FIPS-RSA-keygen-performance.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ce670b283af12c54b7f328e9fd14aeab8060def --- /dev/null +++ b/backport-02-Improve-FIPS-RSA-keygen-performance.patch @@ -0,0 +1,179 @@ +From d2f6e66d2837bff1f5f7636bb2118e3a45c9df61 Mon Sep 17 00:00:00 2001 +From: slontis +Date: Wed, 2 Nov 2022 13:20:55 +1000 +Subject: [PATCH] Improve FIPS RSA keygen performance. + +Reduce the Miller Rabin counts to the values specified by FIPS 186-5. +The old code was using a fixed value of 64. + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/19579) +--- + crypto/bn/bn_prime.c | 11 ++++++++ + crypto/bn/bn_rsa_fips186_4.c | 49 ++++++++++++++++++++++++++++++------ + include/crypto/bn.h | 2 ++ + 3 files changed, 54 insertions(+), 8 deletions(-) + +diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c +index 560855542f..96eb1b3c34 100644 +--- a/crypto/bn/bn_prime.c ++++ b/crypto/bn/bn_prime.c +@@ -250,6 +250,17 @@ int ossl_bn_check_prime(const BIGNUM *w, int checks, BN_CTX *ctx, + return bn_is_prime_int(w, checks, ctx, do_trial_division, cb); + } + ++/* ++ * Use this only for key generation. ++ * It always uses trial division. The number of checks ++ * (MR rounds) passed in is used without being clamped to a minimum value. ++ */ ++int ossl_bn_check_generated_prime(const BIGNUM *w, int checks, BN_CTX *ctx, ++ BN_GENCB *cb) ++{ ++ return bn_is_prime_int(w, checks, ctx, 1, cb); ++} ++ + int BN_check_prime(const BIGNUM *p, BN_CTX *ctx, BN_GENCB *cb) + { + return ossl_bn_check_prime(p, 0, ctx, 1, cb); +diff --git a/crypto/bn/bn_rsa_fips186_4.c b/crypto/bn/bn_rsa_fips186_4.c +index e3a2ad76af..765ee250e7 100644 +--- a/crypto/bn/bn_rsa_fips186_4.c ++++ b/crypto/bn/bn_rsa_fips186_4.c +@@ -48,6 +48,34 @@ const BIGNUM ossl_bn_inv_sqrt_2 = { + BN_FLG_STATIC_DATA + }; + ++/* ++ * Refer to FIPS 186-5 Table B.1 for minimum rounds of Miller Rabin ++ * required for generation of RSA aux primes (p1, p2, q1 and q2). ++ */ ++static int bn_rsa_fips186_5_aux_prime_MR_rounds(int nbits) ++{ ++ if (nbits >= 4096) ++ return 44; ++ if (nbits >= 3072) ++ return 41; ++ if (nbits >= 2048) ++ return 38; ++ return 0; /* Error */ ++} ++ ++/* ++ * Refer to FIPS 186-5 Table B.1 for minimum rounds of Miller Rabin ++ * required for generation of RSA primes (p and q) ++ */ ++static int bn_rsa_fips186_5_prime_MR_rounds(int nbits) ++{ ++ if (nbits >= 3072) ++ return 4; ++ if (nbits >= 2048) ++ return 5; ++ return 0; /* Error */ ++} ++ + /* + * FIPS 186-5 Table A.1. "Min length of auxiliary primes p1, p2, q1, q2". + * (FIPS 186-5 has an entry for >= 4096 bits). +@@ -97,11 +125,13 @@ static int bn_rsa_fips186_5_aux_prime_max_sum_size_for_prob_primes(int nbits) + * Xp1 The passed in starting point to find a probably prime. + * p1 The returned probable prime (first odd integer >= Xp1) + * ctx A BN_CTX object. ++ * rounds The number of Miller Rabin rounds + * cb An optional BIGNUM callback. + * Returns: 1 on success otherwise it returns 0. + */ + static int bn_rsa_fips186_4_find_aux_prob_prime(const BIGNUM *Xp1, + BIGNUM *p1, BN_CTX *ctx, ++ int rounds, + BN_GENCB *cb) + { + int ret = 0; +@@ -117,7 +147,7 @@ static int bn_rsa_fips186_4_find_aux_prob_prime(const BIGNUM *Xp1, + i++; + BN_GENCB_call(cb, 0, i); + /* MR test with trial division */ +- tmp = BN_check_prime(p1, ctx, cb); ++ tmp = ossl_bn_check_generated_prime(p1, rounds, ctx, cb); + if (tmp > 0) + break; + if (tmp < 0) +@@ -160,7 +190,7 @@ int ossl_bn_rsa_fips186_4_gen_prob_primes(BIGNUM *p, BIGNUM *Xpout, + { + int ret = 0; + BIGNUM *p1i = NULL, *p2i = NULL, *Xp1i = NULL, *Xp2i = NULL; +- int bitlen; ++ int bitlen, rounds; + + if (p == NULL || Xpout == NULL) + return 0; +@@ -177,6 +207,7 @@ int ossl_bn_rsa_fips186_4_gen_prob_primes(BIGNUM *p, BIGNUM *Xpout, + bitlen = bn_rsa_fips186_5_aux_prime_min_size(nlen); + if (bitlen == 0) + goto err; ++ rounds = bn_rsa_fips186_5_aux_prime_MR_rounds(nlen); + + /* (Steps 4.1/5.1): Randomly generate Xp1 if it is not passed in */ + if (Xp1 == NULL) { +@@ -194,8 +225,8 @@ int ossl_bn_rsa_fips186_4_gen_prob_primes(BIGNUM *p, BIGNUM *Xpout, + } + + /* (Steps 4.2/5.2) - find first auxiliary probable primes */ +- if (!bn_rsa_fips186_4_find_aux_prob_prime(Xp1i, p1i, ctx, cb) +- || !bn_rsa_fips186_4_find_aux_prob_prime(Xp2i, p2i, ctx, cb)) ++ if (!bn_rsa_fips186_4_find_aux_prob_prime(Xp1i, p1i, ctx, rounds, cb) ++ || !bn_rsa_fips186_4_find_aux_prob_prime(Xp2i, p2i, ctx, rounds, cb)) + goto err; + /* (Table B.1) auxiliary prime Max length check */ + if ((BN_num_bits(p1i) + BN_num_bits(p2i)) >= +@@ -243,11 +274,11 @@ err: + */ + int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + const BIGNUM *r1, const BIGNUM *r2, +- int nlen, const BIGNUM *e, BN_CTX *ctx, +- BN_GENCB *cb) ++ int nlen, const BIGNUM *e, ++ BN_CTX *ctx, BN_GENCB *cb) + { + int ret = 0; +- int i, imax; ++ int i, imax, rounds; + int bits = nlen >> 1; + BIGNUM *tmp, *R, *r1r2x2, *y1, *r1x2; + BIGNUM *base, *range; +@@ -317,6 +348,7 @@ int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + * The number has been updated to 20 * nlen/2 as used in + * FIPS186-5 Appendix B.9 Step 9. + */ ++ rounds = bn_rsa_fips186_5_prime_MR_rounds(nlen); + imax = 20 * bits; /* max = 20/2 * nbits */ + for (;;) { + if (Xin == NULL) { +@@ -346,8 +378,9 @@ int ossl_bn_rsa_fips186_4_derive_prime(BIGNUM *Y, BIGNUM *X, const BIGNUM *Xin, + if (BN_copy(y1, Y) == NULL + || !BN_sub_word(y1, 1)) + goto err; ++ + if (BN_are_coprime(y1, e, ctx)) { +- int rv = BN_check_prime(Y, ctx, cb); ++ int rv = ossl_bn_check_generated_prime(Y, rounds, ctx, cb); + + if (rv > 0) + goto end; +diff --git a/include/crypto/bn.h b/include/crypto/bn.h +index cf69bea848..4d11e0e4b1 100644 +--- a/include/crypto/bn.h ++++ b/include/crypto/bn.h +@@ -95,6 +95,8 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, + + int ossl_bn_miller_rabin_is_prime(const BIGNUM *w, int iterations, BN_CTX *ctx, + BN_GENCB *cb, int enhanced, int *status); ++int ossl_bn_check_generated_prime(const BIGNUM *w, int checks, BN_CTX *ctx, ++ BN_GENCB *cb); + + const BIGNUM *ossl_bn_get0_small_factors(void); + +-- +2.33.0 + diff --git a/backport-Add-CTX-copy-function-for-EVP_MD-to-optimize-the-per.patch b/backport-Add-CTX-copy-function-for-EVP_MD-to-optimize-the-per.patch new file mode 100644 index 0000000000000000000000000000000000000000..92a3238fe5ed27841055e5f9d29cf83774436484 --- /dev/null +++ b/backport-Add-CTX-copy-function-for-EVP_MD-to-optimize-the-per.patch @@ -0,0 +1,306 @@ +From 4c41aa4b338ca181a394483c8bb6aeb6366c6f96 Mon Sep 17 00:00:00 2001 +From: wangcheng +Date: Sat, 26 Oct 2024 17:10:38 +0800 +Subject: [PATCH] Add CTX copy function for EVP_MD to optimize the performance + of EVP_MD_CTX_copy_ex. + +1. Add OSSL_FUNC_digest_copyctx_fn function for EVP_MD, which is used to copy algctx from the old EVP_MD_CTX to the new one. + +2. Add implementation of OSSL_FUNC_digest_copyctx_fn function for default providers. + +3. Modify EVP_MD_CTX_copy_ex: When the fetched digest is the same in in and out contexts, use the copy function to copy the members in EVP_MD_CTX if the OSSL_FUNC_digest_copyctx_fn function exists. Otherwise, use the previous method to copy. + +4. Add documentation for OSSL_FUNC_digest_copyctx function in doc/man7/provider-digest.pod. + +5. Add testcase. + +Fixes #25703 + +Signed-off-by: wangcheng + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/25726) +--- + crypto/evp/digest.c | 47 +++++++++++++------ + doc/man7/provider-digest.pod | 11 +++++ + include/crypto/evp.h | 1 + + include/openssl/core_dispatch.h | 2 + + providers/implementations/digests/sha3_prov.c | 10 ++++ + .../include/prov/digestcommon.h | 7 +++ + test/evp_extra_test2.c | 43 +++++++++++++++++ + 7 files changed, 106 insertions(+), 15 deletions(-) + +diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c +index eefed52..f5c44b1 100644 +--- a/crypto/evp/digest.c ++++ b/crypto/evp/digest.c +@@ -548,23 +548,35 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) + return 0; + } + +- evp_md_ctx_reset_ex(out, 1); +- digest_change = (out->fetched_digest != in->fetched_digest); +- if (digest_change && out->fetched_digest != NULL) +- EVP_MD_free(out->fetched_digest); +- *out = *in; +- /* NULL out pointers in case of error */ +- out->pctx = NULL; +- out->algctx = NULL; ++ if (out->digest == in->digest && in->digest->copyctx != NULL) { + +- if (digest_change && in->fetched_digest != NULL) +- EVP_MD_up_ref(in->fetched_digest); ++ in->digest->copyctx(out->algctx, in->algctx); + +- if (in->algctx != NULL) { +- out->algctx = in->digest->dupctx(in->algctx); +- if (out->algctx == NULL) { +- ERR_raise(ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX); +- return 0; ++ EVP_PKEY_CTX_free(out->pctx); ++ out->pctx = NULL; ++ cleanup_old_md_data(out, 0); ++ ++ out->flags = in->flags; ++ out->update = in->update; ++ } else { ++ evp_md_ctx_reset_ex(out, 1); ++ digest_change = (out->fetched_digest != in->fetched_digest); ++ if (digest_change && out->fetched_digest != NULL) ++ EVP_MD_free(out->fetched_digest); ++ *out = *in; ++ /* NULL out pointers in case of error */ ++ out->pctx = NULL; ++ out->algctx = NULL; ++ ++ if (digest_change && in->fetched_digest != NULL) ++ EVP_MD_up_ref(in->fetched_digest); ++ ++ if (in->algctx != NULL) { ++ out->algctx = in->digest->dupctx(in->algctx); ++ if (out->algctx == NULL) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX); ++ return 0; ++ } + } + } + +@@ -1029,6 +1041,11 @@ static void *evp_md_from_algorithm(int name_id, + md->gettable_ctx_params = + OSSL_FUNC_digest_gettable_ctx_params(fns); + break; ++ case OSSL_FUNC_DIGEST_COPYCTX: ++ if (md->copyctx == NULL) ++ md->copyctx = ++ OSSL_FUNC_digest_copyctx(fns); ++ break; + } + } + if ((fncnt != 0 && fncnt != 5) +diff --git a/doc/man7/provider-digest.pod b/doc/man7/provider-digest.pod +index cac53ac..0ed0d3b 100644 +--- a/doc/man7/provider-digest.pod ++++ b/doc/man7/provider-digest.pod +@@ -20,6 +20,7 @@ provider-digest - The digest library E-E provider functions + void *OSSL_FUNC_digest_newctx(void *provctx); + void OSSL_FUNC_digest_freectx(void *dctx); + void *OSSL_FUNC_digest_dupctx(void *dctx); ++ void OSSL_FUNC_digest_copyctx(void *voutctx, void *vinctx); + + /* Digest generation */ + int OSSL_FUNC_digest_init(void *dctx, const OSSL_PARAM params[]); +@@ -76,6 +77,7 @@ macros in L, as follows: + OSSL_FUNC_digest_newctx OSSL_FUNC_DIGEST_NEWCTX + OSSL_FUNC_digest_freectx OSSL_FUNC_DIGEST_FREECTX + OSSL_FUNC_digest_dupctx OSSL_FUNC_DIGEST_DUPCTX ++ OSSL_FUNC_digest_copyctx OSSL_FUNC_DIGEST_COPYCTX + + OSSL_FUNC_digest_init OSSL_FUNC_DIGEST_INIT + OSSL_FUNC_digest_update OSSL_FUNC_DIGEST_UPDATE +@@ -111,6 +113,14 @@ This function should free any resources associated with that context. + OSSL_FUNC_digest_dupctx() should duplicate the provider side digest context in the + I parameter and return the duplicate copy. + ++OSSL_FUNC_digest_copyctx() should copy the provider side digest context in the ++I parameter to the I parameter which is the another provider side ++context. ++The OSSL_FUNC_digest_copyctx function is used in the EVP_MD_CTX_copy_ex function to ++speed up HMAC operations in the PBKDF2. ++This function is optional, and dupctx will be used if there is no EVP_MD_CTX_copy_ex ++function. ++ + =head2 Digest Generation Functions + + OSSL_FUNC_digest_init() initialises a digest operation given a newly created +@@ -274,6 +284,7 @@ L, L + =head1 HISTORY + + The provider DIGEST interface was introduced in OpenSSL 3.0. ++OSSL_FUNC_digest_copyctx() was added in 3.5 version. + + =head1 COPYRIGHT + +diff --git a/include/crypto/evp.h b/include/crypto/evp.h +index e70d8e9..f17b569 100644 +--- a/include/crypto/evp.h ++++ b/include/crypto/evp.h +@@ -277,6 +277,7 @@ struct evp_md_st { + OSSL_FUNC_digest_final_fn *dfinal; + OSSL_FUNC_digest_digest_fn *digest; + OSSL_FUNC_digest_freectx_fn *freectx; ++ OSSL_FUNC_digest_copyctx_fn *copyctx; + OSSL_FUNC_digest_dupctx_fn *dupctx; + OSSL_FUNC_digest_get_params_fn *get_params; + OSSL_FUNC_digest_set_ctx_params_fn *set_ctx_params; +diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h +index 99fcda0..e6fa38d 100644 +--- a/include/openssl/core_dispatch.h ++++ b/include/openssl/core_dispatch.h +@@ -283,6 +283,7 @@ OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx)) + # define OSSL_FUNC_DIGEST_GETTABLE_PARAMS 11 + # define OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS 12 + # define OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS 13 ++# define OSSL_FUNC_DIGEST_COPYCTX 14 + + OSSL_CORE_MAKE_FUNC(void *, digest_newctx, (void *provctx)) + OSSL_CORE_MAKE_FUNC(int, digest_init, (void *dctx, const OSSL_PARAM params[])) +@@ -297,6 +298,7 @@ OSSL_CORE_MAKE_FUNC(int, digest_digest, + + OSSL_CORE_MAKE_FUNC(void, digest_freectx, (void *dctx)) + OSSL_CORE_MAKE_FUNC(void *, digest_dupctx, (void *dctx)) ++OSSL_CORE_MAKE_FUNC(void, digest_copyctx, (void *outctx, void *inctx)) + + OSSL_CORE_MAKE_FUNC(int, digest_get_params, (OSSL_PARAM params[])) + OSSL_CORE_MAKE_FUNC(int, digest_set_ctx_params, +diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c +index 168825d..3929f97 100644 +--- a/providers/implementations/digests/sha3_prov.c ++++ b/providers/implementations/digests/sha3_prov.c +@@ -32,6 +32,7 @@ static OSSL_FUNC_digest_init_fn keccak_init_params; + static OSSL_FUNC_digest_update_fn keccak_update; + static OSSL_FUNC_digest_final_fn keccak_final; + static OSSL_FUNC_digest_freectx_fn keccak_freectx; ++static OSSL_FUNC_digest_copyctx_fn keccak_copyctx; + static OSSL_FUNC_digest_dupctx_fn keccak_dupctx; + static OSSL_FUNC_digest_set_ctx_params_fn shake_set_ctx_params; + static OSSL_FUNC_digest_settable_ctx_params_fn shake_settable_ctx_params; +@@ -236,6 +237,7 @@ const OSSL_DISPATCH ossl_##name##_functions[] = { \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))keccak_final }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))keccak_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))keccak_dupctx }, \ ++ { OSSL_FUNC_DIGEST_COPYCTX, (void (*)(void))keccak_copyctx }, \ + PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) + + #define PROV_FUNC_SHA3_DIGEST(name, bitlen, blksize, dgstsize, flags) \ +@@ -258,6 +260,14 @@ static void keccak_freectx(void *vctx) + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } + ++static void keccak_copyctx(void *voutctx, void *vinctx) ++{ ++ KECCAK1600_CTX *outctx = (KECCAK1600_CTX *)voutctx; ++ KECCAK1600_CTX *inctx = (KECCAK1600_CTX *)vinctx; ++ ++ *outctx = *inctx; ++} ++ + static void *keccak_dupctx(void *ctx) + { + KECCAK1600_CTX *in = (KECCAK1600_CTX *)ctx; +diff --git a/providers/implementations/include/prov/digestcommon.h b/providers/implementations/include/prov/digestcommon.h +index abdb8bb..332d473 100644 +--- a/providers/implementations/include/prov/digestcommon.h ++++ b/providers/implementations/include/prov/digestcommon.h +@@ -70,6 +70,12 @@ static void *name##_dupctx(void *ctx) \ + *ret = *in; \ + return ret; \ + } \ ++static void name##_copyctx(void *voutctx, void *vinctx) \ ++{ \ ++ CTX *outctx = (CTX *)voutctx; \ ++ CTX *inctx = (CTX *)vinctx; \ ++ *outctx = *inctx; \ ++} \ + PROV_FUNC_DIGEST_FINAL(name, dgstsize, fin) \ + PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \ + const OSSL_DISPATCH ossl_##name##_functions[] = { \ +@@ -78,6 +84,7 @@ const OSSL_DISPATCH ossl_##name##_functions[] = { \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))name##_internal_final }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))name##_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))name##_dupctx }, \ ++ { OSSL_FUNC_DIGEST_COPYCTX, (void (*)(void))name##_copyctx }, \ + PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) + + # define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END \ +diff --git a/test/evp_extra_test2.c b/test/evp_extra_test2.c +index 68329b0..be7db00 100644 +--- a/test/evp_extra_test2.c ++++ b/test/evp_extra_test2.c +@@ -27,6 +27,8 @@ + + #include "testutil.h" + #include "internal/nelem.h" ++#include "crypto/evp.h" ++#include "../crypto/evp/evp_local.h" + + static OSSL_LIB_CTX *mainctx = NULL; + static OSSL_PROVIDER *nullprov = NULL; +@@ -1193,6 +1195,46 @@ static int test_evp_md_ctx_copy(void) + return ret; + } + ++static int test_evp_md_ctx_copy2(void) ++{ ++ int ret = 0; ++ EVP_MD *md = NULL; ++ OSSL_LIB_CTX *ctx = NULL; ++ EVP_MD_CTX *inctx = NULL, *outctx = NULL; ++ void *origin_algctx = NULL; ++ ++ if (!TEST_ptr(ctx = OSSL_LIB_CTX_new()) ++ || !TEST_ptr(md = EVP_MD_fetch(ctx, "sha256", NULL))) ++ goto end; ++ ++ inctx = EVP_MD_CTX_new(); ++ outctx = EVP_MD_CTX_new(); ++ ++ if (!TEST_ptr(inctx) || !TEST_ptr(outctx)) ++ goto end; ++ ++ /* init inctx and outctx, now the contexts are from same providers */ ++ if (!TEST_true(EVP_DigestInit_ex2(inctx, md, NULL))) ++ goto end; ++ if (!TEST_true(EVP_DigestInit_ex2(outctx, md, NULL))) ++ goto end; ++ ++ /* ++ * Test the EVP_MD_CTX_copy_ex function. After copying, ++ * outctx->algctx should be the same as the original. ++ */ ++ origin_algctx = outctx->algctx; ++ ret = TEST_true(EVP_MD_CTX_copy_ex(outctx, inctx)) ++ && TEST_true(outctx->algctx == origin_algctx); ++ ++end: ++ EVP_MD_free(md); ++ EVP_MD_CTX_free(inctx); ++ EVP_MD_CTX_free(outctx); ++ OSSL_LIB_CTX_free(ctx); ++ return ret; ++} ++ + #if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_MD5 + static int test_evp_pbe_alg_add(void) + { +@@ -1262,6 +1304,7 @@ int setup_tests(void) + ADD_ALL_TESTS(test_PEM_read_bio_negative_wrong_password, 2); + ADD_TEST(test_rsa_pss_sign); + ADD_TEST(test_evp_md_ctx_copy); ++ ADD_TEST(test_evp_md_ctx_copy2); + ADD_ALL_TESTS(test_provider_unload_effective, 2); + #if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_MD5 + ADD_TEST(test_evp_pbe_alg_add); +-- +2.33.0 + diff --git a/backport-Avoid-an-unneccessary-lock-if-we-didn-t-add-anything.patch b/backport-Avoid-an-unneccessary-lock-if-we-didn-t-add-anything.patch new file mode 100644 index 0000000000000000000000000000000000000000..4091f1595933058768b5e2e2891cca0247fcf5a2 --- /dev/null +++ b/backport-Avoid-an-unneccessary-lock-if-we-didn-t-add-anything.patch @@ -0,0 +1,47 @@ +From 00bea959ab580c78e00eb56780fec8d53dab054d Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Fri, 12 May 2023 15:52:07 +0100 +Subject: [PATCH] Avoid an unneccessary lock if we didn't add anything to the + store + +Partially fixes #20286 + +Reviewed-by: Tomas Mraz +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/20952) + +(cherry picked from commit 50001e0e15d4a96213c2eea7c56f80087afa89fd) +--- + crypto/x509/by_dir.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c +index 1bc397a847..97e6ea0ee1 100644 +--- a/crypto/x509/by_dir.c ++++ b/crypto/x509/by_dir.c +@@ -348,12 +348,16 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, + /* + * we have added it to the cache so now pull it out again + */ +- if (!X509_STORE_lock(xl->store_ctx)) +- goto finish; +- j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); +- tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); +- X509_STORE_unlock(xl->store_ctx); +- ++ if (k > 0) { ++ if (!X509_STORE_lock(xl->store_ctx)) ++ goto finish; ++ j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); ++ tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); ++ X509_STORE_unlock(xl->store_ctx); ++ } else { ++ j = -1; ++ tmp = NULL; ++ } + /* + * If a CRL, update the last file suffix added for this. + * We don't need to add an entry if k is 0 as this is the initial value. +-- +2.33.0 + diff --git a/backport-Decoder-resolution-performance-optimizations.patch b/backport-Decoder-resolution-performance-optimizations.patch new file mode 100644 index 0000000000000000000000000000000000000000..6932936280c6ead7a9df22cd5d3359be94e89dcc --- /dev/null +++ b/backport-Decoder-resolution-performance-optimizations.patch @@ -0,0 +1,566 @@ +From 4a1108eb5906cd3cf47a3f70bd58722dbe2023a4 Mon Sep 17 00:00:00 2001 +From: Hugo Landau +Date: Thu, 17 Mar 2022 17:29:22 +0000 +Subject: [PATCH] Decoder resolution performance optimizations + +This refactors decoder functionality to reduce calls to +OSSL_DECODER_is_a / EVP_KEYMGMT_is_a, which are substantial bottlenecks +in the performance of repeated decode operations (see #15199). + +Reviewed-by: Matt Caswell +Reviewed-by: Richard Levitte +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/17921) + +(cherry picked from commit 247554458435eaab175cdc9d36878158b9eb6f6e) +--- + crypto/encode_decode/decoder_lib.c | 20 +- + crypto/encode_decode/decoder_meth.c | 18 ++ + crypto/encode_decode/decoder_pkey.c | 323 +++++++++++++++------------ + crypto/encode_decode/encoder_local.h | 4 + + 4 files changed, 222 insertions(+), 143 deletions(-) + +diff --git a/crypto/encode_decode/decoder_lib.c b/crypto/encode_decode/decoder_lib.c +index 817f335453..8863c316d6 100644 +--- a/crypto/encode_decode/decoder_lib.c ++++ b/crypto/encode_decode/decoder_lib.c +@@ -18,6 +18,7 @@ + #include + #include "internal/bio.h" + #include "internal/provider.h" ++#include "internal/namemap.h" + #include "crypto/decoder.h" + #include "encoder_local.h" + #include "e_os.h" +@@ -241,6 +242,7 @@ OSSL_DECODER_INSTANCE *ossl_decoder_instance_new(OSSL_DECODER *decoder, + /* The "input" property is mandatory */ + prop = ossl_property_find_property(props, libctx, "input"); + decoder_inst->input_type = ossl_property_get_string_value(libctx, prop); ++ decoder_inst->input_type_id = 0; + if (decoder_inst->input_type == NULL) { + ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INVALID_PROPERTY_DEFINITION, + "the mandatory 'input' property is missing " +@@ -343,6 +345,8 @@ int OSSL_DECODER_CTX_add_decoder(OSSL_DECODER_CTX *ctx, OSSL_DECODER *decoder) + struct collect_extra_decoder_data_st { + OSSL_DECODER_CTX *ctx; + const char *output_type; ++ int output_type_id; ++ + /* + * 0 to check that the decoder's input type is the same as the decoder name + * 1 to check that the decoder's input type differs from the decoder name +@@ -370,7 +374,7 @@ static void collect_extra_decoder(OSSL_DECODER *decoder, void *arg) + const OSSL_PROVIDER *prov = OSSL_DECODER_get0_provider(decoder); + void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov); + +- if (OSSL_DECODER_is_a(decoder, data->output_type)) { ++ if (ossl_decoder_fast_is_a(decoder, data->output_type, &data->output_type_id)) { + void *decoderctx = NULL; + OSSL_DECODER_INSTANCE *di = NULL; + +@@ -413,8 +417,9 @@ static void collect_extra_decoder(OSSL_DECODER *decoder, void *arg) + switch (data->type_check) { + case IS_SAME: + /* If it differs, this is not a decoder to add for now. */ +- if (!OSSL_DECODER_is_a(decoder, +- OSSL_DECODER_INSTANCE_get_input_type(di))) { ++ if (!ossl_decoder_fast_is_a(decoder, ++ OSSL_DECODER_INSTANCE_get_input_type(di), ++ &di->input_type_id)) { + ossl_decoder_instance_free(di); + OSSL_TRACE_BEGIN(DECODER) { + BIO_printf(trc_out, +@@ -425,8 +430,9 @@ static void collect_extra_decoder(OSSL_DECODER *decoder, void *arg) + break; + case IS_DIFFERENT: + /* If it's the same, this is not a decoder to add for now. */ +- if (OSSL_DECODER_is_a(decoder, +- OSSL_DECODER_INSTANCE_get_input_type(di))) { ++ if (ossl_decoder_fast_is_a(decoder, ++ OSSL_DECODER_INSTANCE_get_input_type(di), ++ &di->input_type_id)) { + ossl_decoder_instance_free(di); + OSSL_TRACE_BEGIN(DECODER) { + BIO_printf(trc_out, +@@ -534,6 +540,7 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx, + data.output_type + = OSSL_DECODER_INSTANCE_get_input_type(decoder_inst); + ++ data.output_type_id = 0; + + for (j = 0; j < numdecoders; j++) + collect_extra_decoder(sk_OSSL_DECODER_value(skdecoders, j), +@@ -867,7 +874,8 @@ static int decoder_process(const OSSL_PARAM params[], void *arg) + * |new_input_type| holds the value of the "input-type" parameter + * for the decoder we're currently considering. + */ +- if (decoder != NULL && !OSSL_DECODER_is_a(decoder, new_input_type)) { ++ if (decoder != NULL && !ossl_decoder_fast_is_a(decoder, new_input_type, ++ &new_decoder_inst->input_type_id)) { + OSSL_TRACE_BEGIN(DECODER) { + BIO_printf(trc_out, + "(ctx %p) %s [%u] the input type doesn't match the name of the previous decoder (%p), skipping...\n", +diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c +index 56899a9269..496fbe3320 100644 +--- a/crypto/encode_decode/decoder_meth.c ++++ b/crypto/encode_decode/decoder_meth.c +@@ -558,6 +558,24 @@ int OSSL_DECODER_is_a(const OSSL_DECODER *decoder, const char *name) + return 0; + } + ++static int resolve_name(OSSL_DECODER *decoder, const char *name) ++{ ++ OSSL_LIB_CTX *libctx = ossl_provider_libctx(decoder->base.prov); ++ OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); ++ ++ return ossl_namemap_name2num(namemap, name); ++} ++ ++int ossl_decoder_fast_is_a(OSSL_DECODER *decoder, const char *name, int *id_cache) ++{ ++ int id = *id_cache; ++ ++ if (id <= 0) ++ *id_cache = id = resolve_name(decoder, name); ++ ++ return id > 0 && ossl_decoder_get_number(decoder) == id; ++} ++ + struct do_one_data_st { + void (*user_fn)(OSSL_DECODER *decoder, void *arg); + void *user_arg; +diff --git a/crypto/encode_decode/decoder_pkey.c b/crypto/encode_decode/decoder_pkey.c +index ed10bb1cee..00d3d48420 100644 +--- a/crypto/encode_decode/decoder_pkey.c ++++ b/crypto/encode_decode/decoder_pkey.c +@@ -17,7 +17,9 @@ + #include + #include "crypto/evp.h" + #include "crypto/decoder.h" ++#include "crypto/evp/evp_local.h" + #include "encoder_local.h" ++#include "internal/namemap.h" + + int OSSL_DECODER_CTX_set_passphrase(OSSL_DECODER_CTX *ctx, + const unsigned char *kstr, +@@ -195,53 +197,83 @@ static void decoder_clean_pkey_construct_arg(void *construct_data) + } + } + +-static void collect_name(const char *name, void *arg) +-{ +- STACK_OF(OPENSSL_CSTRING) *names = arg; ++struct collect_data_st { ++ OSSL_LIB_CTX *libctx; ++ OSSL_DECODER_CTX *ctx; + +- sk_OPENSSL_CSTRING_push(names, name); +-} ++ const char *keytype; /* the keytype requested, if any */ ++ int keytype_id; /* if keytype_resolved is set, keymgmt name_id; else 0 */ ++ int sm2_id; /* if keytype_resolved is set and EC, SM2 name_id; else 0 */ ++ int total; /* number of matching results */ ++ char error_occurred; ++ char keytype_resolved; + +-static void collect_keymgmt(EVP_KEYMGMT *keymgmt, void *arg) ++ STACK_OF(EVP_KEYMGMT) *keymgmts; ++}; ++ ++static void collect_decoder_keymgmt(EVP_KEYMGMT *keymgmt, OSSL_DECODER *decoder, ++ void *provctx, struct collect_data_st *data) + { +- STACK_OF(EVP_KEYMGMT) *keymgmts = arg; ++ void *decoderctx = NULL; ++ OSSL_DECODER_INSTANCE *di = NULL; ++ ++ /* ++ * We already checked the EVP_KEYMGMT is applicable in check_keymgmt so we ++ * don't check it again here. ++ */ + +- if (!EVP_KEYMGMT_up_ref(keymgmt) /* ref++ */) ++ if (keymgmt->name_id != decoder->base.id) ++ /* Mismatch is not an error, continue. */ + return; +- if (sk_EVP_KEYMGMT_push(keymgmts, keymgmt) <= 0) { +- EVP_KEYMGMT_free(keymgmt); /* ref-- */ ++ ++ if ((decoderctx = decoder->newctx(provctx)) == NULL) { ++ data->error_occurred = 1; + return; + } +-} + +-struct collect_decoder_data_st { +- STACK_OF(OPENSSL_CSTRING) *names; +- OSSL_DECODER_CTX *ctx; ++ if ((di = ossl_decoder_instance_new(decoder, decoderctx)) == NULL) { ++ decoder->freectx(decoderctx); ++ data->error_occurred = 1; ++ return; ++ } + +- int total; +- unsigned int error_occurred:1; +-}; ++ OSSL_TRACE_BEGIN(DECODER) { ++ BIO_printf(trc_out, ++ "(ctx %p) Checking out decoder %p:\n" ++ " %s with %s\n", ++ (void *)data->ctx, (void *)decoder, ++ OSSL_DECODER_get0_name(decoder), ++ OSSL_DECODER_get0_properties(decoder)); ++ } OSSL_TRACE_END(DECODER); ++ ++ if (!ossl_decoder_ctx_add_decoder_inst(data->ctx, di)) { ++ ossl_decoder_instance_free(di); ++ data->error_occurred = 1; ++ return; ++ } ++ ++ ++data->total; ++} + + static void collect_decoder(OSSL_DECODER *decoder, void *arg) + { +- struct collect_decoder_data_st *data = arg; ++ struct collect_data_st *data = arg; ++ STACK_OF(EVP_KEYMGMT) *keymgmts = data->keymgmts; + size_t i, end_i; +- const OSSL_PROVIDER *prov = OSSL_DECODER_get0_provider(decoder); +- void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov); ++ EVP_KEYMGMT *keymgmt; ++ const OSSL_PROVIDER *prov; ++ void *provctx; + + if (data->error_occurred) + return; + +- if (data->names == NULL) { +- data->error_occurred = 1; +- return; +- } ++ prov = OSSL_DECODER_get0_provider(decoder); ++ provctx = OSSL_PROVIDER_get0_provider_ctx(prov); + + /* +- * Either the caller didn't give a selection, or if they did, +- * the decoder must tell us if it supports that selection to +- * be accepted. If the decoder doesn't have |does_selection|, +- * it's seen as taking anything. ++ * Either the caller didn't give us a selection, or if they did, the decoder ++ * must tell us if it supports that selection to be accepted. If the decoder ++ * doesn't have |does_selection|, it's seen as taking anything. + */ + if (decoder->does_selection != NULL + && !decoder->does_selection(provctx, data->ctx->selection)) +@@ -256,68 +288,101 @@ static void collect_decoder(OSSL_DECODER *decoder, void *arg) + OSSL_DECODER_get0_properties(decoder)); + } OSSL_TRACE_END(DECODER); + +- end_i = sk_OPENSSL_CSTRING_num(data->names); +- for (i = 0; i < end_i; i++) { +- const char *name = sk_OPENSSL_CSTRING_value(data->names, i); +- +- if (OSSL_DECODER_is_a(decoder, name)) { +- void *decoderctx = NULL; +- OSSL_DECODER_INSTANCE *di = NULL; +- +- if ((decoderctx = decoder->newctx(provctx)) == NULL) { +- data->error_occurred = 1; +- return; +- } +- if ((di = ossl_decoder_instance_new(decoder, decoderctx)) == NULL) { +- decoder->freectx(decoderctx); +- data->error_occurred = 1; +- return; +- } +- +- OSSL_TRACE_BEGIN(DECODER) { +- BIO_printf(trc_out, +- "(ctx %p) Checking out decoder %p:\n" +- " %s with %s\n", +- (void *)data->ctx, (void *)decoder, +- OSSL_DECODER_get0_name(decoder), +- OSSL_DECODER_get0_properties(decoder)); +- } OSSL_TRACE_END(DECODER); +- +- if (!ossl_decoder_ctx_add_decoder_inst(data->ctx, di)) { +- ossl_decoder_instance_free(di); +- data->error_occurred = 1; +- return; +- } +- data->total++; +- +- /* Success */ ++ end_i = sk_EVP_KEYMGMT_num(keymgmts); ++ for (i = 0; i < end_i; ++i) { ++ keymgmt = sk_EVP_KEYMGMT_value(keymgmts, i); ++ ++ collect_decoder_keymgmt(keymgmt, decoder, provctx, data); ++ if (data->error_occurred) + return; +- } ++ } ++} ++ ++/* ++ * Is this EVP_KEYMGMT applicable given the key type given in the call to ++ * ossl_decoder_ctx_setup_for_pkey (if any)? ++ */ ++static int check_keymgmt(EVP_KEYMGMT *keymgmt, struct collect_data_st *data) ++{ ++ /* If no keytype was specified, everything matches. */ ++ if (data->keytype == NULL) ++ return 1; ++ ++ if (!data->keytype_resolved) { ++ /* We haven't cached the IDs from the keytype string yet. */ ++ OSSL_NAMEMAP *namemap = ossl_namemap_stored(data->libctx); ++ data->keytype_id = ossl_namemap_name2num(namemap, data->keytype); ++ ++ /* ++ * If keytype is a value ambiguously used for both EC and SM2, ++ * collect the ID for SM2 as well. ++ */ ++ if (data->keytype_id != 0 ++ && (strcmp(data->keytype, "id-ecPublicKey") == 0 ++ || strcmp(data->keytype, "1.2.840.10045.2.1") == 0)) ++ data->sm2_id = ossl_namemap_name2num(namemap, "SM2"); ++ ++ /* ++ * If keytype_id is zero the name was not found, but we still ++ * set keytype_resolved to avoid trying all this again. ++ */ ++ data->keytype_resolved = 1; + } + +- /* Decoder not suitable - but not a fatal error */ +- data->error_occurred = 0; ++ /* Specified keytype could not be resolved, so nothing matches. */ ++ if (data->keytype_id == 0) ++ return 0; ++ ++ /* Does not match the keytype specified, so skip. */ ++ if (keymgmt->name_id != data->keytype_id ++ && keymgmt->name_id != data->sm2_id) ++ return 0; ++ ++ return 1; + } + ++static void collect_keymgmt(EVP_KEYMGMT *keymgmt, void *arg) ++{ ++ struct collect_data_st *data = arg; ++ ++ if (!check_keymgmt(keymgmt, data)) ++ return; ++ ++ /* ++ * We have to ref EVP_KEYMGMT here because in the success case, ++ * data->keymgmts is referenced by the constructor we register in the ++ * OSSL_DECODER_CTX. The registered cleanup function ++ * (decoder_clean_pkey_construct_arg) unrefs every element of the stack and ++ * frees it. ++ */ ++ if (!EVP_KEYMGMT_up_ref(keymgmt)) ++ return; ++ ++ if (sk_EVP_KEYMGMT_push(data->keymgmts, keymgmt) <= 0) { ++ EVP_KEYMGMT_free(keymgmt); ++ data->error_occurred = 1; ++ } ++} ++ ++/* ++ * This function does the actual binding of decoders to the OSSL_DECODER_CTX. It ++ * searches for decoders matching 'keytype', which is a string like "RSA", "DH", ++ * etc. If 'keytype' is NULL, decoders for all keytypes are bound. ++ */ + int ossl_decoder_ctx_setup_for_pkey(OSSL_DECODER_CTX *ctx, + EVP_PKEY **pkey, const char *keytype, + OSSL_LIB_CTX *libctx, + const char *propquery) + { +- struct decoder_pkey_data_st *process_data = NULL; +- STACK_OF(OPENSSL_CSTRING) *names = NULL; +- const char *input_type = ctx->start_input_type; +- const char *input_structure = ctx->input_structure; + int ok = 0; +- int isecoid = 0; +- int i, end; +- +- if (keytype != NULL +- && (strcmp(keytype, "id-ecPublicKey") == 0 +- || strcmp(keytype, "1.2.840.10045.2.1") == 0)) +- isecoid = 1; ++ struct decoder_pkey_data_st *process_data = NULL; ++ struct collect_data_st collect_data = { NULL }; ++ STACK_OF(EVP_KEYMGMT) *keymgmts = NULL; + + OSSL_TRACE_BEGIN(DECODER) { ++ const char *input_type = ctx->start_input_type; ++ const char *input_structure = ctx->input_structure; ++ + BIO_printf(trc_out, + "(ctx %p) Looking for decoders producing %s%s%s%s%s%s\n", + (void *)ctx, +@@ -329,81 +394,67 @@ int ossl_decoder_ctx_setup_for_pkey(OSSL_DECODER_CTX *ctx, + input_structure != NULL ? input_structure : ""); + } OSSL_TRACE_END(DECODER); + ++ /* Allocate data. */ + if ((process_data = OPENSSL_zalloc(sizeof(*process_data))) == NULL + || (propquery != NULL +- && (process_data->propq = OPENSSL_strdup(propquery)) == NULL) +- || (process_data->keymgmts = sk_EVP_KEYMGMT_new_null()) == NULL +- || (names = sk_OPENSSL_CSTRING_new_null()) == NULL) { ++ && (process_data->propq = OPENSSL_strdup(propquery)) == NULL)) { + ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE); + goto err; + } + +- process_data->object = (void **)pkey; +- process_data->libctx = libctx; ++ /* Allocate our list of EVP_KEYMGMTs. */ ++ keymgmts = sk_EVP_KEYMGMT_new_null(); ++ if (keymgmts == NULL) { ++ ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE); ++ goto err; ++ } ++ ++ process_data->object = (void **)pkey; ++ process_data->libctx = libctx; + process_data->selection = ctx->selection; ++ process_data->keymgmts = keymgmts; + +- /* First, find all keymgmts to form goals */ +- EVP_KEYMGMT_do_all_provided(libctx, collect_keymgmt, +- process_data->keymgmts); ++ /* ++ * Enumerate all keymgmts into a stack. ++ * ++ * We could nest EVP_KEYMGMT_do_all_provided inside ++ * OSSL_DECODER_do_all_provided or vice versa but these functions become ++ * bottlenecks if called repeatedly, which is why we collect the ++ * EVP_KEYMGMTs into a stack here and call both functions only once. ++ * ++ * We resolve the keytype string to a name ID so we don't have to resolve it ++ * multiple times, avoiding repeated calls to EVP_KEYMGMT_is_a, which is a ++ * performance bottleneck. However, we do this lazily on the first call to ++ * collect_keymgmt made by EVP_KEYMGMT_do_all_provided, rather than do it ++ * upfront, as this ensures that the names for all loaded providers have ++ * been registered by the time we try to resolve the keytype string. ++ */ ++ collect_data.ctx = ctx; ++ collect_data.libctx = libctx; ++ collect_data.keymgmts = keymgmts; ++ collect_data.keytype = keytype; ++ EVP_KEYMGMT_do_all_provided(libctx, collect_keymgmt, &collect_data); + +- /* Then, we collect all the keymgmt names */ +- end = sk_EVP_KEYMGMT_num(process_data->keymgmts); +- for (i = 0; i < end; i++) { +- EVP_KEYMGMT *keymgmt = sk_EVP_KEYMGMT_value(process_data->keymgmts, i); ++ if (collect_data.error_occurred) ++ goto err; + +- /* +- * If the key type is given by the caller, we only use the matching +- * KEYMGMTs, otherwise we use them all. +- * We have to special case SM2 here because of its abuse of the EC OID. +- * The EC OID can be used to identify an EC key or an SM2 key - so if +- * we have seen that OID we try both key types +- */ +- if (keytype == NULL +- || EVP_KEYMGMT_is_a(keymgmt, keytype) +- || (isecoid && EVP_KEYMGMT_is_a(keymgmt, "SM2"))) { +- if (!EVP_KEYMGMT_names_do_all(keymgmt, collect_name, names)) { +- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR); +- goto err; +- } +- } +- } ++ /* Enumerate all matching decoders. */ ++ OSSL_DECODER_do_all_provided(libctx, collect_decoder, &collect_data); ++ ++ if (collect_data.error_occurred) ++ goto err; + + OSSL_TRACE_BEGIN(DECODER) { +- end = sk_OPENSSL_CSTRING_num(names); + BIO_printf(trc_out, +- " Found %d keytypes (possibly with duplicates)", +- end); +- for (i = 0; i < end; i++) +- BIO_printf(trc_out, "%s%s", +- i == 0 ? ": " : ", ", +- sk_OPENSSL_CSTRING_value(names, i)); +- BIO_printf(trc_out, "\n"); ++ "(ctx %p) Got %d decoders producing keys\n", ++ (void *)ctx, collect_data.total); + } OSSL_TRACE_END(DECODER); + + /* +- * Finally, find all decoders that have any keymgmt of the collected +- * keymgmt names ++ * Finish initializing the decoder context. If one or more decoders matched ++ * above then the number of decoders attached to the OSSL_DECODER_CTX will ++ * be nonzero. Else nothing was found and we do nothing. + */ +- { +- struct collect_decoder_data_st collect_decoder_data = { NULL, }; +- +- collect_decoder_data.names = names; +- collect_decoder_data.ctx = ctx; +- OSSL_DECODER_do_all_provided(libctx, +- collect_decoder, &collect_decoder_data); +- sk_OPENSSL_CSTRING_free(names); +- names = NULL; +- +- if (collect_decoder_data.error_occurred) +- goto err; +- +- OSSL_TRACE_BEGIN(DECODER) { +- BIO_printf(trc_out, +- "(ctx %p) Got %d decoders producing keys\n", +- (void *)ctx, collect_decoder_data.total); +- } OSSL_TRACE_END(DECODER); +- } +- + if (OSSL_DECODER_CTX_get_num_decoders(ctx) != 0) { + if (!OSSL_DECODER_CTX_set_construct(ctx, decoder_construct_pkey) + || !OSSL_DECODER_CTX_set_construct_data(ctx, process_data) +@@ -417,8 +468,6 @@ int ossl_decoder_ctx_setup_for_pkey(OSSL_DECODER_CTX *ctx, + ok = 1; + err: + decoder_clean_pkey_construct_arg(process_data); +- sk_OPENSSL_CSTRING_free(names); +- + return ok; + } + +diff --git a/crypto/encode_decode/encoder_local.h b/crypto/encode_decode/encoder_local.h +index c1885ffc77..939e831727 100644 +--- a/crypto/encode_decode/encoder_local.h ++++ b/crypto/encode_decode/encoder_local.h +@@ -108,6 +108,7 @@ struct ossl_decoder_instance_st { + void *decoderctx; /* Never NULL */ + const char *input_type; /* Never NULL */ + const char *input_structure; /* May be NULL */ ++ int input_type_id; + + unsigned int flag_input_structure_was_set : 1; + }; +@@ -162,3 +163,6 @@ const OSSL_PROPERTY_LIST * + ossl_decoder_parsed_properties(const OSSL_DECODER *decoder); + const OSSL_PROPERTY_LIST * + ossl_encoder_parsed_properties(const OSSL_ENCODER *encoder); ++ ++int ossl_decoder_fast_is_a(OSSL_DECODER *decoder, ++ const char *name, int *id_cache); +-- +2.33.0 + diff --git a/backport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch b/backport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch new file mode 100644 index 0000000000000000000000000000000000000000..cde3676258fdf933c7e87900efe64639b8e45200 --- /dev/null +++ b/backport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch @@ -0,0 +1,275 @@ +From fca5d6a2b76d0c1f20e63cec5ac1b927eeba7b43 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Thu, 19 May 2022 11:38:23 +0200 +Subject: [PATCH] Drop ossl_namemap_add_name_n() and simplify + ossl_namemap_add_names() + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/18341) + +(cherry picked from commit b00cf0e790661636e1df1026554f712cc513592d) +--- + crypto/core_namemap.c | 96 +++++++++++--------------- + doc/internal/man3/ossl_namemap_new.pod | 15 ++-- + include/internal/namemap.h | 2 - + 3 files changed, 48 insertions(+), 65 deletions(-) + +diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c +index 4c1ca05308..380f4da9c2 100644 +--- a/crypto/core_namemap.c ++++ b/crypto/core_namemap.c +@@ -166,6 +166,7 @@ int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number, + return 1; + } + ++/* This function is not thread safe, the namemap must be locked */ + static int namemap_name2num(const OSSL_NAMEMAP *namemap, + const char *name) + { +@@ -239,25 +240,22 @@ const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number, + return data.name; + } + +-static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len) ++/* This function is not thread safe, the namemap must be locked */ ++static int namemap_add_name(OSSL_NAMEMAP *namemap, int number, ++ const char *name) + { + NAMENUM_ENTRY *namenum = NULL; + int tmp_number; +- char *tmp = OPENSSL_strndup(name, name_len); +- +- if (tmp == NULL) +- return 0; + + /* If it already exists, we don't add it */ +- if ((tmp_number = namemap_name2num(namemap, tmp)) != 0) { +- OPENSSL_free(tmp); ++ if ((tmp_number = namemap_name2num(namemap, name)) != 0) + return tmp_number; +- } + + if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL) ++ return 0; ++ ++ if ((namenum->name = OPENSSL_strdup(name)) == NULL) + goto err; +- namenum->name = tmp; + + /* The tsan_counter use here is safe since we're under lock */ + namenum->number = +@@ -269,13 +267,12 @@ static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + return namenum->number; + + err: +- OPENSSL_free(tmp); +- OPENSSL_free(namenum); ++ namenum_free(namenum); + return 0; + } + +-int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len) ++int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, ++ const char *name) + { + int tmp_number; + +@@ -284,29 +281,20 @@ int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + namemap = ossl_namemap_stored(NULL); + #endif + +- if (name == NULL || name_len == 0 || namemap == NULL) ++ if (name == NULL || *name == 0 || namemap == NULL) + return 0; + + if (!CRYPTO_THREAD_write_lock(namemap->lock)) + return 0; +- tmp_number = namemap_add_name_n(namemap, number, name, name_len); ++ tmp_number = namemap_add_name(namemap, number, name); + CRYPTO_THREAD_unlock(namemap->lock); + return tmp_number; + } + +-int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name) +-{ +- if (name == NULL) +- return 0; +- +- return ossl_namemap_add_name_n(namemap, number, name, strlen(name)); +-} +- + int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, + const char *names, const char separator) + { +- const char *p, *q; +- size_t l; ++ char *tmp, *p, *q, *endp; + + /* Check that we have a namemap */ + if (!ossl_assert(namemap != NULL)) { +@@ -314,71 +302,71 @@ int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, + return 0; + } + +- if (!CRYPTO_THREAD_write_lock(namemap->lock)) ++ if ((tmp = OPENSSL_strdup(names)) == NULL) + return 0; ++ ++ if (!CRYPTO_THREAD_write_lock(namemap->lock)) { ++ OPENSSL_free(tmp); ++ return 0; ++ } + /* + * Check that no name is an empty string, and that all names have at + * most one numeric identity together. + */ +- for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { ++ for (p = tmp; *p != '\0'; p = q) { + int this_number; +- char *allocated; +- const char *tmp; ++ size_t l; + + if ((q = strchr(p, separator)) == NULL) { + l = strlen(p); /* offset to \0 */ +- tmp = p; +- allocated = NULL; ++ q = p + l; + } else { + l = q - p; /* offset to the next separator */ +- tmp = allocated = OPENSSL_strndup(p, l); +- if (tmp == NULL) +- goto err; ++ *q++ = '\0'; + } + +- this_number = namemap_name2num(namemap, tmp); +- OPENSSL_free(allocated); +- +- if (*p == '\0' || *p == separator) { ++ if (*p == '\0') { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME); +- goto err; ++ number = 0; ++ goto end; + } ++ ++ this_number = namemap_name2num(namemap, p); ++ + if (number == 0) { + number = this_number; + } else if (this_number != 0 && this_number != number) { + ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES, +- "\"%.*s\" has an existing different identity %d (from \"%s\")", +- l, p, this_number, names); +- goto err; ++ "\"%s\" has an existing different identity %d (from \"%s\")", ++ p, this_number, names); ++ number = 0; ++ goto end; + } + } ++ endp = p; + + /* Now that we have checked, register all names */ +- for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { ++ for (p = tmp; p < endp; p = q) { + int this_number; + +- if ((q = strchr(p, separator)) == NULL) +- l = strlen(p); /* offset to \0 */ +- else +- l = q - p; /* offset to the next separator */ ++ q = p + strlen(p) + 1; + +- this_number = namemap_add_name_n(namemap, number, p, l); ++ this_number = namemap_add_name(namemap, number, p); + if (number == 0) { + number = this_number; + } else if (this_number != number) { + ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, + "Got number %d when expecting %d", + this_number, number); +- goto err; ++ number = 0; ++ goto end; + } + } + ++ end: + CRYPTO_THREAD_unlock(namemap->lock); ++ OPENSSL_free(tmp); + return number; +- +- err: +- CRYPTO_THREAD_unlock(namemap->lock); +- return 0; + } + + /*- +diff --git a/doc/internal/man3/ossl_namemap_new.pod b/doc/internal/man3/ossl_namemap_new.pod +index ff247e87b0..7f4940fc93 100644 +--- a/doc/internal/man3/ossl_namemap_new.pod ++++ b/doc/internal/man3/ossl_namemap_new.pod +@@ -3,7 +3,7 @@ + =head1 NAME + + ossl_namemap_new, ossl_namemap_free, ossl_namemap_stored, ossl_namemap_empty, +-ossl_namemap_add_name, ossl_namemap_add_name_n, ossl_namemap_add_names, ++ossl_namemap_add_name, ossl_namemap_add_names, + ossl_namemap_name2num, ossl_namemap_name2num_n, + ossl_namemap_doall_names + - internal number E-E name map +@@ -19,8 +19,6 @@ ossl_namemap_doall_names + int ossl_namemap_empty(OSSL_NAMEMAP *namemap); + + int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name); +- int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len); + + int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name); + int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, +@@ -62,10 +60,9 @@ names already associated with that number. + ossl_namemap_name2num() finds the number corresponding to the given + I. + +-ossl_namemap_add_name_n() and ossl_namemap_name2num_n() do the same thing +-as ossl_namemap_add_name() and ossl_namemap_name2num(), but take a string +-length I as well, allowing the caller to use a fragment of +-a string as a name. ++ossl_namemap_name2num_n() does the same thing as ++ossl_namemap_name2num(), but takes a string length I as well, ++allowing the caller to use a fragment of a string as a name. + + ossl_namemap_doall_names() walks through all names associated with + I in the given I and calls the function I for +@@ -88,8 +85,8 @@ ossl_namemap_empty() returns 1 if the B is NULL or + empty, 0 if it's not empty, or -1 on internal error (such as inability + to lock). + +-ossl_namemap_add_name() and ossl_namemap_add_name_n() return the number +-associated with the added string, or zero on error. ++ossl_namemap_add_name() returns the number associated with the added ++string, or zero on error. + + ossl_namemap_num2names() returns a pointer to a NULL-terminated list of + pointers to the names corresponding to the given number, or NULL if +diff --git a/include/internal/namemap.h b/include/internal/namemap.h +index a4c60ae695..6c42a9cd7c 100644 +--- a/include/internal/namemap.h ++++ b/include/internal/namemap.h +@@ -18,8 +18,6 @@ void ossl_namemap_free(OSSL_NAMEMAP *namemap); + int ossl_namemap_empty(OSSL_NAMEMAP *namemap); + + int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name); +-int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len); + + /* + * The number<->name relationship is 1<->many +-- +2.33.0 + diff --git a/backport-Improve-performance-of-the-encoder-collection.patch b/backport-Improve-performance-of-the-encoder-collection.patch new file mode 100644 index 0000000000000000000000000000000000000000..301921e1038b3e22be51cec08eabdfa9eb6d8026 --- /dev/null +++ b/backport-Improve-performance-of-the-encoder-collection.patch @@ -0,0 +1,153 @@ +From 762473f53a0cf319e511895556a6df0e3fbb3f9e Mon Sep 17 00:00:00 2001 +From: slontis +Date: Wed, 5 Oct 2022 09:57:51 +1000 +Subject: [PATCH] Improve performance of the encoder collection + +Reviewed-by: Richard Levitte +Reviewed-by: Tomas Mraz +Reviewed-by: Paul Dale +Reviewed-by: Hugo Landau +(Merged from https://github.com/openssl/openssl/pull/19344) + +(cherry picked from commit c3b46409559c18f103ebb2221c6f8af3cd7db00d) +--- + crypto/encode_decode/encoder_pkey.c | 80 ++++++++++++++++++----------- + 1 file changed, 51 insertions(+), 29 deletions(-) + +diff --git a/crypto/encode_decode/encoder_pkey.c b/crypto/encode_decode/encoder_pkey.c +index 3a24317cf4..f8a5a45acc 100644 +--- a/crypto/encode_decode/encoder_pkey.c ++++ b/crypto/encode_decode/encoder_pkey.c +@@ -17,6 +17,7 @@ + #include + #include "internal/provider.h" + #include "internal/property.h" ++#include "internal/namemap.h" + #include "crypto/evp.h" + #include "encoder_local.h" + +@@ -72,6 +73,7 @@ int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx, + + struct collected_encoder_st { + STACK_OF(OPENSSL_CSTRING) *names; ++ int *id_names; + const char *output_structure; + const char *output_type; + +@@ -85,41 +87,41 @@ struct collected_encoder_st { + static void collect_encoder(OSSL_ENCODER *encoder, void *arg) + { + struct collected_encoder_st *data = arg; +- size_t i, end_i; ++ const OSSL_PROVIDER *prov; + + if (data->error_occurred) + return; + + data->error_occurred = 1; /* Assume the worst */ + +- if (data->names == NULL) +- return; +- +- end_i = sk_OPENSSL_CSTRING_num(data->names); +- for (i = 0; i < end_i; i++) { +- const char *name = sk_OPENSSL_CSTRING_value(data->names, i); +- const OSSL_PROVIDER *prov = OSSL_ENCODER_get0_provider(encoder); ++ prov = OSSL_ENCODER_get0_provider(encoder); ++ /* ++ * collect_encoder() is called in two passes, one where the encoders ++ * from the same provider as the keymgmt are looked up, and one where ++ * the other encoders are looked up. |data->flag_find_same_provider| ++ * tells us which pass we're in. ++ */ ++ if ((data->keymgmt_prov == prov) == data->flag_find_same_provider) { + void *provctx = OSSL_PROVIDER_get0_provider_ctx(prov); +- +- /* +- * collect_encoder() is called in two passes, one where the encoders +- * from the same provider as the keymgmt are looked up, and one where +- * the other encoders are looked up. |data->flag_find_same_provider| +- * tells us which pass we're in. +- */ +- if ((data->keymgmt_prov == prov) != data->flag_find_same_provider) +- continue; +- +- if (!OSSL_ENCODER_is_a(encoder, name) +- || (encoder->does_selection != NULL +- && !encoder->does_selection(provctx, data->ctx->selection)) +- || (data->keymgmt_prov != prov +- && encoder->import_object == NULL)) +- continue; +- +- /* Only add each encoder implementation once */ +- if (OSSL_ENCODER_CTX_add_encoder(data->ctx, encoder)) +- break; ++ size_t i, end_i = sk_OPENSSL_CSTRING_num(data->names); ++ int match; ++ ++ for (i = 0; i < end_i; i++) { ++ if (data->flag_find_same_provider) ++ match = (data->id_names[i] == encoder->base.id); ++ else ++ match = OSSL_ENCODER_is_a(encoder, sk_OPENSSL_CSTRING_value(data->names, i)); ++ if (!match ++ || (encoder->does_selection != NULL ++ && !encoder->does_selection(provctx, data->ctx->selection)) ++ || (data->keymgmt_prov != prov ++ && encoder->import_object == NULL)) ++ continue; ++ ++ /* Only add each encoder implementation once */ ++ if (OSSL_ENCODER_CTX_add_encoder(data->ctx, encoder)) ++ break; ++ } + } + + data->error_occurred = 0; /* All is good now */ +@@ -227,7 +229,8 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx, + struct construct_data_st *data = NULL; + const OSSL_PROVIDER *prov = NULL; + OSSL_LIB_CTX *libctx = NULL; +- int ok = 0; ++ int ok = 0, i, end; ++ OSSL_NAMEMAP *namemap; + + if (!ossl_assert(ctx != NULL) || !ossl_assert(pkey != NULL)) { + ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER); +@@ -271,7 +274,25 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx, + encoder_data.error_occurred = 0; + encoder_data.keymgmt_prov = prov; + encoder_data.ctx = ctx; ++ encoder_data.id_names = NULL; + ++ /* ++ * collect_encoder() is called many times, and for every call it converts all encoder_data.names ++ * into namemap ids if it calls OSSL_ENCODER_is_a(). We cache the ids here instead, ++ * and can use them for encoders with the same provider as the keymgmt. ++ */ ++ namemap = ossl_namemap_stored(libctx); ++ end = sk_OPENSSL_CSTRING_num(encoder_data.names); ++ if (end > 0) { ++ encoder_data.id_names = OPENSSL_malloc(end * sizeof(int)); ++ if (encoder_data.id_names == NULL) ++ goto err; ++ for (i = 0; i < end; ++i) { ++ const char *name = sk_OPENSSL_CSTRING_value(keymgmt_data.names, i); ++ ++ encoder_data.id_names[i] = ossl_namemap_name2num(namemap, name); ++ } ++ } + /* + * Place the encoders with the a different provider as the keymgmt + * last (the chain is processed in reverse order) +@@ -286,6 +307,7 @@ static int ossl_encoder_ctx_setup_for_pkey(OSSL_ENCODER_CTX *ctx, + encoder_data.flag_find_same_provider = 1; + OSSL_ENCODER_do_all_provided(libctx, collect_encoder, &encoder_data); + ++ OPENSSL_free(encoder_data.id_names); + sk_OPENSSL_CSTRING_free(keymgmt_data.names); + if (encoder_data.error_occurred) { + ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE); +-- +2.33.0 + diff --git a/backport-Make-IV-buf-in-prov_cipher_ctx_st-aligned.patch b/backport-Make-IV-buf-in-prov_cipher_ctx_st-aligned.patch new file mode 100644 index 0000000000000000000000000000000000000000..2291107bb57de545b56e1dae08e35de2f59649dd --- /dev/null +++ b/backport-Make-IV-buf-in-prov_cipher_ctx_st-aligned.patch @@ -0,0 +1,62 @@ +From a91c268853c4bda825a505629a873e21685490bf Mon Sep 17 00:00:00 2001 +From: "Hongren (Zenithal) Zheng" +Date: Mon, 9 May 2022 19:42:39 +0800 +Subject: [PATCH] Make IV/buf in prov_cipher_ctx_st aligned + +Make IV/buf aligned will drastically improve performance +as some architecture performs badly on misaligned memory +access. + +Ref to +https://gist.github.com/ZenithalHourlyRate/7b5175734f87acb73d0bbc53391d7140#file-2-openssl-long-md +Ref to +openssl#18197 + +Signed-off-by: Hongren (Zenithal) Zheng + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz + +(cherry picked from commit 2787a709c984d3884e1726383c2f2afca428d795) + +Reviewed-by: Neil Horman +Reviewed-by: Matt Caswell +(Merged from https://github.com/openssl/openssl/pull/23463) +--- + .../implementations/include/prov/ciphercommon.h | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/providers/implementations/include/prov/ciphercommon.h b/providers/implementations/include/prov/ciphercommon.h +index 383b759304..7f9a4a3bf2 100644 +--- a/providers/implementations/include/prov/ciphercommon.h ++++ b/providers/implementations/include/prov/ciphercommon.h +@@ -42,6 +42,13 @@ typedef int (PROV_CIPHER_HW_FN)(PROV_CIPHER_CTX *dat, unsigned char *out, + #define PROV_CIPHER_FLAG_INVERSE_CIPHER 0x0200 + + struct prov_cipher_ctx_st { ++ /* place buffer at the beginning for memory alignment */ ++ /* The original value of the iv */ ++ unsigned char oiv[GENERIC_BLOCK_SIZE]; ++ /* Buffer of partial blocks processed via update calls */ ++ unsigned char buf[GENERIC_BLOCK_SIZE]; ++ unsigned char iv[GENERIC_BLOCK_SIZE]; ++ + block128_f block; + union { + cbc128_f cbc; +@@ -83,12 +90,6 @@ struct prov_cipher_ctx_st { + * manage partial blocks themselves. + */ + unsigned int num; +- +- /* The original value of the iv */ +- unsigned char oiv[GENERIC_BLOCK_SIZE]; +- /* Buffer of partial blocks processed via update calls */ +- unsigned char buf[GENERIC_BLOCK_SIZE]; +- unsigned char iv[GENERIC_BLOCK_SIZE]; + const PROV_CIPHER_HW *hw; /* hardware specific functions */ + const void *ks; /* Pointer to algorithm specific key data */ + OSSL_LIB_CTX *libctx; +-- +2.33.0 + diff --git a/backport-Remove-the-_fetch_by_number-functions.patch b/backport-Remove-the-_fetch_by_number-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..73cd4dddbb12b01a13e5aecc6e2d8ba0aaca72ce --- /dev/null +++ b/backport-Remove-the-_fetch_by_number-functions.patch @@ -0,0 +1,509 @@ +From 4a929c7c5cb06dcf1952691ee8732007cc1a41d4 Mon Sep 17 00:00:00 2001 +From: Pauli +Date: Wed, 4 May 2022 14:54:13 +1000 +Subject: [PATCH] Remove the _fetch_by_number functions + +These functions are unused and untested. They are also implemented rather +inefficiently. If we ever needed them in the future, they'd almost surely +need to be rewritten more efficiently. + +Fixes #18227 + +Reviewed-by: Matt Caswell +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/18237) + +(cherry picked from commit 16ff70a58cfb5c40197e6a940cf4666226f31b79) +--- + crypto/encode_decode/decoder_meth.c | 36 +++------------- + crypto/encode_decode/encoder_meth.c | 36 +++------------- + crypto/evp/evp_fetch.c | 55 ++++--------------------- + crypto/evp/evp_local.h | 7 ---- + crypto/evp/keymgmt_meth.c | 10 ----- + crypto/store/store_local.h | 3 -- + crypto/store/store_meth.c | 37 +++-------------- + doc/internal/man3/evp_generic_fetch.pod | 19 +-------- + include/crypto/decoder.h | 4 -- + include/crypto/encoder.h | 2 - + 10 files changed, 27 insertions(+), 182 deletions(-) + +diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c +index 62e30ccb1a..74c86a8fe8 100644 +--- a/crypto/encode_decode/decoder_meth.c ++++ b/crypto/encode_decode/decoder_meth.c +@@ -340,38 +340,27 @@ static void free_decoder(void *method) + + /* Fetching support. Can fetch by numeric identity or by name */ + static OSSL_DECODER * +-inner_ossl_decoder_fetch(struct decoder_data_st *methdata, int id, ++inner_ossl_decoder_fetch(struct decoder_data_st *methdata, + const char *name, const char *properties) + { + OSSL_METHOD_STORE *store = get_decoder_store(methdata->libctx); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); + const char *const propq = properties != NULL ? properties : ""; + void *method = NULL; +- int unsupported = 0; ++ int unsupported, id; + + if (store == NULL || namemap == NULL) { + ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + +- /* +- * If we have been passed both an id and a name, we have an +- * internal programming error. +- */ +- if (!ossl_assert(id == 0 || name == NULL)) { +- ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR); +- return NULL; +- } +- +- if (id == 0 && name != NULL) +- id = ossl_namemap_name2num(namemap, name); ++ id = name != NULL ? ossl_namemap_name2num(namemap, name) : 0; + + /* + * If we haven't found the name yet, chances are that the algorithm to + * be fetched is unsupported. + */ +- if (id == 0) +- unsupported = 1; ++ unsupported = id == 0; + + if (id == 0 + || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) { +@@ -436,20 +425,7 @@ OSSL_DECODER *OSSL_DECODER_fetch(OSSL_LIB_CTX *libctx, const char *name, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- method = inner_ossl_decoder_fetch(&methdata, 0, name, properties); +- dealloc_tmp_decoder_store(methdata.tmp_store); +- return method; +-} +- +-OSSL_DECODER *ossl_decoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id, +- const char *properties) +-{ +- struct decoder_data_st methdata; +- void *method; +- +- methdata.libctx = libctx; +- methdata.tmp_store = NULL; +- method = inner_ossl_decoder_fetch(&methdata, id, NULL, properties); ++ method = inner_ossl_decoder_fetch(&methdata, name, properties); + dealloc_tmp_decoder_store(methdata.tmp_store); + return method; + } +@@ -579,7 +555,7 @@ void OSSL_DECODER_do_all_provided(OSSL_LIB_CTX *libctx, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- (void)inner_ossl_decoder_fetch(&methdata, 0, NULL, NULL /* properties */); ++ (void)inner_ossl_decoder_fetch(&methdata, NULL, NULL /* properties */); + + data.user_fn = user_fn; + data.user_arg = user_arg; +diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c +index f91d349587..7092ba7ef8 100644 +--- a/crypto/encode_decode/encoder_meth.c ++++ b/crypto/encode_decode/encoder_meth.c +@@ -350,38 +350,27 @@ static void free_encoder(void *method) + + /* Fetching support. Can fetch by numeric identity or by name */ + static OSSL_ENCODER * +-inner_ossl_encoder_fetch(struct encoder_data_st *methdata, int id, ++inner_ossl_encoder_fetch(struct encoder_data_st *methdata, + const char *name, const char *properties) + { + OSSL_METHOD_STORE *store = get_encoder_store(methdata->libctx); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); + const char *const propq = properties != NULL ? properties : ""; + void *method = NULL; +- int unsupported = 0; ++ int unsupported, id; + + if (store == NULL || namemap == NULL) { + ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + +- /* +- * If we have been passed both an id and a name, we have an +- * internal programming error. +- */ +- if (!ossl_assert(id == 0 || name == NULL)) { +- ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR); +- return NULL; +- } +- +- if (id == 0) +- id = ossl_namemap_name2num(namemap, name); ++ id = name != NULL ? ossl_namemap_name2num(namemap, name) : 0; + + /* + * If we haven't found the name yet, chances are that the algorithm to + * be fetched is unsupported. + */ +- if (id == 0) +- unsupported = 1; ++ unsupported = id == 0; + + if (id == 0 + || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) { +@@ -445,20 +434,7 @@ OSSL_ENCODER *OSSL_ENCODER_fetch(OSSL_LIB_CTX *libctx, const char *name, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- method = inner_ossl_encoder_fetch(&methdata, 0, name, properties); +- dealloc_tmp_encoder_store(methdata.tmp_store); +- return method; +-} +- +-OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id, +- const char *properties) +-{ +- struct encoder_data_st methdata; +- void *method; +- +- methdata.libctx = libctx; +- methdata.tmp_store = NULL; +- method = inner_ossl_encoder_fetch(&methdata, id, NULL, properties); ++ method = inner_ossl_encoder_fetch(&methdata, name, properties); + dealloc_tmp_encoder_store(methdata.tmp_store); + return method; + } +@@ -570,7 +546,7 @@ void OSSL_ENCODER_do_all_provided(OSSL_LIB_CTX *libctx, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- (void)inner_ossl_encoder_fetch(&methdata, 0, NULL, NULL /* properties */); ++ (void)inner_ossl_encoder_fetch(&methdata, NULL, NULL /* properties */); + + data.user_fn = user_fn; + data.user_arg = user_arg; +diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c +index 26ed5edcaf..4908f6cfee 100644 +--- a/crypto/evp/evp_fetch.c ++++ b/crypto/evp/evp_fetch.c +@@ -122,7 +122,7 @@ static void *get_evp_method_from_store(void *store, const OSSL_PROVIDER **prov, + { + struct evp_method_data_st *methdata = data; + void *method = NULL; +- int name_id = 0; ++ int name_id; + uint32_t meth_id; + + /* +@@ -239,8 +239,7 @@ static void destruct_evp_method(void *method, void *data) + static void * + inner_evp_generic_fetch(struct evp_method_data_st *methdata, + OSSL_PROVIDER *prov, int operation_id, +- int name_id, const char *name, +- const char *properties, ++ const char *name, const char *properties, + void *(*new_method)(int name_id, + const OSSL_ALGORITHM *algodef, + OSSL_PROVIDER *prov), +@@ -252,7 +251,7 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, + const char *const propq = properties != NULL ? properties : ""; + uint32_t meth_id = 0; + void *method = NULL; +- int unsupported = 0; ++ int unsupported, name_id; + + if (store == NULL || namemap == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT); +@@ -268,18 +267,8 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, + return NULL; + } + +- /* +- * If we have been passed both a name_id and a name, we have an +- * internal programming error. +- */ +- if (!ossl_assert(name_id == 0 || name == NULL)) { +- ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); +- return NULL; +- } +- + /* If we haven't received a name id yet, try to get one for the name */ +- if (name_id == 0 && name != NULL) +- name_id = ossl_namemap_name2num(namemap, name); ++ name_id = name != NULL ? ossl_namemap_name2num(namemap, name) : 0; + + /* + * If we have a name id, calculate a method id with evp_method_id(). +@@ -298,8 +287,7 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, + * If we haven't found the name yet, chances are that the algorithm to + * be fetched is unsupported. + */ +- if (name_id == 0) +- unsupported = 1; ++ unsupported = name_id == 0; + + if (meth_id == 0 + || !ossl_method_store_cache_get(store, prov, meth_id, propq, &method)) { +@@ -374,34 +362,7 @@ void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id, + methdata.libctx = libctx; + methdata.tmp_store = NULL; + method = inner_evp_generic_fetch(&methdata, NULL, operation_id, +- 0, name, properties, +- new_method, up_ref_method, free_method); +- dealloc_tmp_evp_method_store(methdata.tmp_store); +- return method; +-} +- +-/* +- * evp_generic_fetch_by_number() is special, and only returns methods for +- * already known names, i.e. it refuses to work if no name_id can be found +- * (it's considered an internal programming error). +- * This is meant to be used when one method needs to fetch an associated +- * method. +- */ +-void *evp_generic_fetch_by_number(OSSL_LIB_CTX *libctx, int operation_id, +- int name_id, const char *properties, +- void *(*new_method)(int name_id, +- const OSSL_ALGORITHM *algodef, +- OSSL_PROVIDER *prov), +- int (*up_ref_method)(void *), +- void (*free_method)(void *)) +-{ +- struct evp_method_data_st methdata; +- void *method; +- +- methdata.libctx = libctx; +- methdata.tmp_store = NULL; +- method = inner_evp_generic_fetch(&methdata, NULL, operation_id, +- name_id, NULL, properties, ++ name, properties, + new_method, up_ref_method, free_method); + dealloc_tmp_evp_method_store(methdata.tmp_store); + return method; +@@ -427,7 +388,7 @@ void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, + methdata.libctx = ossl_provider_libctx(prov); + methdata.tmp_store = NULL; + method = inner_evp_generic_fetch(&methdata, prov, operation_id, +- 0, name, properties, ++ name, properties, + new_method, up_ref_method, free_method); + dealloc_tmp_evp_method_store(methdata.tmp_store); + return method; +@@ -631,7 +592,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- (void)inner_evp_generic_fetch(&methdata, NULL, operation_id, 0, NULL, NULL, ++ (void)inner_evp_generic_fetch(&methdata, NULL, operation_id, NULL, NULL, + new_method, up_ref_method, free_method); + + data.operation_id = operation_id; +diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h +index 3ccfaeb37c..a853174452 100644 +--- a/crypto/evp/evp_local.h ++++ b/crypto/evp/evp_local.h +@@ -270,13 +270,6 @@ void *evp_generic_fetch(OSSL_LIB_CTX *ctx, int operation_id, + OSSL_PROVIDER *prov), + int (*up_ref_method)(void *), + void (*free_method)(void *)); +-void *evp_generic_fetch_by_number(OSSL_LIB_CTX *ctx, int operation_id, +- int name_id, const char *properties, +- void *(*new_method)(int name_id, +- const OSSL_ALGORITHM *algodef, +- OSSL_PROVIDER *prov), +- int (*up_ref_method)(void *), +- void (*free_method)(void *)); + void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, + const char *name, const char *properties, + void *(*new_method)(int name_id, +diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c +index 90fd8068dc..5fab4a7639 100644 +--- a/crypto/evp/keymgmt_meth.c ++++ b/crypto/evp/keymgmt_meth.c +@@ -203,16 +203,6 @@ static void *keymgmt_from_algorithm(int name_id, + return keymgmt; + } + +-EVP_KEYMGMT *evp_keymgmt_fetch_by_number(OSSL_LIB_CTX *ctx, int name_id, +- const char *properties) +-{ +- return evp_generic_fetch_by_number(ctx, +- OSSL_OP_KEYMGMT, name_id, properties, +- keymgmt_from_algorithm, +- (int (*)(void *))EVP_KEYMGMT_up_ref, +- (void (*)(void *))EVP_KEYMGMT_free); +-} +- + EVP_KEYMGMT *evp_keymgmt_fetch_from_prov(OSSL_PROVIDER *prov, + const char *name, + const char *properties) +diff --git a/crypto/store/store_local.h b/crypto/store/store_local.h +index 8f817fd514..f73bce32b9 100644 +--- a/crypto/store/store_local.h ++++ b/crypto/store/store_local.h +@@ -168,9 +168,6 @@ int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx); + OSSL_STORE_LOADER *ossl_store_loader_fetch(OSSL_LIB_CTX *libctx, + const char *scheme, + const char *properties); +-OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx, +- int scheme_id, +- const char *properties); + + /* Standard function to handle the result from OSSL_FUNC_store_load() */ + struct ossl_load_result_data_st { +diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c +index 42848b799a..ab1016853e 100644 +--- a/crypto/store/store_meth.c ++++ b/crypto/store/store_meth.c +@@ -278,39 +278,28 @@ static void destruct_loader(void *method, void *data) + + /* Fetching support. Can fetch by numeric identity or by scheme */ + static OSSL_STORE_LOADER * +-inner_loader_fetch(struct loader_data_st *methdata, int id, ++inner_loader_fetch(struct loader_data_st *methdata, + const char *scheme, const char *properties) + { + OSSL_METHOD_STORE *store = get_loader_store(methdata->libctx); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); + const char *const propq = properties != NULL ? properties : ""; + void *method = NULL; +- int unsupported = 0; ++ int unsupported, id; + + if (store == NULL || namemap == NULL) { + ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + +- /* +- * If we have been passed both an id and a scheme, we have an +- * internal programming error. +- */ +- if (!ossl_assert(id == 0 || scheme == NULL)) { +- ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR); +- return NULL; +- } +- + /* If we haven't received a name id yet, try to get one for the name */ +- if (id == 0 && scheme != NULL) +- id = ossl_namemap_name2num(namemap, scheme); ++ id = scheme != NULL ? ossl_namemap_name2num(namemap, scheme) : 0; + + /* + * If we haven't found the name yet, chances are that the algorithm to + * be fetched is unsupported. + */ +- if (id == 0) +- unsupported = 1; ++ unsupported = id == 0; + + if (id == 0 + || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) { +@@ -381,21 +370,7 @@ OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(OSSL_LIB_CTX *libctx, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- method = inner_loader_fetch(&methdata, 0, scheme, properties); +- dealloc_tmp_loader_store(methdata.tmp_store); +- return method; +-} +- +-OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx, +- int scheme_id, +- const char *properties) +-{ +- struct loader_data_st methdata; +- void *method; +- +- methdata.libctx = libctx; +- methdata.tmp_store = NULL; +- method = inner_loader_fetch(&methdata, scheme_id, NULL, properties); ++ method = inner_loader_fetch(&methdata, scheme, properties); + dealloc_tmp_loader_store(methdata.tmp_store); + return method; + } +@@ -491,7 +466,7 @@ void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx, + + methdata.libctx = libctx; + methdata.tmp_store = NULL; +- (void)inner_loader_fetch(&methdata, 0, NULL, NULL /* properties */); ++ (void)inner_loader_fetch(&methdata, NULL, NULL /* properties */); + + data.user_fn = user_fn; + data.user_arg = user_arg; +diff --git a/doc/internal/man3/evp_generic_fetch.pod b/doc/internal/man3/evp_generic_fetch.pod +index b23d2ec0ea..ce75ffbfc8 100644 +--- a/doc/internal/man3/evp_generic_fetch.pod ++++ b/doc/internal/man3/evp_generic_fetch.pod +@@ -2,7 +2,7 @@ + + =head1 NAME + +-evp_generic_fetch, evp_generic_fetch_by_number, evp_generic_fetch_from_prov ++evp_generic_fetch, evp_generic_fetch_from_prov + - generic algorithm fetchers and method creators for EVP + + =head1 SYNOPSIS +@@ -20,15 +20,6 @@ evp_generic_fetch, evp_generic_fetch_by_number, evp_generic_fetch_from_prov + int (*up_ref_method)(void *), + void (*free_method)(void *)); + +- void *evp_generic_fetch_by_number(OSSL_LIB_CTX *ctx, int operation_id, +- int name_id, const char *properties, +- void *(*new_method)(int name_id, +- const OSSL_DISPATCH *fns, +- OSSL_PROVIDER *prov, +- void *method_data), +- void *method_data, +- int (*up_ref_method)(void *), +- void (*free_method)(void *)); + void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, + int name_id, const char *properties, + void *(*new_method)(int name_id, +@@ -46,14 +37,6 @@ I, I, I, and I and uses + it to create an EVP method with the help of the functions + I, I, and I. + +-evp_generic_fetch_by_number() does the same thing as evp_generic_fetch(), +-but takes a numeric I instead of a name. +-I must always be nonzero; as a matter of fact, it being zero +-is considered a programming error. +-This is meant to be used when one method needs to fetch an associated +-method, and is typically called from inside the given function +-I. +- + evp_generic_fetch_from_prov() does the same thing as evp_generic_fetch(), + but limits the search of methods to the provider given with I. + This is meant to be used when one method needs to fetch an associated +diff --git a/include/crypto/decoder.h b/include/crypto/decoder.h +index 107a7b502a..6b5ee56ac6 100644 +--- a/include/crypto/decoder.h ++++ b/include/crypto/decoder.h +@@ -13,10 +13,6 @@ + + # include + +-OSSL_DECODER *ossl_decoder_fetch_by_number(OSSL_LIB_CTX *libctx, +- int id, +- const char *properties); +- + /* + * These are specially made for the 'file:' provider-native loader, which + * uses this to install a DER to anything decoder, which doesn't do much +diff --git a/include/crypto/encoder.h b/include/crypto/encoder.h +index 562081ad41..5c53bbea39 100644 +--- a/include/crypto/encoder.h ++++ b/include/crypto/encoder.h +@@ -13,8 +13,6 @@ + + # include + +-OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id, +- const char *properties); + int ossl_encoder_get_number(const OSSL_ENCODER *encoder); + int ossl_encoder_store_cache_flush(OSSL_LIB_CTX *libctx); + int ossl_encoder_store_remove_all_provided(const OSSL_PROVIDER *prov); +-- +2.33.0 + diff --git a/backport-When-we-re-just-reading-EX_CALLBACK-data-just-get-a-.patch b/backport-When-we-re-just-reading-EX_CALLBACK-data-just-get-a-.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf0a7a105009319635124368df8ae14ab4c271c4 --- /dev/null +++ b/backport-When-we-re-just-reading-EX_CALLBACK-data-just-get-a-.patch @@ -0,0 +1,115 @@ +From f56744fe1e47ca153f487eb383e62aac0e8b0545 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Thu, 11 May 2023 11:25:07 +0100 +Subject: [PATCH] When we're just reading EX_CALLBACK data just get a read lock + +The crypto_ex_data code was always obtaining a write lock in all functions +regardless of whether we were only reading EX_CALLBACK data or actually +changing it. Changes to the EX_CALLBACK data are rare, with many reads so +we should change to a read lock where we can. + +We hit this every time we create or free any object that can have ex_data +associated with it (e.g. BIOs, SSL, etc) + +Partially fixes #20286 + +Reviewed-by: Tomas Mraz +Reviewed-by: Hugo Landau +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/20943) + +(cherry picked from commit 6d15357aeb893c6e8b4c7a8188c18f4db54c0612) +--- + crypto/ex_data.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/crypto/ex_data.c b/crypto/ex_data.c +index 40223f06e4..33c35da7d0 100644 +--- a/crypto/ex_data.c ++++ b/crypto/ex_data.c +@@ -26,8 +26,10 @@ int ossl_do_ex_data_init(OSSL_LIB_CTX *ctx) + * Return the EX_CALLBACKS from the |ex_data| array that corresponds to + * a given class. On success, *holds the lock.* + * The |global| parameter is assumed to be non null (checked by the caller). ++ * If |read| is 1 then a read lock is obtained. Otherwise it is a write lock. + */ +-static EX_CALLBACKS *get_and_lock(OSSL_EX_DATA_GLOBAL *global, int class_index) ++static EX_CALLBACKS *get_and_lock(OSSL_EX_DATA_GLOBAL *global, int class_index, ++ int read) + { + EX_CALLBACKS *ip; + +@@ -44,8 +46,14 @@ static EX_CALLBACKS *get_and_lock(OSSL_EX_DATA_GLOBAL *global, int class_index) + return NULL; + } + +- if (!CRYPTO_THREAD_write_lock(global->ex_data_lock)) +- return NULL; ++ if (read) { ++ if (!CRYPTO_THREAD_read_lock(global->ex_data_lock)) ++ return NULL; ++ } else { ++ if (!CRYPTO_THREAD_write_lock(global->ex_data_lock)) ++ return NULL; ++ } ++ + ip = &global->ex_data[class_index]; + return ip; + } +@@ -112,7 +120,7 @@ int ossl_crypto_free_ex_index_ex(OSSL_LIB_CTX *ctx, int class_index, int idx) + if (global == NULL) + return 0; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 0); + if (ip == NULL) + return 0; + +@@ -153,7 +161,7 @@ int ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index, + if (global == NULL) + return -1; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 0); + if (ip == NULL) + return -1; + +@@ -221,7 +229,7 @@ int ossl_crypto_new_ex_data_ex(OSSL_LIB_CTX *ctx, int class_index, void *obj, + if (global == NULL) + return 0; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 1); + if (ip == NULL) + return 0; + +@@ -284,7 +292,7 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, + if (global == NULL) + return 0; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 1); + if (ip == NULL) + return 0; + +@@ -373,7 +381,7 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) + if (global == NULL) + goto err; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 1); + if (ip == NULL) + goto err; + +@@ -440,7 +448,7 @@ int ossl_crypto_alloc_ex_data_intern(int class_index, void *obj, + if (global == NULL) + return 0; + +- ip = get_and_lock(global, class_index); ++ ip = get_and_lock(global, class_index, 1); + if (ip == NULL) + return 0; + f = sk_EX_CALLBACK_value(ip->meth, idx); +-- +2.33.0 + diff --git a/backport-evp_md_init_internal-Avoid-reallocating-algctx-if-di.patch b/backport-evp_md_init_internal-Avoid-reallocating-algctx-if-di.patch new file mode 100644 index 0000000000000000000000000000000000000000..72101aafa55bc63c55dbad6b37a2f874f2a67dae --- /dev/null +++ b/backport-evp_md_init_internal-Avoid-reallocating-algctx-if-di.patch @@ -0,0 +1,134 @@ +From 708bf3dde8f53446cccded5dadafb853e7e9d38b Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Wed, 13 Apr 2022 16:26:18 +0200 +Subject: [PATCH] evp_md_init_internal: Avoid reallocating algctx if digest + unchanged + +Fixes #16947 + +Also refactor out algctx freeing into a separate function. + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Ben Kaduk +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/18105) + +(cherry picked from commit fe5c5cb85197aec7d68ab095b866ed22076850d0) +--- + crypto/evp/digest.c | 35 ++++++++++++++++++++--------------- + crypto/evp/m_sigver.c | 11 ++--------- + include/crypto/evp.h | 2 ++ + 3 files changed, 24 insertions(+), 24 deletions(-) + +diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c +index b93e079b15..7a8e15241f 100644 +--- a/crypto/evp/digest.c ++++ b/crypto/evp/digest.c +@@ -141,6 +141,20 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) + OPENSSL_free(ctx); + } + ++int evp_md_ctx_free_algctx(EVP_MD_CTX *ctx) ++{ ++ if (ctx->algctx != NULL) { ++ if (!ossl_assert(ctx->digest != NULL)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ++ return 0; ++ } ++ if (ctx->digest->freectx != NULL) ++ ctx->digest->freectx(ctx->algctx); ++ ctx->algctx = NULL; ++ } ++ return 1; ++} ++ + static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + const OSSL_PARAM params[], ENGINE *impl) + { +@@ -169,16 +183,6 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + +- if (ctx->algctx != NULL) { +- if (!ossl_assert(ctx->digest != NULL)) { +- ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +- return 0; +- } +- if (ctx->digest->freectx != NULL) +- ctx->digest->freectx(ctx->algctx); +- ctx->algctx = NULL; +- } +- + if (type != NULL) { + ctx->reqdigest = type; + } else { +@@ -229,6 +233,10 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + || (type != NULL && type->origin == EVP_ORIG_METH) + || (type == NULL && ctx->digest != NULL + && ctx->digest->origin == EVP_ORIG_METH)) { ++ /* If we were using provided hash before, cleanup algctx */ ++ if (!evp_md_ctx_free_algctx(ctx)) ++ return 0; ++ + if (ctx->digest == ctx->fetched_digest) + ctx->digest = NULL; + EVP_MD_free(ctx->fetched_digest); +@@ -239,6 +247,8 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + cleanup_old_md_data(ctx, 1); + + /* Start of non-legacy code below */ ++ if (ctx->digest != type && !evp_md_ctx_free_algctx(ctx)) ++ return 0; + + if (type->prov == NULL) { + #ifdef FIPS_MODULE +@@ -261,11 +271,6 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + #endif + } + +- if (ctx->algctx != NULL && ctx->digest != NULL && ctx->digest != type) { +- if (ctx->digest->freectx != NULL) +- ctx->digest->freectx(ctx->algctx); +- ctx->algctx = NULL; +- } + if (type->prov != NULL && ctx->fetched_digest != type) { + if (!EVP_MD_up_ref((EVP_MD *)type)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c +index fc087d2cb6..630d339c35 100644 +--- a/crypto/evp/m_sigver.c ++++ b/crypto/evp/m_sigver.c +@@ -51,15 +51,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + void *provkey = NULL; + int ret, iter, reinit = 1; + +- if (ctx->algctx != NULL) { +- if (!ossl_assert(ctx->digest != NULL)) { +- ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +- return 0; +- } +- if (ctx->digest->freectx != NULL) +- ctx->digest->freectx(ctx->algctx); +- ctx->algctx = NULL; +- } ++ if (!evp_md_ctx_free_algctx(ctx)) ++ return 0; + + if (ctx->pctx == NULL) { + reinit = 0; +diff --git a/include/crypto/evp.h b/include/crypto/evp.h +index e70d8e9e84..dbbdcccbda 100644 +--- a/include/crypto/evp.h ++++ b/include/crypto/evp.h +@@ -909,6 +909,8 @@ int evp_set_default_properties_int(OSSL_LIB_CTX *libctx, const char *propq, + char *evp_get_global_properties_str(OSSL_LIB_CTX *libctx, int loadconfig); + + void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force, int keep_digest); ++/* just free the algctx if set, returns 0 on inconsistent state of ctx */ ++int evp_md_ctx_free_algctx(EVP_MD_CTX *ctx); + + /* Three possible states: */ + # define EVP_PKEY_STATE_UNKNOWN 0 +-- +2.33.0 + diff --git a/backport-ossl_namemap_name2_num-Avoid-unnecessary-OPENSSL_str.patch b/backport-ossl_namemap_name2_num-Avoid-unnecessary-OPENSSL_str.patch new file mode 100644 index 0000000000000000000000000000000000000000..88f97d15ee86db16d1ba22924bf543681f1492d2 --- /dev/null +++ b/backport-ossl_namemap_name2_num-Avoid-unnecessary-OPENSSL_str.patch @@ -0,0 +1,137 @@ +From 8af5c6c4d340961dcb853a6126831ebc5a86b311 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Wed, 18 May 2022 16:45:20 +0200 +Subject: [PATCH] ossl_namemap_name2_num: Avoid unnecessary OPENSSL_strndup(). + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/18341) + +(cherry picked from commit dab5098eacb9e264c32a33332ba047f234a3de68) +--- + crypto/core_namemap.c | 55 +++++++++++++++++++++++++++++-------------- + 1 file changed, 37 insertions(+), 18 deletions(-) + +diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c +index 554524a5c4..4c1ca05308 100644 +--- a/crypto/core_namemap.c ++++ b/crypto/core_namemap.c +@@ -166,22 +166,19 @@ int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number, + return 1; + } + +-static int namemap_name2num_n(const OSSL_NAMEMAP *namemap, +- const char *name, size_t name_len) ++static int namemap_name2num(const OSSL_NAMEMAP *namemap, ++ const char *name) + { + NAMENUM_ENTRY *namenum_entry, namenum_tmpl; + +- if ((namenum_tmpl.name = OPENSSL_strndup(name, name_len)) == NULL) +- return 0; ++ namenum_tmpl.name = (char *)name; + namenum_tmpl.number = 0; + namenum_entry = + lh_NAMENUM_ENTRY_retrieve(namemap->namenum, &namenum_tmpl); +- OPENSSL_free(namenum_tmpl.name); + return namenum_entry != NULL ? namenum_entry->number : 0; + } + +-int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, +- const char *name, size_t name_len) ++int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name) + { + int number; + +@@ -195,18 +192,24 @@ int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, + + if (!CRYPTO_THREAD_read_lock(namemap->lock)) + return 0; +- number = namemap_name2num_n(namemap, name, name_len); ++ number = namemap_name2num(namemap, name); + CRYPTO_THREAD_unlock(namemap->lock); + + return number; + } + +-int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name) ++int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, ++ const char *name, size_t name_len) + { +- if (name == NULL) ++ char *tmp; ++ int ret; ++ ++ if (name == NULL || (tmp = OPENSSL_strndup(name, name_len)) == NULL) + return 0; + +- return ossl_namemap_name2num_n(namemap, name, strlen(name)); ++ ret = ossl_namemap_name2num(namemap, tmp); ++ OPENSSL_free(tmp); ++ return ret; + } + + struct num2name_data_st { +@@ -241,14 +244,20 @@ static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + { + NAMENUM_ENTRY *namenum = NULL; + int tmp_number; ++ char *tmp = OPENSSL_strndup(name, name_len); ++ ++ if (tmp == NULL) ++ return 0; + + /* If it already exists, we don't add it */ +- if ((tmp_number = namemap_name2num_n(namemap, name, name_len)) != 0) ++ if ((tmp_number = namemap_name2num(namemap, tmp)) != 0) { ++ OPENSSL_free(tmp); + return tmp_number; ++ } + +- if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL +- || (namenum->name = OPENSSL_strndup(name, name_len)) == NULL) ++ if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL) + goto err; ++ namenum->name = tmp; + + /* The tsan_counter use here is safe since we're under lock */ + namenum->number = +@@ -260,7 +269,8 @@ static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + return namenum->number; + + err: +- namenum_free(namenum); ++ OPENSSL_free(tmp); ++ OPENSSL_free(namenum); + return 0; + } + +@@ -312,13 +322,22 @@ int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, + */ + for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { + int this_number; ++ char *allocated; ++ const char *tmp; + +- if ((q = strchr(p, separator)) == NULL) ++ if ((q = strchr(p, separator)) == NULL) { + l = strlen(p); /* offset to \0 */ +- else ++ tmp = p; ++ allocated = NULL; ++ } else { + l = q - p; /* offset to the next separator */ ++ tmp = allocated = OPENSSL_strndup(p, l); ++ if (tmp == NULL) ++ goto err; ++ } + +- this_number = namemap_name2num_n(namemap, p, l); ++ this_number = namemap_name2num(namemap, tmp); ++ OPENSSL_free(allocated); + + if (*p == '\0' || *p == separator) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME); +-- +2.33.0 + diff --git a/backport-performance-improve-ossl_lh_strcasehash.patch b/backport-performance-improve-ossl_lh_strcasehash.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e73d8724e1050372bfce65f0cec58d23aecd6ee --- /dev/null +++ b/backport-performance-improve-ossl_lh_strcasehash.patch @@ -0,0 +1,66 @@ +From d295e4b1da6d223242eb43bfae10479616c5236d Mon Sep 17 00:00:00 2001 +From: Pauli +Date: Fri, 20 May 2022 10:15:55 +1000 +Subject: [PATCH] performance: improve ossl_lh_strcasehash + +This improvement seems to roughly halve the time it takes to run the +ossl_lh_strcasehash function. + +It should have no impact on the strings we hash and search for often (algorithm +names, property strings). + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/18354) + +(cherry picked from commit a4e21d18d5b7cb4fef66c10f13b1b3b55945439f) +--- + crypto/lhash/lhash.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c +index 1cd988f01f..c319a44c7b 100644 +--- a/crypto/lhash/lhash.c ++++ b/crypto/lhash/lhash.c +@@ -344,18 +344,37 @@ unsigned long OPENSSL_LH_strhash(const char *c) + return (ret >> 16) ^ ret; + } + ++/* ++ * Case insensitive string hashing. ++ * ++ * The lower/upper case bit is masked out (forcing all letters to be capitals). ++ * The major side effect on non-alpha characters is mapping the symbols and ++ * digits into the control character range (which should be harmless). ++ * The duplication (with respect to the hash value) of printable characters ++ * are that '`', '{', '|', '}' and '~' map to '@', '[', '\', ']' and '^' ++ * respectively (which seems tolerable). ++ * ++ * For EBCDIC, the alpha mapping is to lower case, most symbols go to control ++ * characters. The only duplication is '0' mapping to '^', which is better ++ * than for ASCII. ++ */ + unsigned long ossl_lh_strcasehash(const char *c) + { + unsigned long ret = 0; + long n; + unsigned long v; + int r; ++#if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST) ++ const long int case_adjust = ~0x40; ++#else ++ const long int case_adjust = ~0x20; ++#endif + + if (c == NULL || *c == '\0') + return ret; + + for (n = 0x100; *c != '\0'; n += 0x100) { +- v = n | ossl_tolower(*c); ++ v = n | (case_adjust & *c); + r = (int)((v >> 2) ^ v) & 0x0f; + /* cast to uint64_t to avoid 32 bit shift of 32 bit value */ + ret = (ret << r) | (unsigned long)((uint64_t)ret >> (32 - r)); +-- +2.33.0 + diff --git a/backport-use-__builtin_expect-to-improve-EVP_EncryptUpdate-pe.patch b/backport-use-__builtin_expect-to-improve-EVP_EncryptUpdate-pe.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b4c471ed23e96f1475a8955089e57c0a32109c6 --- /dev/null +++ b/backport-use-__builtin_expect-to-improve-EVP_EncryptUpdate-pe.patch @@ -0,0 +1,128 @@ +From ed6dfd1e3694b3438249f3d0117bc314afa6b240 Mon Sep 17 00:00:00 2001 +From: Liu-ErMeng +Date: Tue, 11 Jul 2023 16:22:53 +0800 +Subject: [PATCH] use '__builtin_expect' to improve EVP_EncryptUpdate + performance for gcc/clang. + +Signed-off-by: Liu-ErMeng + +Reviewed-by: Tomas Mraz +Reviewed-by: Tom Cosgrove +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/21425) +--- + crypto/evp/evp_enc.c | 24 ++++++++++++------------ + include/internal/common.h | 8 ++++++++ + 2 files changed, 20 insertions(+), 12 deletions(-) + +diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c +index 6b6d65163f..8dddcc0bb5 100644 +--- a/crypto/evp/evp_enc.c ++++ b/crypto/evp/evp_enc.c +@@ -27,6 +27,14 @@ + #include "crypto/evp.h" + #include "evp_local.h" + ++#if defined(__GNUC__) || defined(__clang__) ++ #define likely(x) __builtin_expect(!!(x), 1) ++ #define unlikely(x) __builtin_expect(!!(x), 0) ++#else ++ #define likely(x) x ++ #define unlikely(x) x ++#endif ++ + int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) + { + if (ctx == NULL) +@@ -621,7 +621,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + size_t soutl, inl_ = (size_t)inl; + int blocksize; + +- if (outl != NULL) { ++ if (likely(outl != NULL)) { + *outl = 0; + } else { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); +@@ -629,22 +629,22 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + } + + /* Prevent accidental use of decryption context when encrypting */ +- if (!ctx->encrypt) { ++ if (unlikely(!ctx->encrypt)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return 0; + } + +- if (ctx->cipher == NULL) { ++ if (unlikely(ctx->cipher == NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } + +- if (ctx->cipher->prov == NULL) ++ if (unlikely(ctx->cipher->prov == NULL)) + goto legacy; + + blocksize = ctx->cipher->block_size; + +- if (ctx->cipher->cupdate == NULL || blocksize < 1) { ++ if (unlikely(ctx->cipher->cupdate == NULL || blocksize < 1)) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } +@@ -653,7 +653,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + inl_ + (size_t)(blocksize == 1 ? 0 : blocksize), + in, inl_); + +- if (ret) { ++ if (likely(ret)) { + if (soutl > INT_MAX) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; +@@ -770,7 +770,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + size_t soutl, inl_ = (size_t)inl; + int blocksize; + +- if (outl != NULL) { ++ if (likely(outl != NULL)) { + *outl = 0; + } else { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); +@@ -778,21 +778,21 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + } + + /* Prevent accidental use of encryption context when decrypting */ +- if (ctx->encrypt) { ++ if (unlikely(ctx->encrypt)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION); + return 0; + } + +- if (ctx->cipher == NULL) { ++ if (unlikely(ctx->cipher == NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } +- if (ctx->cipher->prov == NULL) ++ if (unlikely(ctx->cipher->prov == NULL)) + goto legacy; + + blocksize = EVP_CIPHER_CTX_get_block_size(ctx); + +- if (ctx->cipher->cupdate == NULL || blocksize < 1) { ++ if (unlikely(ctx->cipher->cupdate == NULL || blocksize < 1)) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } +@@ -800,7 +800,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, + inl_ + (size_t)(blocksize == 1 ? 0 : blocksize), + in, inl_); + +- if (ret) { ++ if (likely(ret)) { + if (soutl > INT_MAX) { + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; +-- +2.33.0 + diff --git a/bacport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch b/bacport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch new file mode 100644 index 0000000000000000000000000000000000000000..cde3676258fdf933c7e87900efe64639b8e45200 --- /dev/null +++ b/bacport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch @@ -0,0 +1,275 @@ +From fca5d6a2b76d0c1f20e63cec5ac1b927eeba7b43 Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Thu, 19 May 2022 11:38:23 +0200 +Subject: [PATCH] Drop ossl_namemap_add_name_n() and simplify + ossl_namemap_add_names() + +Reviewed-by: Dmitry Belyavskiy +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/18341) + +(cherry picked from commit b00cf0e790661636e1df1026554f712cc513592d) +--- + crypto/core_namemap.c | 96 +++++++++++--------------- + doc/internal/man3/ossl_namemap_new.pod | 15 ++-- + include/internal/namemap.h | 2 - + 3 files changed, 48 insertions(+), 65 deletions(-) + +diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c +index 4c1ca05308..380f4da9c2 100644 +--- a/crypto/core_namemap.c ++++ b/crypto/core_namemap.c +@@ -166,6 +166,7 @@ int ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number, + return 1; + } + ++/* This function is not thread safe, the namemap must be locked */ + static int namemap_name2num(const OSSL_NAMEMAP *namemap, + const char *name) + { +@@ -239,25 +240,22 @@ const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number, + return data.name; + } + +-static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len) ++/* This function is not thread safe, the namemap must be locked */ ++static int namemap_add_name(OSSL_NAMEMAP *namemap, int number, ++ const char *name) + { + NAMENUM_ENTRY *namenum = NULL; + int tmp_number; +- char *tmp = OPENSSL_strndup(name, name_len); +- +- if (tmp == NULL) +- return 0; + + /* If it already exists, we don't add it */ +- if ((tmp_number = namemap_name2num(namemap, tmp)) != 0) { +- OPENSSL_free(tmp); ++ if ((tmp_number = namemap_name2num(namemap, name)) != 0) + return tmp_number; +- } + + if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL) ++ return 0; ++ ++ if ((namenum->name = OPENSSL_strdup(name)) == NULL) + goto err; +- namenum->name = tmp; + + /* The tsan_counter use here is safe since we're under lock */ + namenum->number = +@@ -269,13 +267,12 @@ static int namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + return namenum->number; + + err: +- OPENSSL_free(tmp); +- OPENSSL_free(namenum); ++ namenum_free(namenum); + return 0; + } + +-int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len) ++int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, ++ const char *name) + { + int tmp_number; + +@@ -284,29 +281,20 @@ int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, + namemap = ossl_namemap_stored(NULL); + #endif + +- if (name == NULL || name_len == 0 || namemap == NULL) ++ if (name == NULL || *name == 0 || namemap == NULL) + return 0; + + if (!CRYPTO_THREAD_write_lock(namemap->lock)) + return 0; +- tmp_number = namemap_add_name_n(namemap, number, name, name_len); ++ tmp_number = namemap_add_name(namemap, number, name); + CRYPTO_THREAD_unlock(namemap->lock); + return tmp_number; + } + +-int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name) +-{ +- if (name == NULL) +- return 0; +- +- return ossl_namemap_add_name_n(namemap, number, name, strlen(name)); +-} +- + int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, + const char *names, const char separator) + { +- const char *p, *q; +- size_t l; ++ char *tmp, *p, *q, *endp; + + /* Check that we have a namemap */ + if (!ossl_assert(namemap != NULL)) { +@@ -314,71 +302,71 @@ int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number, + return 0; + } + +- if (!CRYPTO_THREAD_write_lock(namemap->lock)) ++ if ((tmp = OPENSSL_strdup(names)) == NULL) + return 0; ++ ++ if (!CRYPTO_THREAD_write_lock(namemap->lock)) { ++ OPENSSL_free(tmp); ++ return 0; ++ } + /* + * Check that no name is an empty string, and that all names have at + * most one numeric identity together. + */ +- for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { ++ for (p = tmp; *p != '\0'; p = q) { + int this_number; +- char *allocated; +- const char *tmp; ++ size_t l; + + if ((q = strchr(p, separator)) == NULL) { + l = strlen(p); /* offset to \0 */ +- tmp = p; +- allocated = NULL; ++ q = p + l; + } else { + l = q - p; /* offset to the next separator */ +- tmp = allocated = OPENSSL_strndup(p, l); +- if (tmp == NULL) +- goto err; ++ *q++ = '\0'; + } + +- this_number = namemap_name2num(namemap, tmp); +- OPENSSL_free(allocated); +- +- if (*p == '\0' || *p == separator) { ++ if (*p == '\0') { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME); +- goto err; ++ number = 0; ++ goto end; + } ++ ++ this_number = namemap_name2num(namemap, p); ++ + if (number == 0) { + number = this_number; + } else if (this_number != 0 && this_number != number) { + ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES, +- "\"%.*s\" has an existing different identity %d (from \"%s\")", +- l, p, this_number, names); +- goto err; ++ "\"%s\" has an existing different identity %d (from \"%s\")", ++ p, this_number, names); ++ number = 0; ++ goto end; + } + } ++ endp = p; + + /* Now that we have checked, register all names */ +- for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) { ++ for (p = tmp; p < endp; p = q) { + int this_number; + +- if ((q = strchr(p, separator)) == NULL) +- l = strlen(p); /* offset to \0 */ +- else +- l = q - p; /* offset to the next separator */ ++ q = p + strlen(p) + 1; + +- this_number = namemap_add_name_n(namemap, number, p, l); ++ this_number = namemap_add_name(namemap, number, p); + if (number == 0) { + number = this_number; + } else if (this_number != number) { + ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, + "Got number %d when expecting %d", + this_number, number); +- goto err; ++ number = 0; ++ goto end; + } + } + ++ end: + CRYPTO_THREAD_unlock(namemap->lock); ++ OPENSSL_free(tmp); + return number; +- +- err: +- CRYPTO_THREAD_unlock(namemap->lock); +- return 0; + } + + /*- +diff --git a/doc/internal/man3/ossl_namemap_new.pod b/doc/internal/man3/ossl_namemap_new.pod +index ff247e87b0..7f4940fc93 100644 +--- a/doc/internal/man3/ossl_namemap_new.pod ++++ b/doc/internal/man3/ossl_namemap_new.pod +@@ -3,7 +3,7 @@ + =head1 NAME + + ossl_namemap_new, ossl_namemap_free, ossl_namemap_stored, ossl_namemap_empty, +-ossl_namemap_add_name, ossl_namemap_add_name_n, ossl_namemap_add_names, ++ossl_namemap_add_name, ossl_namemap_add_names, + ossl_namemap_name2num, ossl_namemap_name2num_n, + ossl_namemap_doall_names + - internal number E-E name map +@@ -19,8 +19,6 @@ ossl_namemap_doall_names + int ossl_namemap_empty(OSSL_NAMEMAP *namemap); + + int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name); +- int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len); + + int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name); + int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap, +@@ -62,10 +60,9 @@ names already associated with that number. + ossl_namemap_name2num() finds the number corresponding to the given + I. + +-ossl_namemap_add_name_n() and ossl_namemap_name2num_n() do the same thing +-as ossl_namemap_add_name() and ossl_namemap_name2num(), but take a string +-length I as well, allowing the caller to use a fragment of +-a string as a name. ++ossl_namemap_name2num_n() does the same thing as ++ossl_namemap_name2num(), but takes a string length I as well, ++allowing the caller to use a fragment of a string as a name. + + ossl_namemap_doall_names() walks through all names associated with + I in the given I and calls the function I for +@@ -88,8 +85,8 @@ ossl_namemap_empty() returns 1 if the B is NULL or + empty, 0 if it's not empty, or -1 on internal error (such as inability + to lock). + +-ossl_namemap_add_name() and ossl_namemap_add_name_n() return the number +-associated with the added string, or zero on error. ++ossl_namemap_add_name() returns the number associated with the added ++string, or zero on error. + + ossl_namemap_num2names() returns a pointer to a NULL-terminated list of + pointers to the names corresponding to the given number, or NULL if +diff --git a/include/internal/namemap.h b/include/internal/namemap.h +index a4c60ae695..6c42a9cd7c 100644 +--- a/include/internal/namemap.h ++++ b/include/internal/namemap.h +@@ -18,8 +18,6 @@ void ossl_namemap_free(OSSL_NAMEMAP *namemap); + int ossl_namemap_empty(OSSL_NAMEMAP *namemap); + + int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name); +-int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number, +- const char *name, size_t name_len); + + /* + * The number<->name relationship is 1<->many +-- +2.33.0 + diff --git a/openssl.spec b/openssl.spec index 03cfcea3125acb1e230474db77898c7145865e27..ec6a792e85c8d4b73ee4a69d64ae51feb1471b6c 100644 --- a/openssl.spec +++ b/openssl.spec @@ -2,7 +2,7 @@ Name: openssl Epoch: 1 Version: 3.0.12 -Release: 11 +Release: 12 Summary: Cryptography and SSL/TLS Toolkit License: OpenSSL and SSLeay URL: https://www.openssl.org/ @@ -51,6 +51,21 @@ Patch39: Backport-CVE-2024-5535-Add-a-test-for-ALPN-and-NPN.patch Patch40: backport-Add-FIPS_mode-compatibility-macro.patch Patch41: Backport-CVE-2024-6119-Avoid-type-errors-in-EAI-related-name-check-logic.patch +Patch42: backport-Add-CTX-copy-function-for-EVP_MD-to-optimize-the-per.patch +Patch43: backport-Decoder-resolution-performance-optimizations.patch +Patch44: backport-Improve-performance-of-the-encoder-collection.patch +Patch45: backport-evp_md_init_internal-Avoid-reallocating-algctx-if-di.patch +Patch46: backport-Remove-the-_fetch_by_number-functions.patch +Patch47: backport-Make-IV-buf-in-prov_cipher_ctx_st-aligned.patch +Patch48: backport-ossl_namemap_name2_num-Avoid-unnecessary-OPENSSL_str.patch +Patch49: backport-performance-improve-ossl_lh_strcasehash.patch +Patch50: backport-01-Improve-FIPS-RSA-keygen-performance.patch +Patch51: backport-02-Improve-FIPS-RSA-keygen-performance.patch +Patch52: backport-When-we-re-just-reading-EX_CALLBACK-data-just-get-a-.patch +Patch53: backport-Avoid-an-unneccessary-lock-if-we-didn-t-add-anything.patch +Patch54: backport-use-__builtin_expect-to-improve-EVP_EncryptUpdate-pe.patch +Patch55: backport-Drop-ossl_namemap_add_name_n-and-simplify-ossl_namem.patch + Patch9000: add-FIPS_mode_set-support.patch Patch9001: backport-CVE-2024-9143-Harden-BN_GF2m_poly2arr-against-misuse.patch @@ -253,6 +268,9 @@ make test || : %ldconfig_scriptlets libs %changelog +* Fri Nov 22 2024 zhujianwei - 1:3.0.12-12 +- backport patch for performance improvements + * Thu Oct 17 2024 liningjie - 1:3.0.12-11 - fix CVE-2024-9143