From 0285160ffa3b8c2b5491222243042593808298c4 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 29 May 2024 16:32:19 +0200 Subject: [PATCH 001/138] Skip newly added blocked OAEP SHAKE testcases with old fips providers Reviewed-by: Paul Dale Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24529) --- test/recipes/30-test_evp_data/evppkey_rsa_common.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt index 9fa4094bcc16f..9cc007ad7b195 100644 --- a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt +++ b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt @@ -330,6 +330,7 @@ Output = "Hello World" # Decrypt OAEP SHAKE MGF1 Availablein = fips +FIPSversion = >=3.4.0 Decrypt = RSA-2048 Ctrl = rsa_padding_mode:oaep Ctrl = rsa_mgf1_md:shake128 @@ -338,6 +339,7 @@ Result = KEYOP_ERROR # Decrypt OAEP SHAKE MD Availablein = fips +FIPSversion = >=3.4.0 Decrypt = RSA-2048 Ctrl = rsa_padding_mode:oaep Ctrl = rsa_oaep_md:shake128 From ae20c423f9b86956267ea82bd678179e9d648bad Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 3 Jun 2024 16:46:41 +0200 Subject: [PATCH 002/138] Update CHANGES.md and NEWS.md for the upcoming release Reviewed-by: Matt Caswell Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/24549) (cherry picked from commit 6152b08631568551f155f9d8219298f55aef5d94) --- CHANGES.md | 25 +++++++++++++++++++++++++ NEWS.md | 20 +++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 2557ae113717f..49dbe58502630 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -100,6 +100,29 @@ OpenSSL 3.3 ### Changes between 3.3.0 and 3.3.1 [xx XXX xxxx] + * Fixed potential use after free after SSL_free_buffers() is called. + + The SSL_free_buffers function is used to free the internal OpenSSL + buffer used when processing an incoming record from the network. + The call is only expected to succeed if the buffer is not currently + in use. However, two scenarios have been identified where the buffer + is freed even when still in use. + + The first scenario occurs where a record header has been received + from the network and processed by OpenSSL, but the full record body + has not yet arrived. In this case calling SSL_free_buffers will succeed + even though a record has only been partially processed and the buffer + is still in use. + + The second scenario occurs where a full record containing application + data has been received and processed by OpenSSL but the application has + only read part of this data. Again a call to SSL_free_buffers will + succeed even though the buffer is still in use. + + ([CVE-2024-4741]) + + *Matt Caswell* + * Fixed an issue where checking excessively long DSA keys or parameters may be very slow. @@ -20702,6 +20725,8 @@ ndif +[CVE-2024-4741]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-4741 +[CVE-2024-4603]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-4603 [CVE-2024-2511]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-2511 [CVE-2024-0727]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-0727 [CVE-2023-6237]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6237 diff --git a/NEWS.md b/NEWS.md index 3196a06254184..bc8b40ee7353c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -33,7 +33,21 @@ This release is in development. OpenSSL 3.3 ----------- -### Major changes between OpenSSL 3.2 and OpenSSL 3.3 [under development] +### Major changes between OpenSSL 3.3.0 and OpenSSL 3.3.1 [under development] + +OpenSSL 3.3.1 is a security patch release. The most severe CVE fixed in this +release is Low. + +This release incorporates the following bug fixes and mitigations: + + * Fixed potential use after free after SSL_free_buffers() is called + ([CVE-2024-4741]) + + * Fixed an issue where checking excessively long DSA keys or parameters may + be very slow + ([CVE-2024-4603]) + +### Major changes between OpenSSL 3.2 and OpenSSL 3.3.0 [9 Apr 2024] OpenSSL 3.3.0 is a feature release adding significant new functionality to OpenSSL. @@ -171,8 +185,10 @@ This release incorporates the following bug fixes and mitigations: * Fixed PKCS12 Decoding crashes ([CVE-2024-0727]) + * Fixed excessive time spent checking invalid RSA public keys ([CVE-2023-6237]) + * Fixed POLY1305 MAC implementation corrupting vector registers on PowerPC CPUs which support PowerISA 2.07 ([CVE-2023-6129]) @@ -1725,6 +1741,8 @@ OpenSSL 0.9.x +[CVE-2024-4741]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-4741 +[CVE-2024-4603]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-4603 [CVE-2024-2511]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-2511 [CVE-2024-0727]: https://www.openssl.org/news/vulnerabilities.html#CVE-2024-0727 [CVE-2023-6237]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-6237 From 0e2567d7293d3204de66acca0ed55bda4f0c0768 Mon Sep 17 00:00:00 2001 From: "Randall S. Becker" Date: Wed, 22 May 2024 23:34:45 +0000 Subject: [PATCH 003/138] Disable 70-test_quic_multistream.t when building with PUT threads. The test recipe includes a TEST_skip when OpenSSL is built with _PUT_MODEL_ based on design assumptions for QUIC and incompatibility with PUT wrapper methods. Fixes: #24442 Fixes: #24431 Signed-off-by: Randall S. Becker Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24468) --- NOTES-NONSTOP.md | 3 +++ test/quic_multistream_test.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/NOTES-NONSTOP.md b/NOTES-NONSTOP.md index 09085967de68f..2b35151ec0a6f 100644 --- a/NOTES-NONSTOP.md +++ b/NOTES-NONSTOP.md @@ -35,6 +35,9 @@ for each on the TNS/X (L-Series) platform: The SPT threading model is no longer supported as of OpenSSL 3.2. +The PUT model is incompatible with the QUIC capability. This capability should +be disabled when building with PUT. + ### TNS/E Considerations The TNS/E platform is build using the same set of builds specifying `nse` diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index fb2daac879d46..c74488ebf72a3 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -5923,6 +5923,10 @@ OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") int setup_tests(void) { +#if defined (_PUT_MODEL_) + return TEST_skip("QUIC is not supported by this build"); +#endif + if (!test_skip_common_options()) { TEST_error("Error parsing test options\n"); return 0; From 23b6ef4894679aa0278c93de29007d1e695856ee Mon Sep 17 00:00:00 2001 From: Watson Ladd Date: Tue, 21 Nov 2023 12:59:05 -0500 Subject: [PATCH 004/138] Allow group methods to customize initialization for speed This commit also adds an implementation for P256 that avoids some expensive initialization of Montgomery arithmetic structures in favor of precomputation. Since ECC groups are not always cached by higher layers this brings significant savings to TLS handshakes. Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22746) --- CHANGES.md | 5 ++ crypto/bn/bn_mont.c | 42 +++++++++++++ crypto/ec/ec_curve.c | 36 +++++++++-- crypto/ec/ec_local.h | 1 + crypto/ec/ecp_nistz256.c | 128 ++++++++++++++++++++++++++++++++++++++- include/crypto/bn.h | 6 ++ test/ec_internal_test.c | 64 ++++++++++++++++++++ 7 files changed, 275 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 49dbe58502630..9918e10c972ba 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -95,6 +95,11 @@ OpenSSL 3.4 *Alexander Kanavin* + * ECC groups may now customize their initialization to save CPU by using + precomputed values. This is used by the P-256 implementation. + + *Watson Ladd* + OpenSSL 3.3 ----------- diff --git a/crypto/bn/bn_mont.c b/crypto/bn/bn_mont.c index 8b4c7900ad47f..7cd16c66ee8af 100644 --- a/crypto/bn/bn_mont.c +++ b/crypto/bn/bn_mont.c @@ -465,3 +465,45 @@ BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_RWLOCK *lock, CRYPTO_THREAD_unlock(lock); return ret; } + +int ossl_bn_mont_ctx_set(BN_MONT_CTX *ctx, const BIGNUM *modulus, int ri, const unsigned char *rr, + size_t rrlen, uint32_t nlo, uint32_t nhi) +{ + if (BN_copy(&ctx->N, modulus) == NULL) + return 0; + if (BN_bin2bn(rr, rrlen, &ctx->RR) == NULL) + return 0; + ctx->ri = ri; +#if (BN_BITS2 <= 32) && defined(OPENSSL_BN_ASM_MONT) + ctx->n0[0] = nlo; + ctx->n0[1] = nhi; +#elif BN_BITS2 <= 32 + ctx->n0[0] = nlo; + ctx->n0[1] = 0; +#else + ctx->n0[0] = ((BN_ULONG)nhi << 32)| nlo; + ctx->n0[1] = 0; +#endif + + return 1; +} + +int ossl_bn_mont_ctx_eq(const BN_MONT_CTX *m1, const BN_MONT_CTX *m2) +{ + if (m1->ri != m2->ri) + return 0; + if (BN_cmp(&m1->RR, &m2->RR) != 0) + return 0; + if (m1->flags != m2->flags) + return 0; +#ifdef MONT_WORD + if (m1->n0[0] != m2->n0[0]) + return 0; + if (m1->n0[1] != m2->n0[1]) + return 0; +#else + if (BN_cmp(&m1->Ni, &m2->Ni) != 0) + return 0; +#endif + return 1; +} diff --git a/crypto/ec/ec_curve.c b/crypto/ec/ec_curve.c index d703d16b3cae8..75feaa79d499c 100644 --- a/crypto/ec/ec_curve.c +++ b/crypto/ec/ec_curve.c @@ -383,7 +383,7 @@ static const struct { static const struct { EC_CURVE_DATA h; - unsigned char data[20 + 32 * 6]; + unsigned char data[20 + 32 * 8]; } _EC_X9_62_PRIME_256V1 = { { NID_X9_62_prime_field, 20, 32, 1 @@ -415,7 +415,15 @@ static const struct { /* order */ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, - 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, + /* RR for prime */ + 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + /* RR for order */ + 0x66, 0xe1, 0x2d, 0x94, 0xf3, 0xd9, 0x56, 0x20, 0x28, 0x45, 0xb2, 0x39, + 0x2b, 0x6b, 0xec, 0x59, 0x46, 0x99, 0x79, 0x9c, 0x49, 0xbd, 0x6f, 0xa6, + 0x83, 0x24, 0x4c, 0x95, 0xbe, 0x79, 0xee, 0xa2 } }; @@ -3168,6 +3176,24 @@ static EC_GROUP *ec_group_new_from_data(OSSL_LIB_CTX *libctx, seed_len = data->seed_len; param_len = data->param_len; params = (const unsigned char *)(data + 1); /* skip header */ + + if (curve.meth != NULL) { + meth = curve.meth(); + if ((group = ossl_ec_group_new_ex(libctx, propq, meth)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + if (group->meth->group_full_init != NULL) { + if (!group->meth->group_full_init(group, params)){ + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + EC_GROUP_set_curve_name(group, curve.nid); + BN_CTX_free(ctx); + return group; + } + } + params += seed_len; /* skip seed */ if ((p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) == NULL @@ -3177,10 +3203,8 @@ static EC_GROUP *ec_group_new_from_data(OSSL_LIB_CTX *libctx, goto err; } - if (curve.meth != 0) { - meth = curve.meth(); - if (((group = ossl_ec_group_new_ex(libctx, propq, meth)) == NULL) || - (!(group->meth->group_set_curve(group, p, a, b, ctx)))) { + if (group != NULL) { + if (group->meth->group_set_curve(group, p, a, b, ctx) == 0) { ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); goto err; } diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h index 2814d8739438f..a041db9c1335c 100644 --- a/crypto/ec/ec_local.h +++ b/crypto/ec/ec_local.h @@ -196,6 +196,7 @@ struct ec_method_st { int (*ladder_post)(const EC_GROUP *group, EC_POINT *r, EC_POINT *s, EC_POINT *p, BN_CTX *ctx); + int (*group_full_init)(EC_GROUP *group, const unsigned char *data); }; /* diff --git a/crypto/ec/ecp_nistz256.c b/crypto/ec/ecp_nistz256.c index 5760639a2ee24..765c344bec70a 100644 --- a/crypto/ec/ecp_nistz256.c +++ b/crypto/ec/ecp_nistz256.c @@ -1445,6 +1445,131 @@ static int ecp_nistz256_inv_mod_ord(const EC_GROUP *group, BIGNUM *r, # define ecp_nistz256_inv_mod_ord NULL #endif +static int ecp_nistz256group_full_init(EC_GROUP *group, + const unsigned char *params) { + BN_CTX *ctx = NULL; + BN_MONT_CTX *mont = NULL, *ordmont = NULL; + const int param_len = 32; + const int seed_len = 20; + int ok = 0; + uint32_t hi_order_n = 0xccd1c8aa; + uint32_t lo_order_n = 0xee00bc4f; + BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL, *one = NULL, + *order = NULL; + EC_POINT *P = NULL; + + if ((ctx = BN_CTX_new_ex(group->libctx)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!EC_GROUP_set_seed(group, params, seed_len)) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + params += seed_len; + + if ((p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) == NULL + || (a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) == NULL + || (b = BN_bin2bn(params + 2 * param_len, param_len, NULL)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); + goto err; + } + + /* + * Set up curve params and montgomery for field + * Start by setting up montgomery and one + */ + mont = BN_MONT_CTX_new(); + if (mont == NULL) + goto err; + + if (!ossl_bn_mont_ctx_set(mont, p, 256, params + 6 * param_len, param_len, + 1, 0)) + goto err; + + one = BN_new(); + if (one == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); + goto err; + } + if (!BN_to_montgomery(one, BN_value_one(), mont, ctx)){ + ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); + goto err; + } + group->field_data1 = mont; + mont = NULL; + group->field_data2 = one; + one = NULL; + + if (!ossl_ec_GFp_simple_group_set_curve(group, p, a, b, ctx)) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + + if ((P = EC_POINT_new(group)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + + if ((x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) == NULL + || (y = BN_bin2bn(params + 4 * param_len, param_len, NULL)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); + goto err; + } + if (!EC_POINT_set_affine_coordinates(group, P, x, y, ctx)) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + if ((order = BN_bin2bn(params + 5 * param_len, param_len, NULL)) == NULL + || !BN_set_word(x, (BN_ULONG)1)) { // cofactor is 1 + ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); + goto err; + } + + /* + * Set up generator and order and montgomery data + */ + group->generator = EC_POINT_new(group); + if (group->generator == NULL){ + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_copy(group->generator, P)) + goto err; + if (!BN_copy(group->order, order)) + goto err; + if (!BN_set_word(group->cofactor, 1)) + goto err; + + ordmont = BN_MONT_CTX_new(); + if (ordmont == NULL) + goto err; + if (!ossl_bn_mont_ctx_set(ordmont, order, 256, params + 7 * param_len, + param_len, lo_order_n, hi_order_n)) + goto err; + + group->mont_data = ordmont; + ordmont = NULL; + + ok = 1; + + err: + EC_POINT_free(P); + BN_CTX_free(ctx); + BN_MONT_CTX_free(mont); + BN_MONT_CTX_free(ordmont); + BN_free(p); + BN_free(one); + BN_free(a); + BN_free(b); + BN_free(order); + BN_free(x); + BN_free(y); + + return ok; +} + const EC_METHOD *EC_GFp_nistz256_method(void) { static const EC_METHOD ret = { @@ -1501,7 +1626,8 @@ const EC_METHOD *EC_GFp_nistz256_method(void) 0, /* blind_coordinates */ 0, /* ladder_pre */ 0, /* ladder_step */ - 0 /* ladder_post */ + 0, /* ladder_post */ + ecp_nistz256group_full_init }; return &ret; diff --git a/include/crypto/bn.h b/include/crypto/bn.h index 9a988a467de27..128cae3bf8558 100644 --- a/include/crypto/bn.h +++ b/include/crypto/bn.h @@ -135,3 +135,9 @@ int s390x_crt(BIGNUM *r, const BIGNUM *i, const BIGNUM *p, const BIGNUM *q, const BIGNUM *dmp, const BIGNUM *dmq, const BIGNUM *iqmp); #endif + +int ossl_bn_mont_ctx_set(BN_MONT_CTX *ctx, const BIGNUM *modulus, int ri, + const unsigned char *rr, size_t rrlen, + uint32_t nlo, uint32_t nhi); + +int ossl_bn_mont_ctx_eq(const BN_MONT_CTX *m1, const BN_MONT_CTX *m2); diff --git a/test/ec_internal_test.c b/test/ec_internal_test.c index 5076f9894d5b8..8e99f6210507d 100644 --- a/test/ec_internal_test.c +++ b/test/ec_internal_test.c @@ -16,6 +16,7 @@ #include "testutil.h" #include #include "ec_local.h" +#include #include static size_t crv_len = 0; @@ -433,6 +434,68 @@ int ecpkparams_i2d2i_test(int n) return testresult; } + +static int check_bn_mont_ctx(BN_MONT_CTX *mont, BIGNUM *mod, BN_CTX *ctx) +{ + int ret = 0; + BN_MONT_CTX *regenerated = BN_MONT_CTX_new(); + + if (!TEST_ptr(regenerated)) + return ret; + if (!TEST_ptr(mont)) + goto err; + + if (!TEST_true(BN_MONT_CTX_set(regenerated, mod, ctx))) + goto err; + + if (!TEST_true(ossl_bn_mont_ctx_eq(regenerated, mont))) + goto err; + + ret = 1; + + err: + BN_MONT_CTX_free(regenerated); + return ret; +} + +static int montgomery_correctness_test(EC_GROUP *group) +{ + int ret = 0; + BN_CTX *ctx = NULL; + + ctx = BN_CTX_new(); + if (!TEST_ptr(ctx)) + return ret; + if (!TEST_true(check_bn_mont_ctx(group->mont_data, group->order, ctx))) { + TEST_error("group order issue"); + goto err; + } + if (group->field_data1 != NULL) { + if (!TEST_true(check_bn_mont_ctx(group->field_data1, group->field, ctx))) + goto err; + } + ret = 1; + err: + BN_CTX_free(ctx); + return ret; +} + +static int named_group_creation_test(void) +{ + int ret = 0; + EC_GROUP *group = NULL; + + if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) + || !TEST_true(montgomery_correctness_test(group))) + goto err; + + ret = 1; + + err: + EC_GROUP_free(group); + return ret; +} + int setup_tests(void) { crv_len = EC_get_builtin_curves(NULL, 0); @@ -452,6 +515,7 @@ int setup_tests(void) ADD_TEST(set_private_key); ADD_TEST(decoded_flag_test); ADD_ALL_TESTS(ecpkparams_i2d2i_test, crv_len); + ADD_TEST(named_group_creation_test); return 1; } From 5bbdbce856c7ca132e039a24a315618484874c81 Mon Sep 17 00:00:00 2001 From: shridhar kalavagunta Date: Thu, 11 Apr 2024 20:42:37 -0500 Subject: [PATCH 005/138] Fix memory leak on error in crypto/conf/conf_mod.c Fixes #24111 Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24119) --- crypto/conf/conf_mod.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index ffdde5f467b2d..1ac3d9f7b7573 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -528,13 +528,14 @@ void CONF_modules_unload(int all) old_modules = ossl_rcu_deref(&supported_modules); new_modules = sk_CONF_MODULE_dup(old_modules); - to_delete = sk_CONF_MODULE_new_null(); if (new_modules == NULL) { ossl_rcu_write_unlock(module_list_lock); return; } + to_delete = sk_CONF_MODULE_new_null(); + /* unload modules in reverse order */ for (i = sk_CONF_MODULE_num(new_modules) - 1; i >= 0; i--) { md = sk_CONF_MODULE_value(new_modules, i); From a9fa07f47cea6a43d5ac4a3aa336ab34756c2e9b Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 5 Jun 2024 10:22:22 +0200 Subject: [PATCH 006/138] Drop the old PGP key fingerprint All public releases have the information of the new PGP key in doc/fingerprints.txt, so it is finally time to drop the old. Reviewed-by: Kurt Roeckx Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24563) --- doc/fingerprints.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/fingerprints.txt b/doc/fingerprints.txt index 9613cbac98486..bdcad1472309e 100644 --- a/doc/fingerprints.txt +++ b/doc/fingerprints.txt @@ -12,9 +12,6 @@ in the file named openssl-1.0.1h.tar.gz.asc. The following is the list of fingerprints for the keys that are currently in use to sign OpenSSL distributions: -OpenSSL OMC: -EFC0 A467 D613 CB83 C7ED 6D30 D894 E2CE 8B3D 79F5 - OpenSSL: BA54 73A2 B058 7B07 FB27 CF2D 2160 94DF D0CB 81EF From 417dad1e370b19f94682d1006cb54d10ac90b8ec Mon Sep 17 00:00:00 2001 From: Dmitry Misharov Date: Thu, 30 May 2024 16:12:37 +0200 Subject: [PATCH 007/138] add static analysis workflow for on-premise Coverity Connect Reviewed-by: Kurt Roeckx Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24534) --- .github/workflows/static-analysis-on-prem.yml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/static-analysis-on-prem.yml diff --git a/.github/workflows/static-analysis-on-prem.yml b/.github/workflows/static-analysis-on-prem.yml new file mode 100644 index 0000000000000..4c920fcad4b51 --- /dev/null +++ b/.github/workflows/static-analysis-on-prem.yml @@ -0,0 +1,39 @@ +# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +name: Static Analysis On Prem + +on: + schedule: + - cron: '20 0 * * *' + workflow_dispatch: + +permissions: + contents: read + +jobs: + coverity-analysis: + runs-on: ubuntu-latest + container: quay.io/openssl-ci/coverity-analysis:2024.3.1 + steps: + - name: Put license + run: echo ${{ secrets.COVERITY_LICENSE }} | base64 -d > /opt/coverity-analysis/bin/license.dat + - name: Put auth key file + run: | + echo ${{ secrets.COVERITY_AUTH_KEY }} | base64 -d > /auth_key_file.txt + chmod 0600 /auth_key_file.txt + - uses: actions/checkout@v4 + - name: Config + run: CC=gcc ./config --banner=Configured --debug enable-fips enable-rc5 enable-md2 enable-ssl3 enable-nextprotoneg enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-shared enable-buildtest-c++ enable-external-tests -DPEDANTIC + - name: Config dump + run: ./configdata.pm --dump + - name: Make + run: cov-build --dir cov-int make -s -j4 + - name: Analyze + run: cov-analyze --dir cov-int --strip-path $(pwd) + - name: Commit defects + run: cov-commit-defects --url https://coverity.openssl.org:443 --stream OpenSSL --dir cov-int --auth-key-file /auth_key_file.txt From 140540189c67ba94188165b1144fdfb5b248bc02 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 11 Apr 2024 11:34:57 +0200 Subject: [PATCH 008/138] test/prov_config_test.c: Cleanup and fix potential leaks Fixes #24106 Reviewed-by: Tom Cosgrove Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24107) --- test/prov_config_test.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/prov_config_test.c b/test/prov_config_test.c index 4f0cbc247b431..4dd9c67f7c0b8 100644 --- a/test/prov_config_test.c +++ b/test/prov_config_test.c @@ -26,15 +26,13 @@ static int test_double_config(void) int testresult = 0; EVP_MD *sha256 = NULL; - if (!TEST_ptr(configfile)) - return 0; if (!TEST_ptr(ctx)) return 0; if (!TEST_true(OSSL_LIB_CTX_load_config(ctx, configfile))) - return 0; + goto err; if (!TEST_true(OSSL_LIB_CTX_load_config(ctx, configfile))) - return 0; + goto err; /* Check we can actually fetch something */ sha256 = EVP_MD_fetch(ctx, "SHA2-256", NULL); @@ -54,9 +52,6 @@ static int test_recursive_config(void) int testresult = 0; unsigned long err; - if (!TEST_ptr(recurseconfigfile)) - goto err; - if (!TEST_ptr(ctx)) goto err; From d4700c0b237c05315e3bf14fc416abcbdfe51ff2 Mon Sep 17 00:00:00 2001 From: Ruslan Baratov Date: Thu, 23 May 2024 22:03:12 +0800 Subject: [PATCH 009/138] [Docs] Notes about freeing objects - Free objects returned from PEM read - Free objects returned from d2i_* Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24478) --- doc/man3/PEM_read_bio_PrivateKey.pod | 4 +++- doc/man3/d2i_X509.pod | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/man3/PEM_read_bio_PrivateKey.pod b/doc/man3/PEM_read_bio_PrivateKey.pod index 6e521b268f0db..290a5eef51b29 100644 --- a/doc/man3/PEM_read_bio_PrivateKey.pod +++ b/doc/man3/PEM_read_bio_PrivateKey.pod @@ -332,7 +332,9 @@ NULL but I<*x> is NULL then the structure returned will be written to I<*x>. If neither I nor I<*x> is NULL then an attempt is made to reuse the structure at I<*x> (but see BUGS and EXAMPLES sections). Irrespective of the value of I a pointer to the structure is always -returned (or NULL if an error occurred). +returned (or NULL if an error occurred). The caller retains ownership of the +returned object and needs to free it when it is no longer needed, e.g. +using X509_free() for X509 objects or EVP_PKEY_free() for EVP_PKEY objects. The PEM functions which write private keys take an I parameter which specifies the encryption algorithm to use, encryption is done diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 06f764ef8bb8c..1c0b5bf62526d 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -395,7 +395,9 @@ B>() attempts to decode I bytes at I<*ppin>. If successful a pointer to the B> structure is returned and I<*ppin> is incremented to the byte following the parsed data. If I is not NULL then a pointer to the returned structure is also written to I<*a>. If an error occurred -then NULL is returned. +then NULL is returned. The caller retains ownership of the +returned object and needs to free it when it is no longer needed, e.g. +using X509_free() for X509 objects or DSA_SIG_free() for DSA_SIG objects. On a successful return, if I<*a> is not NULL then it is assumed that I<*a> contains a valid B> structure and an attempt is made to reuse it. From 1977c00f00ad0546421a5ec0b40c1326aee4cddb Mon Sep 17 00:00:00 2001 From: Amir Mohammadi Date: Wed, 5 Jun 2024 22:26:19 +0330 Subject: [PATCH 010/138] Fix memory leak in quic_trace.c Fixes #24340 Reviewed-by: Ben Kaduk Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24568) --- ssl/quic/quic_trace.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ssl/quic/quic_trace.c b/ssl/quic/quic_trace.c index 5a6d79bf4bb53..c2ffdac9733f4 100644 --- a/ssl/quic/quic_trace.c +++ b/ssl/quic/quic_trace.c @@ -79,20 +79,21 @@ static int frame_ack(BIO *bio, PACKET *pkt) OSSL_QUIC_ACK_RANGE *ack_ranges = NULL; uint64_t total_ranges = 0; uint64_t i; + int ret = 0; if (!ossl_quic_wire_peek_frame_ack_num_ranges(pkt, &total_ranges) /* In case sizeof(uint64_t) > sizeof(size_t) */ || total_ranges > SIZE_MAX / sizeof(ack_ranges[0]) || (ack_ranges = OPENSSL_zalloc(sizeof(ack_ranges[0]) * (size_t)total_ranges)) == NULL) - return 0; + return ret; ack.ack_ranges = ack_ranges; ack.num_ack_ranges = (size_t)total_ranges; /* Ack delay exponent is 0, so we can get the raw delay time below */ if (!ossl_quic_wire_decode_frame_ack(pkt, 0, &ack, NULL)) - return 0; + goto end; BIO_printf(bio, " Largest acked: %llu\n", (unsigned long long)ack.ack_ranges[0].end); @@ -112,8 +113,10 @@ static int frame_ack(BIO *bio, PACKET *pkt) - ack.ack_ranges[i].start)); } + ret = 1; +end: OPENSSL_free(ack_ranges); - return 1; + return ret; } static int frame_reset_stream(BIO *bio, PACKET *pkt) From 6e01d3114b77c82cf83a2bfe53f7ba97840fbe36 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 5 Jun 2024 21:43:01 +0200 Subject: [PATCH 011/138] Configure: make absolutedir() use rel2abs() on Windows too perl's realpath() seems to be buggy on Windows, so we turn to rel2abs() there as well. Fixes #23593 Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24569) --- Configure | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Configure b/Configure index c15f5b2fffe26..73a95a000ddaf 100755 --- a/Configure +++ b/Configure @@ -3522,6 +3522,13 @@ sub absolutedir { return rel2abs($dir); } + # realpath() on Windows seems to check if the directory actually exists, + # which isn't what is wanted here. All we want to know is if a directory + # spec is absolute, not if it exists. + if ($^O eq "MSWin32") { + return rel2abs($dir); + } + # We use realpath() on Unix, since no other will properly clean out # a directory spec. use Cwd qw/realpath/; From f8acb534e41450d3e113e338caed8b15d4a3d5e6 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Wed, 6 Mar 2024 09:48:30 +0100 Subject: [PATCH 012/138] 80-test_cmp_http_data/test_connection.csv: disable localhost test as not supported on some hosts Fixes #22870 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/23756) --- test/recipes/80-test_cmp_http_data/test_connection.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/recipes/80-test_cmp_http_data/test_connection.csv b/test/recipes/80-test_cmp_http_data/test_connection.csv index 94916e89f37a2..83e746518df5d 100644 --- a/test/recipes/80-test_cmp_http_data/test_connection.csv +++ b/test/recipes/80-test_cmp_http_data/test_connection.csv @@ -2,7 +2,7 @@ expected,description, -section,val, -server,val, -proxy,val, -no_proxy,val, -tls ,Message transfer options:,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,, 1,default config, -section,,,,,,,,BLANK,,,,BLANK,,BLANK,,BLANK, -1,server domain name, -section,, -server,localhost:_SERVER_PORT,,,,,,,,,,,,,, +disabled as not supported by some host IP configurations,server domain name, -section,, -server,localhost:_SERVER_PORT,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,, 0,wrong server, -section,, -server,xn--rksmrgs-5wao1o.example.com:_SERVER_PORT,,,,,BLANK,,,, -msg_timeout,1,BLANK,,BLANK, 0,wrong server port, -section,, -server,_SERVER_HOST:99,,,,,BLANK,,,, -msg_timeout,1,BLANK,,BLANK, From b893ceef2feb6b64504446f984ee5a57d2b69d1f Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Mon, 11 Mar 2024 12:48:26 +0100 Subject: [PATCH 013/138] OSSL_CMP_validate_msg(): fix check such that OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR becomes usable again Fixes #23706 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/23814) --- crypto/cmp/cmp_vfy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index ec99ab7fe58dd..47bf38b2af5da 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -632,7 +632,7 @@ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) default: scrt = ctx->srvCert; if (scrt == NULL) { - if (ctx->trusted == NULL) { + if (ctx->trusted == NULL && ctx->secretValue != NULL) { ossl_cmp_info(ctx, "no trust store nor pinned server cert available for verifying signature-based CMP message protection"); ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR); return 0; From 40948c4c74099ae21843d9265dfe65f13cb9e6c5 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Mon, 11 Mar 2024 13:06:13 +0100 Subject: [PATCH 014/138] OSSL_CMP_{validate_msg,CTX_new}.pod: add warning notes on OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/23814) --- doc/man3/OSSL_CMP_CTX_new.pod | 5 +++++ doc/man3/OSSL_CMP_validate_msg.pod | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index 9d117e204a913..2f8e8dee513ec 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -343,6 +343,11 @@ RFC 4210. Allow retrieving a trust anchor from extraCerts and using that to validate the certificate chain of an IP message. + This is a quirk option added to support 3GPP TS 33.310. + + Note that using this option is dangerous as the certificate obtained + this way has not been authenticated (at least not at CMP level). + Taking it over as a trust anchor implements trust-on-first-use (TOFU). =item B diff --git a/doc/man3/OSSL_CMP_validate_msg.pod b/doc/man3/OSSL_CMP_validate_msg.pod index c416a49d77720..2fe94dabc8739 100644 --- a/doc/man3/OSSL_CMP_validate_msg.pod +++ b/doc/man3/OSSL_CMP_validate_msg.pod @@ -42,11 +42,14 @@ using any trust store set via L. If the option OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR was set by calling L, for an Initialization Response (IP) message -any self-issued certificate from the I extraCerts field may also be used -as trust anchor for the path verification of an acceptable cert if it can be +any self-issued certificate from the I extraCerts field may be used +as a trust anchor for the path verification of an 'acceptable' cert if it can be used also to validate the issued certificate returned in the IP message. This is according to TS 33.310 [Network Domain Security (NDS); Authentication Framework (AF)] document specified by the The 3rd Generation Partnership Project (3GPP). +Note that using this option is dangerous as the certificate obtained this way +has not been authenticated (at least not at CMP level). +Taking it over as a trust anchor implements trust-on-first-use (TOFU). Any cert that has been found as described above is cached and tried first when validating the signatures of subsequent messages in the same transaction. From 58301e24f66aa74b13b85a171dd14e6088c35662 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Sat, 1 Jun 2024 19:23:25 +0000 Subject: [PATCH 015/138] Add support for targetingInformation X.509v3 extension Support for the targetingInformation X.509v3 extension defined in ITU-T Recommendation X.509 (2019), Section 17.1.2.2. This extension is used in attribute certificates. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22206) --- crypto/x509/build.info | 2 +- crypto/x509/ext_dat.h | 1 + crypto/x509/standard_exts.h | 1 + crypto/x509/v3_ac_tgt.c | 239 ++++++++++++++++++++++++ crypto/x509/v3_crld.c | 16 +- crypto/x509/v3_utl.c | 13 ++ doc/build.info | 6 + doc/man3/OSSL_GENERAL_NAMES_print.pod | 36 ++++ doc/man3/X509_dup.pod | 12 ++ doc/man3/d2i_X509.pod | 12 ++ fuzz/asn1.c | 2 + include/crypto/x509_acert.h | 4 + include/openssl/x509_acert.h.in | 36 ++++ include/openssl/x509v3.h.in | 2 + test/certs/ext-targetingInformation.pem | 14 ++ test/recipes/25-test_x509.t | 31 ++- util/libcrypto.num | 16 ++ 17 files changed, 427 insertions(+), 16 deletions(-) create mode 100644 crypto/x509/v3_ac_tgt.c create mode 100644 doc/man3/OSSL_GENERAL_NAMES_print.pod create mode 100644 test/certs/ext-targetingInformation.pem diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 6cebadea77296..1184329b2052f 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -16,7 +16,7 @@ SOURCE[../../libcrypto]=\ pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \ v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_no_rev_avail.c \ v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ - x509_acert.c x509aset.c t_acert.c x_ietfatt.c + x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index 1ffc816e5eea3..8d34e829dc5f2 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -31,3 +31,4 @@ extern const X509V3_EXT_METHOD ossl_v3_no_assertion; extern const X509V3_EXT_METHOD ossl_v3_no_rev_avail; extern const X509V3_EXT_METHOD ossl_v3_single_use; extern const X509V3_EXT_METHOD ossl_v3_indirect_issuer; +extern const X509V3_EXT_METHOD ossl_v3_targeting_information; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index 87a564b238d6b..eba9e31dec819 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -53,6 +53,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { #endif &ossl_v3_sinfo, &ossl_v3_policy_constraints, + &ossl_v3_targeting_information, &ossl_v3_no_rev_avail, #ifndef OPENSSL_NO_OCSP &ossl_v3_crl_hold, diff --git a/crypto/x509/v3_ac_tgt.c b/crypto/x509/v3_ac_tgt.c new file mode 100644 index 0000000000000..c6b3701b4ec6b --- /dev/null +++ b/crypto/x509/v3_ac_tgt.c @@ -0,0 +1,239 @@ +/* + * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "internal/cryptlib.h" +#include +#include +#include +#include +#include "ext_dat.h" +#include "x509_local.h" +#include "crypto/asn1.h" + +static int i2r_ISSUER_SERIAL(X509V3_EXT_METHOD *method, + OSSL_ISSUER_SERIAL *iss, + BIO *out, int indent); +static int i2r_OBJECT_DIGEST_INFO(X509V3_EXT_METHOD *method, + OSSL_OBJECT_DIGEST_INFO *odi, + BIO *out, int indent); +static int i2r_TARGET_CERT(X509V3_EXT_METHOD *method, + OSSL_TARGET_CERT *tc, + BIO *out, int indent); +static int i2r_TARGET(X509V3_EXT_METHOD *method, + OSSL_TARGET *target, + BIO *out, int indent); +static int i2r_TARGETING_INFORMATION(X509V3_EXT_METHOD *method, + OSSL_TARGETING_INFORMATION *tinfo, + BIO *out, int indent); + +ASN1_SEQUENCE(OSSL_ISSUER_SERIAL) = { + ASN1_SEQUENCE_OF(OSSL_ISSUER_SERIAL, issuer, GENERAL_NAME), + ASN1_EMBED(OSSL_ISSUER_SERIAL, serial, ASN1_INTEGER), + ASN1_OPT(OSSL_ISSUER_SERIAL, issuerUID, ASN1_BIT_STRING), +} static_ASN1_SEQUENCE_END(OSSL_ISSUER_SERIAL) + +ASN1_SEQUENCE(OSSL_OBJECT_DIGEST_INFO) = { + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, digestedObjectType, ASN1_ENUMERATED), + ASN1_OPT(OSSL_OBJECT_DIGEST_INFO, otherObjectTypeID, ASN1_OBJECT), + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, digestAlgorithm, X509_ALGOR), + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, objectDigest, ASN1_BIT_STRING), +} static_ASN1_SEQUENCE_END(OSSL_OBJECT_DIGEST_INFO) + +ASN1_SEQUENCE(OSSL_TARGET_CERT) = { + ASN1_SIMPLE(OSSL_TARGET_CERT, targetCertificate, OSSL_ISSUER_SERIAL), + ASN1_OPT(OSSL_TARGET_CERT, targetName, GENERAL_NAME), + ASN1_OPT(OSSL_TARGET_CERT, certDigestInfo, OSSL_OBJECT_DIGEST_INFO), +} static_ASN1_SEQUENCE_END(OSSL_TARGET_CERT) + +ASN1_CHOICE(OSSL_TARGET) = { + ASN1_EXP(OSSL_TARGET, choice.targetName, GENERAL_NAME, 0), + ASN1_EXP(OSSL_TARGET, choice.targetGroup, GENERAL_NAME, 1), + ASN1_IMP(OSSL_TARGET, choice.targetCert, OSSL_TARGET_CERT, 2), +} ASN1_CHOICE_END(OSSL_TARGET) + +ASN1_ITEM_TEMPLATE(OSSL_TARGETS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Targets, OSSL_TARGET) +ASN1_ITEM_TEMPLATE_END(OSSL_TARGETS) + +ASN1_ITEM_TEMPLATE(OSSL_TARGETING_INFORMATION) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, TargetingInformation, OSSL_TARGETS) +ASN1_ITEM_TEMPLATE_END(OSSL_TARGETING_INFORMATION) + +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TARGET) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TARGETS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_TARGETING_INFORMATION) + +static int i2r_ISSUER_SERIAL(X509V3_EXT_METHOD *method, + OSSL_ISSUER_SERIAL *iss, + BIO *out, int indent) +{ + if (iss->issuer != NULL) { + BIO_printf(out, "%*sIssuer Names:\n", indent, ""); + OSSL_GENERAL_NAMES_print(out, iss->issuer, indent); + BIO_puts(out, "\n"); + } + BIO_printf(out, "%*sIssuer Serial: ", indent, ""); + if (i2a_ASN1_INTEGER(out, &(iss->serial)) <= 0) + return 0; + BIO_puts(out, "\n"); + if (iss->issuerUID != NULL) { + BIO_printf(out, "%*sIssuer UID: ", indent, ""); + if (i2a_ASN1_STRING(out, iss->issuerUID, V_ASN1_BIT_STRING) <= 0) + return 0; + BIO_puts(out, "\n"); + } + return 1; +} + +static int i2r_OBJECT_DIGEST_INFO(X509V3_EXT_METHOD *method, + OSSL_OBJECT_DIGEST_INFO *odi, + BIO *out, int indent) +{ + int64_t dot = 0; + int sig_nid; + X509_ALGOR *digalg; + ASN1_STRING *sig; + + if (odi == NULL) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + digalg = &odi->digestAlgorithm; + sig = &odi->objectDigest; + if (!ASN1_ENUMERATED_get_int64(&dot, &odi->digestedObjectType)) { + return 0; + } + switch (dot) { + case OSSL_ODI_TYPE_PUBLIC_KEY: + BIO_printf(out, "%*sDigest Type: Public Key\n", indent, ""); + break; + case OSSL_ODI_TYPE_PUBLIC_KEY_CERT: + BIO_printf(out, "%*sDigest Type: Public Key Certificate\n", indent, ""); + break; + case OSSL_ODI_TYPE_OTHER: + BIO_printf(out, "%*sDigest Type: Other\n", indent, ""); + break; + } + if (odi->otherObjectTypeID != NULL) { + BIO_printf(out, "%*sDigest Type Identifier: ", indent, ""); + i2a_ASN1_OBJECT(out, odi->otherObjectTypeID); + BIO_puts(out, "\n"); + } + if (BIO_printf(out, "%*sSignature Algorithm: ", indent, "") <= 0) + return 0; + if (i2a_ASN1_OBJECT(out, odi->digestAlgorithm.algorithm) <= 0) + return 0; + BIO_puts(out, "\n"); + if (BIO_printf(out, "\n%*sSignature Value: ", indent, "") <= 0) + return 0; + sig_nid = OBJ_obj2nid(odi->digestAlgorithm.algorithm); + if (sig_nid != NID_undef) { + int pkey_nid, dig_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) { + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth && ameth->sig_print) + return ameth->sig_print(out, digalg, sig, indent + 4, 0); + } + } + if (BIO_write(out, "\n", 1) != 1) + return 0; + if (sig) + return X509_signature_dump(out, sig, indent + 4); + return 1; +} + +static int i2r_TARGET_CERT(X509V3_EXT_METHOD *method, + OSSL_TARGET_CERT *tc, + BIO *out, int indent) +{ + BIO_printf(out, "%*s", indent, ""); + if (tc->targetCertificate != NULL) { + BIO_puts(out, "Target Certificate:\n"); + i2r_ISSUER_SERIAL(method, tc->targetCertificate, out, indent + 2); + } + if (tc->targetName != NULL) { + BIO_printf(out, "%*sTarget Name: ", indent, ""); + GENERAL_NAME_print(out, tc->targetName); + BIO_puts(out, "\n"); + } + if (tc->certDigestInfo != NULL) { + BIO_printf(out, "%*sCertificate Digest Info:\n", indent, ""); + i2r_OBJECT_DIGEST_INFO(method, tc->certDigestInfo, out, indent + 2); + } + BIO_puts(out, "\n"); + return 1; +} + +static int i2r_TARGET(X509V3_EXT_METHOD *method, + OSSL_TARGET *target, + BIO *out, int indent) +{ + switch (target->type) { + case OSSL_TGT_TARGET_NAME: + BIO_printf(out, "%*sTarget Name: ", indent, ""); + GENERAL_NAME_print(out, target->choice.targetName); + BIO_puts(out, "\n"); + break; + case OSSL_TGT_TARGET_GROUP: + BIO_printf(out, "%*sTarget Group: ", indent, ""); + GENERAL_NAME_print(out, target->choice.targetGroup); + BIO_puts(out, "\n"); + break; + case OSSL_TGT_TARGET_CERT: + BIO_printf(out, "%*sTarget Cert:\n", indent, ""); + i2r_TARGET_CERT(method, target->choice.targetCert, out, indent + 2); + break; + } + return 1; +} + +static int i2r_TARGETS(X509V3_EXT_METHOD *method, + OSSL_TARGETS *targets, + BIO *out, int indent) +{ + int i; + OSSL_TARGET *target; + + for (i = 0; i < sk_OSSL_TARGET_num(targets); i++) { + BIO_printf(out, "%*sTarget:\n", indent, ""); + target = sk_OSSL_TARGET_value(targets, i); + i2r_TARGET(method, target, out, indent + 2); + } + return 1; +} + +static int i2r_TARGETING_INFORMATION(X509V3_EXT_METHOD *method, + OSSL_TARGETING_INFORMATION *tinfo, + BIO *out, int indent) +{ + int i; + OSSL_TARGETS *targets; + + for (i = 0; i < sk_OSSL_TARGETS_num(tinfo); i++) { + BIO_printf(out, "%*sTargets:\n", indent, ""); + targets = sk_OSSL_TARGETS_value(tinfo, i); + i2r_TARGETS(method, targets, out, indent + 2); + } + return 1; +} + +const X509V3_EXT_METHOD ossl_v3_targeting_information = { + NID_target_information, 0, ASN1_ITEM_ref(OSSL_TARGETING_INFORMATION), + 0, 0, 0, 0, + 0, + 0, + 0, 0, + (X509V3_EXT_I2R)i2r_TARGETING_INFORMATION, + 0, + NULL +}; diff --git a/crypto/x509/v3_crld.c b/crypto/x509/v3_crld.c index 839b2c1afefc4..ae772cdd80aad 100644 --- a/crypto/x509/v3_crld.c +++ b/crypto/x509/v3_crld.c @@ -419,23 +419,11 @@ static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, return NULL; } -static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent) -{ - int i; - for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { - if (i > 0) - BIO_puts(out, "\n"); - BIO_printf(out, "%*s", indent + 2, ""); - GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i)); - } - return 1; -} - static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent) { if (dpn->type == 0) { BIO_printf(out, "%*sFull Name:\n", indent, ""); - print_gens(out, dpn->name.fullname, indent); + OSSL_GENERAL_NAMES_print(out, dpn->name.fullname, indent); } else { X509_NAME ntmp; ntmp.entries = dpn->name.relativename; @@ -486,7 +474,7 @@ static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, print_reasons(out, "Reasons", point->reasons, indent); if (point->CRLissuer) { BIO_printf(out, "%*sCRL Issuer:\n", indent, ""); - print_gens(out, point->CRLissuer, indent); + OSSL_GENERAL_NAMES_print(out, point->CRLissuer, indent); } } return 1; diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 1a18174995196..a036e9e9ad822 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1356,3 +1356,16 @@ int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE) *dn_sk, } return 1; } + +int OSSL_GENERAL_NAMES_print(BIO *out, GENERAL_NAMES *gens, int indent) +{ + int i; + + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + if (i > 0) + BIO_puts(out, "\n"); + BIO_printf(out, "%*s", indent + 2, ""); + GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i)); + } + return 1; +} diff --git a/doc/build.info b/doc/build.info index bff96a8a90a06..cb9c76b6a3fd4 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1711,6 +1711,10 @@ DEPEND[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_ GENERATE[html/man3/OSSL_ESS_check_signing_certs.html]=man3/OSSL_ESS_check_signing_certs.pod DEPEND[man/man3/OSSL_ESS_check_signing_certs.3]=man3/OSSL_ESS_check_signing_certs.pod GENERATE[man/man3/OSSL_ESS_check_signing_certs.3]=man3/OSSL_ESS_check_signing_certs.pod +DEPEND[html/man3/OSSL_GENERAL_NAMES_print.html]=man3/OSSL_GENERAL_NAMES_print.pod +GENERATE[html/man3/OSSL_GENERAL_NAMES_print.html]=man3/OSSL_GENERAL_NAMES_print.pod +DEPEND[man/man3/OSSL_GENERAL_NAMES_print.3]=man3/OSSL_GENERAL_NAMES_print.pod +GENERATE[man/man3/OSSL_GENERAL_NAMES_print.3]=man3/OSSL_GENERAL_NAMES_print.pod DEPEND[html/man3/OSSL_HPKE_CTX_new.html]=man3/OSSL_HPKE_CTX_new.pod GENERATE[html/man3/OSSL_HPKE_CTX_new.html]=man3/OSSL_HPKE_CTX_new.pod DEPEND[man/man3/OSSL_HPKE_CTX_new.3]=man3/OSSL_HPKE_CTX_new.pod @@ -3403,6 +3407,7 @@ html/man3/OSSL_ENCODER_CTX_new_for_pkey.html \ html/man3/OSSL_ENCODER_to_bio.html \ html/man3/OSSL_ERR_STATE_save.html \ html/man3/OSSL_ESS_check_signing_certs.html \ +html/man3/OSSL_GENERAL_NAMES_print.html \ html/man3/OSSL_HPKE_CTX_new.html \ html/man3/OSSL_HTTP_REQ_CTX.html \ html/man3/OSSL_HTTP_parse_url.html \ @@ -4059,6 +4064,7 @@ man/man3/OSSL_ENCODER_CTX_new_for_pkey.3 \ man/man3/OSSL_ENCODER_to_bio.3 \ man/man3/OSSL_ERR_STATE_save.3 \ man/man3/OSSL_ESS_check_signing_certs.3 \ +man/man3/OSSL_GENERAL_NAMES_print.3 \ man/man3/OSSL_HPKE_CTX_new.3 \ man/man3/OSSL_HTTP_REQ_CTX.3 \ man/man3/OSSL_HTTP_parse_url.3 \ diff --git a/doc/man3/OSSL_GENERAL_NAMES_print.pod b/doc/man3/OSSL_GENERAL_NAMES_print.pod new file mode 100644 index 0000000000000..84282ee71d865 --- /dev/null +++ b/doc/man3/OSSL_GENERAL_NAMES_print.pod @@ -0,0 +1,36 @@ +=pod + +=head1 NAME + +OSSL_GENERAL_NAMES_print - print GeneralNames in a human-friendly, multi-line +string + +=head1 SYNOPSIS + + #include + + int OSSL_GENERAL_NAMES_print(BIO *out, GENERAL_NAMES *gens, int indent); + +=head1 DESCRIPTION + +OSSL_GENERAL_NAMES_print() prints a human readable version of the GeneralNames +I to BIO I. Each line is indented by I spaces. + +=head1 RETURN VALUES + +OSSL_GENERAL_NAMES_print() always returns 1. + +=head1 HISTORY + +The functions described here were all added in OpenSSL 3.4. + +=head1 COPYRIGHT + +Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index 17100a45ffb5e..6333ba698585f 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -176,6 +176,18 @@ OSSL_CRMF_PKIPUBLICATIONINFO_new, OSSL_CRMF_SINGLEPUBINFO_free, OSSL_CRMF_SINGLEPUBINFO_it, OSSL_CRMF_SINGLEPUBINFO_new, +OSSL_TARGET_CERT_free, +OSSL_TARGET_CERT_it, +OSSL_TARGET_CERT_new, +OSSL_TARGET_free, +OSSL_TARGET_it, +OSSL_TARGET_new, +OSSL_TARGETING_INFORMATION_free, +OSSL_TARGETING_INFORMATION_it, +OSSL_TARGETING_INFORMATION_new, +OSSL_TARGETS_free, +OSSL_TARGETS_it, +OSSL_TARGETS_new, OSSL_IETF_ATTR_SYNTAX_VALUE_free, OSSL_IETF_ATTR_SYNTAX_VALUE_it, OSSL_IETF_ATTR_SYNTAX_VALUE_new, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 1c0b5bf62526d..373962e135161 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -101,6 +101,12 @@ d2i_OSSL_CRMF_PBMPARAMETER, d2i_OSSL_CRMF_PKIPUBLICATIONINFO, d2i_OSSL_CRMF_SINGLEPUBINFO, d2i_OSSL_IETF_ATTR_SYNTAX, +d2i_OSSL_ISSUER_SERIAL, +d2i_OSSL_OBJECT_DIGEST_INFO, +d2i_OSSL_TARGET_CERT, +d2i_OSSL_TARGET, +d2i_OSSL_TARGETING_INFORMATION, +d2i_OSSL_TARGETS, d2i_OTHERNAME, d2i_PBE2PARAM, d2i_PBEPARAM, @@ -276,6 +282,12 @@ i2d_OSSL_CRMF_PBMPARAMETER, i2d_OSSL_CRMF_PKIPUBLICATIONINFO, i2d_OSSL_CRMF_SINGLEPUBINFO, i2d_OSSL_IETF_ATTR_SYNTAX, +i2d_OSSL_ISSUER_SERIAL, +i2d_OSSL_OBJECT_DIGEST_INFO, +i2d_OSSL_TARGET_CERT, +i2d_OSSL_TARGET, +i2d_OSSL_TARGETING_INFORMATION, +i2d_OSSL_TARGETS, i2d_OTHERNAME, i2d_PBE2PARAM, i2d_PBEPARAM, diff --git a/fuzz/asn1.c b/fuzz/asn1.c index f7a019774b9dd..febb296ce924c 100644 --- a/fuzz/asn1.c +++ b/fuzz/asn1.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "internal/nelem.h" #include "fuzzer.h" @@ -174,6 +175,7 @@ static ASN1_ITEM_EXP *item_type[] = { #endif ASN1_ITEM_ref(SXNET), ASN1_ITEM_ref(SXNETID), + ASN1_ITEM_ref(OSSL_TARGETING_INFORMATION), ASN1_ITEM_ref(USERNOTICE), ASN1_ITEM_ref(X509), ASN1_ITEM_ref(X509_ALGOR), diff --git a/include/crypto/x509_acert.h b/include/crypto/x509_acert.h index 3223bf623447f..faf6bf50e9773 100644 --- a/include/crypto/x509_acert.h +++ b/include/crypto/x509_acert.h @@ -13,6 +13,10 @@ # include +#define OSSL_ODI_TYPE_PUBLIC_KEY 0 +#define OSSL_ODI_TYPE_PUBLIC_KEY_CERT 1 +#define OSSL_ODI_TYPE_OTHER 2 + struct ossl_object_digest_info_st { ASN1_ENUMERATED digestedObjectType; ASN1_OBJECT *otherObjectTypeID; diff --git a/include/openssl/x509_acert.h.in b/include/openssl/x509_acert.h.in index 42376a6cb763e..70facf8ecc8d5 100644 --- a/include/openssl/x509_acert.h.in +++ b/include/openssl/x509_acert.h.in @@ -153,4 +153,40 @@ int OSSL_IETF_ATTR_SYNTAX_add1_value(OSSL_IETF_ATTR_SYNTAX *a, int type, void *data); int OSSL_IETF_ATTR_SYNTAX_print(BIO *bp, OSSL_IETF_ATTR_SYNTAX *a, int indent); +struct TARGET_CERT_st { + OSSL_ISSUER_SERIAL *targetCertificate; + GENERAL_NAME *targetName; + OSSL_OBJECT_DIGEST_INFO *certDigestInfo; +}; + +typedef struct TARGET_CERT_st OSSL_TARGET_CERT; + +# define OSSL_TGT_TARGET_NAME 0 +# define OSSL_TGT_TARGET_GROUP 1 +# define OSSL_TGT_TARGET_CERT 2 + +typedef struct TARGET_st { + int type; + union { + GENERAL_NAME *targetName; + GENERAL_NAME *targetGroup; + OSSL_TARGET_CERT *targetCert; + } choice; +} OSSL_TARGET; + +typedef STACK_OF(OSSL_TARGET) OSSL_TARGETS; +typedef STACK_OF(OSSL_TARGETS) OSSL_TARGETING_INFORMATION; + +{- + generate_stack_macros("OSSL_TARGET"); +-} + +{- + generate_stack_macros("OSSL_TARGETS"); +-} + +DECLARE_ASN1_FUNCTIONS(OSSL_TARGET) +DECLARE_ASN1_FUNCTIONS(OSSL_TARGETS) +DECLARE_ASN1_FUNCTIONS(OSSL_TARGETING_INFORMATION) + #endif diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index a967064f4c4b5..7c2313e424881 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1019,6 +1019,8 @@ const ASN1_PRINTABLESTRING *PROFESSION_INFO_get0_registrationNumber( void PROFESSION_INFO_set0_registrationNumber( PROFESSION_INFO *pi, ASN1_PRINTABLESTRING *rn); +int OSSL_GENERAL_NAMES_print(BIO *out, GENERAL_NAMES *gens, int indent); + # ifdef __cplusplus } # endif diff --git a/test/certs/ext-targetingInformation.pem b/test/certs/ext-targetingInformation.pem new file mode 100644 index 0000000000000..0ce3998ab246e --- /dev/null +++ b/test/certs/ext-targetingInformation.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICKzCCAhegAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMwMTI1 +NDEzWhgPMjAyMTA4MzAxMjU0MTNaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABo4GxMIGuMIGrBgNVHTcEgaMwgaAw +OqAgpB4wHDEaMBgGA1UEAwwRV2lsZGJvYXIgU29mdHdhcmWhFoIUd2lsZGJvYXJz +b2Z0d2FyZS5jb20wYqJgMDEwJaQeMBwxGjAYBgNVBAMMEVdpbGRib2FyIFNvZnR3 +YXJliANVBAMCBAECAwQDAgOwgRVqb25hdGhhbkB3aWxidXIuc3BhY2UwFAoBADAL +BgkqhkiG9w0BAQUDAgIkMAsGCSqGSIb3DQEBBQMBAA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index c727e5cdb3dcf..2ae13df615adb 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 51; +plan tests => 60; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -143,6 +143,35 @@ cert_contains(srctop_file(@certs, "ext-indirectIssuer.pem"), "Indirect Issuer", 1, 'X.509 Indirect Issuer'); +my $tgt_info_cert = srctop_file(@certs, "ext-targetingInformation.pem"); +cert_contains($tgt_info_cert, + "AC Targeting", + 1, 'X.509 Targeting Information Extension'); +cert_contains($tgt_info_cert, + "Targets:", + 1, 'X.509 Targeting Information Targets'); +cert_contains($tgt_info_cert, + "Target:", + 1, 'X.509 Targeting Information Target'); +cert_contains($tgt_info_cert, + "Target Name: DirName:CN = W", + 1, 'X.509 Targeting Information Target Name'); +cert_contains($tgt_info_cert, + "Target Group: DNS:wildboarsoftware.com", + 1, 'X.509 Targeting Information Target Name'); +cert_contains($tgt_info_cert, + "Issuer Names:", + 1, 'X.509 Targeting Information Issuer Names'); +cert_contains($tgt_info_cert, + "Issuer Serial: 01020304", + 1, 'X.509 Targeting Information Issuer Serial'); +cert_contains($tgt_info_cert, + "Issuer UID: B0", + 1, 'X.509 Targeting Information Issuer UID'); +cert_contains($tgt_info_cert, + "Digest Type: Public Key", + 1, 'X.509 Targeting Information Object Digest Type'); + sub test_errors { # actually tests diagnostics of OSSL_STORE my ($expected, $cert, @opts) = @_; my $infile = srctop_file(@certs, $cert); diff --git a/util/libcrypto.num b/util/libcrypto.num index e0474a0021dd9..526cc59355dce 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5647,3 +5647,19 @@ X509_ACERT_add_attr_nconf ? 3_4_0 EXIST::FUNCTION: OSSL_LIB_CTX_get_conf_diagnostics ? 3_4_0 EXIST::FUNCTION: OSSL_LIB_CTX_set_conf_diagnostics ? 3_4_0 EXIST::FUNCTION: OSSL_LIB_CTX_get_data ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_TARGET ? 3_4_0 EXIST::FUNCTION: +i2d_OSSL_TARGET ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGET_free ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGET_new ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGET_it ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_TARGETS ? 3_4_0 EXIST::FUNCTION: +i2d_OSSL_TARGETS ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETS_free ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETS_new ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETS_it ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_TARGETING_INFORMATION ? 3_4_0 EXIST::FUNCTION: +i2d_OSSL_TARGETING_INFORMATION ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETING_INFORMATION_free ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETING_INFORMATION_new ? 3_4_0 EXIST::FUNCTION: +OSSL_TARGETING_INFORMATION_it ? 3_4_0 EXIST::FUNCTION: +OSSL_GENERAL_NAMES_print ? 3_4_0 EXIST::FUNCTION: From 929fcc57125b8ed3cc58b254bdc1790a8136247e Mon Sep 17 00:00:00 2001 From: "Randall S. Becker" Date: Thu, 6 Jun 2024 20:57:10 +0000 Subject: [PATCH 016/138] Remove configuration targets and related documentation for Guardian builds. The intermediate configuration items to support Guardian builds are left in place as a convenience for users who want to set up configurations for Guardian on their own. Fixes: #22175 Signed-off-by: Randall S. Becker Reviewed-by: Richard Levitte Reviewed-by: Tomas Mraz Reviewed-by: Tom Cosgrove Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/24579) --- Configurations/50-nonstop.conf | 25 ------------------------- NOTES-NONSTOP.md | 13 ++----------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/Configurations/50-nonstop.conf b/Configurations/50-nonstop.conf index 7a5c5dcd454ad..572c5a5de8b5b 100644 --- a/Configurations/50-nonstop.conf +++ b/Configurations/50-nonstop.conf @@ -211,18 +211,6 @@ multibin => '64-put', disable => ['atexit'], }, - 'nonstop-nsx_g' => { - inherit_from => [ 'nonstop-common', - 'nonstop-archenv-x86_64-guardian', - 'nonstop-ilp32', 'nonstop-nfloat-x86_64' ], - disable => ['threads','atexit'], - }, - 'nonstop-nsx_g_tandem' => { - inherit_from => [ 'nonstop-common', - 'nonstop-archenv-x86_64-guardian', - 'nonstop-ilp32', 'nonstop-tfloat-x86_64' ], - disable => ['threads','atexit'], - }, 'nonstop-nsv' => { inherit_from => [ 'nonstop-nsx' ], }, @@ -262,16 +250,3 @@ multibin => '64-put', disable => ['atexit'], }, - 'nonstop-nse_g' => { - inherit_from => [ 'nonstop-common', - 'nonstop-archenv-itanium-guardian', - 'nonstop-ilp32', 'nonstop-nfloat-itanium' ], - disable => ['threads','atexit'], - }, - - 'nonstop-nse_g_tandem' => { - inherit_from => [ 'nonstop-common', - 'nonstop-archenv-itanium-guardian', - 'nonstop-ilp32', 'nonstop-tfloat-itanium' ], - disable => ['threads','atexit'], - }, diff --git a/NOTES-NONSTOP.md b/NOTES-NONSTOP.md index 2b35151ec0a6f..0ef99513bc9ac 100644 --- a/NOTES-NONSTOP.md +++ b/NOTES-NONSTOP.md @@ -217,15 +217,12 @@ Example Configure Targets ------------------------- For OSS targets, the main DLL names will be `libssl.so` and `libcrypto.so`. -For GUARDIAN targets, DLL names will be `ssl` and `crypto`. The following -assumes that your PWD is set according to your installation standards. +The following assumes that your PWD is set according to your installation +standards. ./Configure nonstop-nsx --prefix=${PWD} \ --openssldir=${PWD}/ssl no-threads \ --with-rand-seed=rdcpu ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} - ./Configure nonstop-nsx_g --prefix=${PWD} \ - --openssldir=${PWD}/ssl no-threads \ - --with-rand-seed=rdcpu ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} ./Configure nonstop-nsx_put --prefix=${PWD} \ --openssldir=${PWD}/ssl threads "-D_REENTRANT" \ --with-rand-seed=rdcpu ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} @@ -235,9 +232,6 @@ assumes that your PWD is set according to your installation standards. ./Configure nonstop-nsx_64_put --prefix=${PWD} \ --openssldir=${PWD}/ssl threads "-D_REENTRANT" \ --with-rand-seed=rdcpu ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} - ./Configure nonstop-nsx_g_tandem --prefix=${PWD} \ - --openssldir=${PWD}/ssl no-threads \ - --with-rand-seed=rdcpu ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} ./Configure nonstop-nse --prefix=${PWD} \ --openssldir=${PWD}/ssl no-threads \ @@ -254,6 +248,3 @@ assumes that your PWD is set according to your installation standards. ./Configure nonstop-nse_64_put --prefix=${PWD} \ --openssldir=${PWD}/ssl threads "-D_REENTRANT" --with-rand-seed=egd ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} - ./Configure nonstop-nse_g_tandem --prefix=${PWD} \ - --openssldir=${PWD}/ssl no-threads \ - --with-rand-seed=egd ${CIPHENABLES} ${DBGFLAG} ${SYSTEMLIBS} From 7301759afedffaf2f106495b3b171de9abfa2d2a Mon Sep 17 00:00:00 2001 From: sashan Date: Wed, 22 May 2024 09:16:49 +0200 Subject: [PATCH 017/138] fix potential memory leak in PKCS12_add_key_ex() function must make sure memorry allocated for `p8` gets freed in error path. Issue reported by LuMingYinDetect Fixes #24453 Reviewed-by: Tomas Mraz Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/24456) --- crypto/pkcs12/p12_crt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crypto/pkcs12/p12_crt.c b/crypto/pkcs12/p12_crt.c index 2e40dd93c2841..9f94dce80633f 100644 --- a/crypto/pkcs12/p12_crt.c +++ b/crypto/pkcs12/p12_crt.c @@ -249,16 +249,19 @@ PKCS12_SAFEBAG *PKCS12_add_key_ex(STACK_OF(PKCS12_SAFEBAG) **pbags, if (key_usage && !PKCS8_add_keyusage(p8, key_usage)) goto err; if (nid_key != -1) { + /* This call does not take ownership of p8 */ bag = PKCS12_SAFEBAG_create_pkcs8_encrypt_ex(nid_key, pass, -1, NULL, 0, iter, p8, ctx, propq); - PKCS8_PRIV_KEY_INFO_free(p8); - } else + } else { bag = PKCS12_SAFEBAG_create0_p8inf(p8); + if (bag != NULL) + p8 = NULL; /* bag takes ownership of p8 */ + } + /* This does not need to be in the error path */ + if (p8 != NULL) + PKCS8_PRIV_KEY_INFO_free(p8); - if (!bag) - goto err; - - if (!pkcs12_add_bag(pbags, bag)) + if (bag == NULL || !pkcs12_add_bag(pbags, bag)) goto err; return bag; From f4b4a185b546044150821f1929e5cd6fd0dfba99 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Mon, 27 May 2024 21:35:56 +1000 Subject: [PATCH 018/138] MVP demo TLS server - No concurrency, one client-at-a-time - Blocking - No client certs - Fixed chain and key file names - Minimal support for session resumption Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/24505) --- demos/guide/Makefile | 12 +- demos/guide/tls-server-block.c | 284 +++++++++++++++++++ doc/build.info | 6 + doc/man7/ossl-guide-introduction.pod | 2 + doc/man7/ossl-guide-tls-client-block.pod | 3 + doc/man7/ossl-guide-tls-introduction.pod | 10 +- doc/man7/ossl-guide-tls-server-block.pod | 329 +++++++++++++++++++++++ 7 files changed, 641 insertions(+), 5 deletions(-) create mode 100644 demos/guide/tls-server-block.c create mode 100644 doc/man7/ossl-guide-tls-server-block.pod diff --git a/demos/guide/Makefile b/demos/guide/Makefile index 29a0fd56e4072..943d2f3ee78d3 100644 --- a/demos/guide/Makefile +++ b/demos/guide/Makefile @@ -5,6 +5,7 @@ # LD_LIBRARY_PATH=../.. ./tls-client-block www.example.com 443 TESTS = tls-client-block \ + tls-server-block \ quic-client-block \ quic-multi-stream \ tls-client-non-block \ @@ -14,21 +15,28 @@ CFLAGS = -I../../include -g -Wall LDFLAGS = -L../.. LDLIBS = -lcrypto -lssl -all: $(TESTS) +all: $(TESTS) chain tls-client-block: tls-client-block.o +tls-server-block: tls-server-block.o quic-client-block: quic-client-block.o quic-multi-stream: quic-multi-stream.o tls-client-non-block: tls-client-non-block.o quic-client-non-block: quic-client-non-block.o +chain: chain.pem +pkey.pem: + openssl genpkey -algorithm rsa -out pkey.pem -pkeyopt rsa_keygen_bits:2048 +chain.pem: pkey.pem + openssl req -x509 -new -key pkey.pem -days 36500 -subj / -out chain.pem + $(TESTS): $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS) clean: $(RM) $(TESTS) *.o -.PHONY: test +.PHONY: test chain test: all @echo "\nTLS and QUIC tests:" @echo "skipped" diff --git a/demos/guide/tls-server-block.c b/demos/guide/tls-server-block.c new file mode 100644 index 0000000000000..45246ce4fe0fd --- /dev/null +++ b/demos/guide/tls-server-block.c @@ -0,0 +1,284 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * NB: Changes to this file should also be reflected in + * doc/man7/ossl-guide-tls-server-block.pod + */ + +#include + +/* Include the appropriate header file for SOCK_STREAM */ +#ifdef _WIN32 /* Windows */ +# include +# include +#else /* Linux/Unix */ +# include +# include +# include +#endif + +#include +#include +#include + +static const char cache_id[] = "OpenSSL Demo Server"; + +#ifdef _WIN32 +static const char *progname; + +static void vwarnx(const char *fmt, va_list ap) +{ + if (progname != NULL) + fprintf(stderr, "%s: ", progname); + vfprintf(stderr, fmt, ap); + putc('\n', stderr); +} + +static void errx(int status, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); + exit(status); +} + +static void warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} +#endif + +/* Minimal TLS echo server. */ +int main(int argc, char *argv[]) +{ + int res = EXIT_FAILURE; + long opts; + const char *hostport; + SSL_CTX *ctx = NULL; + BIO *acceptor_bio; + +#ifdef _WIN32 + progname = argv[0]; +#endif + + if (argc != 2) + errx(res, "Usage: %s [host:]port", argv[0]); + hostport = argv[1]; + + /* + * An SSL_CTX holds shared configuration information for multiple + * subsequent per-client SSL connections. + */ + ctx = SSL_CTX_new(TLS_server_method()); + if (ctx == NULL) { + ERR_print_errors_fp(stderr); + errx(res, "Failed to create server SSL_CTX"); + } + + /* + * TLS versions older than TLS 1.2 are deprecated by IETF and SHOULD + * be avoided if possible. + */ + if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Failed to set the minimum TLS protocol version"); + } + +#if 0 + /* + * In applications (e.g. SMTP) where most clients are performing + * unauthenticated opportunistic TLS it may make sense to set the security + * level to 0, allowing weaker encryption parameters, which are still + * stronger than a potential cleartext fallback. + * + * The default security level is 2 (as of OpenSSL 3.2), which is roughly + * equivalent to that of 112 bit symmetric keys, or 2048-bit RSA or + * finite-field Diffie-Hellman keys. Notably, non-zero security levels no + * longer allow the use of SHA-1 in certificate signatures, key exchange + * or in the TLS 1.[01] PRF (so TLS 1.0 and 1.1 require security level 0). + */ + SSL_CTX_set_security_level(ctx, 0); +#endif + + /* + * Tolerate clients hanging up without a TLS "shutdown". Appropriate in all + * application protocols which perform their own message "framing", and + * don't rely on TLS to defend against "truncation" attacks. + */ + opts = SSL_OP_IGNORE_UNEXPECTED_EOF; + + /* + * Block potential CPU-exhaustion attacks by clients that request frequent + * renegotiation. This is of course only effective if there are existing + * limits on initial full TLS handshake or connection rates. + */ + opts |= SSL_OP_NO_RENEGOTIATION; + + /* + * Most servers elect to use their own cipher preference rather than that of + * the client. + */ + opts |= SSL_OP_CIPHER_SERVER_PREFERENCE; + + /* Apply the selection options */ + SSL_CTX_set_options(ctx, opts); + + /* + * Load the server's certificate *chain* file (PEM format), which includes + * not only the leaf (end-entity) server certificate, but also any + * intermediate issuer-CA certificates. The leaf certificate must be the + * first certificate in the file. + * + * In advanced use-cases this can be called multiple times, once per public + * key algorithm for which the server has a corresponding certificate. + * However, the corresponding private key (see below) must be loaded first, + * *before* moving on to the next chain file. + * + * The requisite files "chain.pem" and "pkey.pem" can be generated by running + * "make chain" in this directory. If the server will be executed from some + * other directory, move or copy the files there. + */ + if (SSL_CTX_use_certificate_chain_file(ctx, "chain.pem") <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Failed to load the server certificate chain file"); + } + + /* + * Load the corresponding private key, this also checks that the private + * key matches the just loaded end-entity certificate. It does not check + * whether the certificate chain is valid, the certificates could be + * expired, or may otherwise fail to form a chain that a client can validate. + */ + if (SSL_CTX_use_PrivateKey_file(ctx, "pkey.pem", SSL_FILETYPE_PEM) <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error loading the server private key file, " + "possible key/cert mismatch???"); + } + + /* + * Servers that want to enable session resumption must specify a cache id + * byte array, that identifies the server application, and reduces the + * chance of inappropriate cache sharing. + */ + SSL_CTX_set_session_id_context(ctx, (void *)cache_id, sizeof(cache_id)); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); + + /* + * How many client TLS sessions to cache. The default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (20k in recent OpenSSL versions), + * which may be too small or too large. + */ + SSL_CTX_sess_set_cache_size(ctx, 1024); + + /* + * Sessions older than this are considered a cache miss even if still in + * the cache. The default is two hours. Busy servers whose clients make + * many connections in a short burst may want a shorter timeout, on lightly + * loaded servers with sporadic connections from any given client, a longer + * time may be appropriate. + */ + SSL_CTX_set_timeout(ctx, 3600); + + /* + * Clients rarely employ certificate-based authentication, and so we don't + * require "mutual" TLS authentication (indeed there's no way to know + * whether or how the client authenticated the server, so the term "mutual" + * is potentially misleading). + * + * Since we're not soliciting or processing client certificates, we don't + * need to configure a trusted-certificate store, so no call to + * SSL_CTX_set_default_verify_paths() is needed. The server's own + * certificate chain is assumed valid. + */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + + /* + * Create a listener socket wrapped in a BIO. + * The first call to BIO_do_accept() initialises the socket + */ + acceptor_bio = BIO_new_accept(hostport); + if (acceptor_bio == NULL) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error creating acceptor bio"); + } + + BIO_set_bind_mode(acceptor_bio, BIO_BIND_REUSEADDR); + if (BIO_do_accept(acceptor_bio) <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error setting up acceptor socket"); + } + + /* Wait for incoming connection */ + for (;;) { + BIO *client_bio; + SSL *ssl; + unsigned char buf[8192]; + size_t nread; + size_t nwritten; + size_t total = 0; + + /* Pristine error stack for each new connection */ + ERR_clear_error(); + + /* Wait for the next client to connect */ + if (BIO_do_accept(acceptor_bio) <= 0) { + /* Client went away before we accepted the connection */ + continue; + } + + /* Pop the client connection from the BIO chain */ + client_bio = BIO_pop(acceptor_bio); + fprintf(stderr, "New client connection accepted\n"); + + /* Associate a new SSL handle with the new connection */ + if ((ssl = SSL_new(ctx)) == NULL) { + ERR_print_errors_fp(stderr); + warnx("Error creating SSL handle for new connection"); + BIO_free(client_bio); + continue; + } + SSL_set_bio(ssl, client_bio, client_bio); + + /* Attempt an SSL handshake with the client */ + if (SSL_accept(ssl) <= 0) { + ERR_print_errors_fp(stderr); + warnx("Error performing SSL handshake with client"); + SSL_free(ssl); + continue; + } + + while (SSL_read_ex(ssl, buf, sizeof(buf), &nread) > 0) { + if (SSL_write_ex(ssl, buf, nread, &nwritten) > 0 && + nwritten == nread) { + total += nwritten; + continue; + } + warnx("Error echoing client input"); + break; + } + fprintf(stderr, "Client connection closed, %zu bytes sent\n", total); + SSL_free(ssl); + } + + /* + * Unreachable placeholder cleanup code, the above loop runs forever. + */ + SSL_CTX_free(ctx); + return EXIT_SUCCESS; +} diff --git a/doc/build.info b/doc/build.info index cb9c76b6a3fd4..f84364dba24be 100644 --- a/doc/build.info +++ b/doc/build.info @@ -4919,6 +4919,10 @@ DEPEND[html/man7/ossl-guide-tls-introduction.html]=man7/ossl-guide-tls-introduct GENERATE[html/man7/ossl-guide-tls-introduction.html]=man7/ossl-guide-tls-introduction.pod DEPEND[man/man7/ossl-guide-tls-introduction.7]=man7/ossl-guide-tls-introduction.pod GENERATE[man/man7/ossl-guide-tls-introduction.7]=man7/ossl-guide-tls-introduction.pod +DEPEND[html/man7/ossl-guide-tls-server-block.html]=man7/ossl-guide-tls-server-block.pod +GENERATE[html/man7/ossl-guide-tls-server-block.html]=man7/ossl-guide-tls-server-block.pod +DEPEND[man/man7/ossl-guide-tls-server-block.7]=man7/ossl-guide-tls-server-block.pod +GENERATE[man/man7/ossl-guide-tls-server-block.7]=man7/ossl-guide-tls-server-block.pod DEPEND[html/man7/ossl_store-file.html]=man7/ossl_store-file.pod GENERATE[html/man7/ossl_store-file.html]=man7/ossl_store-file.pod DEPEND[man/man7/ossl_store-file.7]=man7/ossl_store-file.pod @@ -5135,6 +5139,7 @@ html/man7/ossl-guide-quic-multi-stream.html \ html/man7/ossl-guide-tls-client-block.html \ html/man7/ossl-guide-tls-client-non-block.html \ html/man7/ossl-guide-tls-introduction.html \ +html/man7/ossl-guide-tls-server-block.html \ html/man7/ossl_store-file.html \ html/man7/ossl_store.html \ html/man7/passphrase-encoding.html \ @@ -5279,6 +5284,7 @@ man/man7/ossl-guide-quic-multi-stream.7 \ man/man7/ossl-guide-tls-client-block.7 \ man/man7/ossl-guide-tls-client-non-block.7 \ man/man7/ossl-guide-tls-introduction.7 \ +man/man7/ossl-guide-tls-server-block.7 \ man/man7/ossl_store-file.7 \ man/man7/ossl_store.7 \ man/man7/passphrase-encoding.7 \ diff --git a/doc/man7/ossl-guide-introduction.pod b/doc/man7/ossl-guide-introduction.pod index b6c1f955bb4f2..4fd94f02723f3 100644 --- a/doc/man7/ossl-guide-introduction.pod +++ b/doc/man7/ossl-guide-introduction.pod @@ -79,6 +79,8 @@ The pages in the guide are as follows: =item L: Writing a simple nonblocking TLS client +=item L: Writing a simple blocking TLS server + =item L: An introduction to QUIC in OpenSSL =item L: Writing a simple blocking QUIC client diff --git a/doc/man7/ossl-guide-tls-client-block.pod b/doc/man7/ossl-guide-tls-client-block.pod index 8f72fe3a1c034..34c6b36517e73 100644 --- a/doc/man7/ossl-guide-tls-client-block.pod +++ b/doc/man7/ossl-guide-tls-client-block.pod @@ -564,6 +564,9 @@ intermediate CAs, or the issuer is simply unrecognised). See L to read a tutorial on how to modify the client developed on this page to support a nonblocking socket. +See L for a tutorial on how to implement a +simple TLS server handling one client at a time over a blocking socket. + See L to read a tutorial on how to modify the client developed on this page to support QUIC instead of TLS. diff --git a/doc/man7/ossl-guide-tls-introduction.pod b/doc/man7/ossl-guide-tls-introduction.pod index fd8184e592949..d7c05f686914b 100644 --- a/doc/man7/ossl-guide-tls-introduction.pod +++ b/doc/man7/ossl-guide-tls-introduction.pod @@ -230,7 +230,8 @@ circumstances where you want them to be different. It is up to the application programmer to create the B objects that are needed and supply them to the B object. See -L for further information. +L and L for +usage examples. Finally, an endpoint can establish a "session" with its peer. The session holds various TLS parameters about the connection between the client and the server. @@ -295,15 +296,18 @@ object. =head1 FURTHER READING -See L to see an example of applying these +See L for an example of how to apply these concepts in order to write a simple TLS client based on a blocking socket. +See L for an example of how to apply these +concepts in order to write a simple TLS server handling one client at a time +over a blocking socket. See L for an introduction to QUIC in OpenSSL. =head1 SEE ALSO L, L, L, L, -L +L, L =head1 COPYRIGHT diff --git a/doc/man7/ossl-guide-tls-server-block.pod b/doc/man7/ossl-guide-tls-server-block.pod new file mode 100644 index 0000000000000..e6bd2b05ca425 --- /dev/null +++ b/doc/man7/ossl-guide-tls-server-block.pod @@ -0,0 +1,329 @@ +=pod + +=begin comment + +NB: Changes to the source code samples in this file should also be reflected in +demos/guide/tls-server-block.c + +=end comment + +=head1 NAME + +ossl-guide-tls-server-block +- OpenSSL Guide: Writing a simple blocking TLS server + +=head1 SIMPLE BLOCKING TLS SERVER EXAMPLE + +This page will present various source code samples demonstrating how to write a +simple, non-concurrent, TLS "echo" server application which accepts one client +connection at a time, echoing input from the client back to the same client. +Once the current client disconnects, the next client connection is accepted. + +Both the acceptor socket and client connections are "blocking". A more typical +server might use nonblocking sockets with an event loop and callbacks for I/O +events. + +The complete source code for this example blocking TLS server is available in +the B directory of the OpenSSL source distribution in the file +B. It is also available online at +L. + +We assume that you already have OpenSSL installed on your system; that you +already have some fundamental understanding of OpenSSL concepts and TLS (see +L and L); +and that you know how to write and build C code and link it against the +libcrypto and libssl libraries that are provided by OpenSSL. It also assumes +that you have a basic understanding of TCP/IP and sockets. + +=head2 Creating the SSL_CTX and SSL objects + +The first step is to create an B object for our server. We use the +L function for this purpose. We could alternatively use +L if we want to associate the B with a particular +B (see L to learn about +B). We pass as an argument the return value of the function +L. You should use this method whenever you are writing a +TLS server. This method will automatically use TLS version negotiation to select +the highest version of the protocol that is mutually supported by both the +server and the client. + + /* + * An SSL_CTX holds shared configuration information for multiple + * subsequent per-client SSL connections. + */ + ctx = SSL_CTX_new(TLS_server_method()); + if (ctx == NULL) { + ERR_print_errors_fp(stderr); + errx(res, "Failed to create server SSL_CTX"); + } + +We would also like to restrict the TLS versions that we are willing to accept to +TLSv1.2 or above. TLS protocol versions earlier than that are generally to be +avoided where possible. We can do that using +L: + + /* + * TLS versions older than TLS 1.2 are deprecated by IETF and SHOULD + * be avoided if possible. + */ + if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Failed to set the minimum TLS protocol version"); + } + +Next we configure some option flags, see L for details: + + /* + * Tolerate clients hanging up without a TLS "shutdown". Appropriate in all + * application protocols which perform their own message "framing", and + * don't rely on TLS to defend against "truncation" attacks. + */ + opts = SSL_OP_IGNORE_UNEXPECTED_EOF; + + /* + * Block potential CPU-exhaustion attacks by clients that request frequent + * renegotiation. This is of course only effective if there are existing + * limits on initial full TLS handshake or connection rates. + */ + opts |= SSL_OP_NO_RENEGOTIATION; + + /* + * Most servers elect to use their own cipher preference rather than that of + * the client. + */ + opts |= SSL_OP_CIPHER_SERVER_PREFERENCE; + + /* Apply the selection options */ + SSL_CTX_set_options(ctx, opts); + +Servers need a private key and certificate. Though anonymous ciphers (no +server certificate) are possible in TLS 1.2, they are rarely applicable, and +are not currently defined for TLS 1.3. Additional intermediate issuer CA +certificates are often also required, and both the server (end-entity or EE) +certificate and the issuer ("chain") certificates are most easily configured in +a single "chain file". Below we load such a chain file (the EE certificate +must appear first), and then load the corresponding private key, checking that +it matches the server certificate. No checks are performed to check the +integrity of the chain (CA signatures or certificate expiration dates, for +example). + + /* + * Load the server's certificate *chain* file (PEM format), which includes + * not only the leaf (end-entity) server certificate, but also any + * intermediate issuer-CA certificates. The leaf certificate must be the + * first certificate in the file. + * + * In advanced use-cases this can be called multiple times, once per public + * key algorithm for which the server has a corresponding certificate. + * However, the corresponding private key (see below) must be loaded first, + * *before* moving on to the next chain file. + */ + if (SSL_CTX_use_certificate_chain_file(ctx, "chain.pem") <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Failed to load the server certificate chain file"); + } + + /* + * Load the corresponding private key, this also checks that the private + * key matches the just loaded end-entity certificate. It does not check + * whether the certificate chain is valid, the certificates could be + * expired, or may otherwise fail to form a chain that a client can validate. + */ + if (SSL_CTX_use_PrivateKey_file(ctx, "pkey.pem", SSL_FILETYPE_PEM) <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error loading the server private key file, " + "possible key/cert mismatch???"); + } + +Next we enable session caching, which makes it possible for clients to more +efficiently make additional TLS connections after completing an initial full +TLS handshake. With TLS 1.3, session resumption typically still performs a fresh +key agreement, but the certificate exchange is avoided. + + /* + * Servers that want to enable session resumption must specify a cache id + * byte array, that identifies the server application, and reduces the + * chance of inappropriate cache sharing. + */ + SSL_CTX_set_session_id_context(ctx, (void *)cache_id, sizeof(cache_id)); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); + + /* + * How many client TLS sessions to cache. The default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (20k in recent OpenSSL versions), + * which may be too small or too large. + */ + SSL_CTX_sess_set_cache_size(ctx, 1024); + + /* + * Sessions older than this are considered a cache miss even if still in + * the cache. The default is two hours. Busy servers whose clients make + * many connections in a short burst may want a shorter timeout, on lightly + * loaded servers with sporadic connections from any given client, a longer + * time may be appropriate. + */ + SSL_CTX_set_timeout(ctx, 3600); + +Most servers, including this one, do not solicit client certificates. We +therefore do not need a "trust store" and allow the handshake to complete even +when the client does not present a certificate. Note: Even if a client did +present a trusted ceritificate, for it to be useful, the server application +would still need custom code to use the verified identity to grant nondefault +access to that particular client. Some servers grant access to all clients +with certificates from a private CA, this then requires processing of +certificate revocation lists to deauthorise a client. It is often simpler and +more secure to instead keep a list of authorised public keys. + +Though this is the default setting, we explicitly call the +L function and pass the B value to it. +The final argument to this function is a callback that you can optionally +supply to override the default handling for certificate verification. Most +applications do not need to do this so this can safely be set to NULL to get +the default handling. + + /* + * Clients rarely employ certificate-based authentication, and so we don't + * require "mutual" TLS authentication (indeed there's no way to know + * whether or how the client authenticated the server, so the term "mutual" + * is potentially misleading). + * + * Since we're not soliciting or processing client certificates, we don't + * need to configure a trusted-certificate store, so no call to + * SSL_CTX_set_default_verify_paths() is needed. The server's own + * certificate chain is assumed valid. + */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + +That is all the setup that we need to do for the B. Next we create an +acceptor BIO on which to accept client connections. This just records the +intended port (and optional "host:" prefix), without actually creating the +socket. This delayed processing allows the programmer to specify additional +behaviours before the listening socket is actually created. + + /* + * Create a listener socket wrapped in a BIO. + * The first call to BIO_do_accept() initialises the socket + */ + acceptor_bio = BIO_new_accept(hostport); + if (acceptor_bio == NULL) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error creating acceptor bio"); + } + +Servers almost always want to use the "SO_REUSEADDR" option to avoid startup +failures if there are still lingering client connections, so we do that before +making the B call to L which creates the listening +socket, without accepting a client connection. Subsequent calls to the same +function will accept new connections. + + BIO_set_bind_mode(acceptor_bio, BIO_BIND_REUSEADDR); + if (BIO_do_accept(acceptor_bio) <= 0) { + SSL_CTX_free(ctx); + ERR_print_errors_fp(stderr); + errx(res, "Error setting up acceptor socket"); + } + +=head2 Server loop + +The server now enters a "forever" loop handling one client connection at a +time. Before each connection we clear the OpenSSL error stack, so that any +error reports are related to just the new connection. + + /* Pristine error stack for each new connection */ + ERR_clear_error(); + +At this point the server blocks to accept the next client: + + /* Wait for the next client to connect */ + if (BIO_do_accept(acceptor_bio) <= 0) { + /* Client went away before we accepted the connection */ + continue; + } + +On success the accepted client connection has been wrapped in a fresh BIO and +pushed onto the end of the acceptor BIO chain. We pop it off returning the +acceptor BIO to its initial state. + + /* Pop the client connection from the BIO chain */ + client_bio = BIO_pop(acceptor_bio); + fprintf(stderr, "New client connection accepted\n"); + +Next, we create an B object by calling the B function and +passing the B we created as an argument. The client connection BIO is +configured as the I/O conduit for this SSL handle. SSL_set_bio transfers +ownership of the BIO or BIOs involved (our B) to the SSL handle. + + /* Associate a new SSL handle with the new connection */ + if ((ssl = SSL_new(ctx)) == NULL) { + ERR_print_errors_fp(stderr); + warnx("Error creating SSL handle for new connection"); + BIO_free(client_bio); + continue; + } + SSL_set_bio(ssl, client_bio, client_bio); + +And now we're ready to attempt the SSL handshake. With a blocking socket +OpenSSL will perform all the read and write operations required to complete the +handshake (or detect and report a failure) before returning. + + /* Attempt an SSL handshake with the client */ + if (SSL_accept(ssl) <= 0) { + ERR_print_errors_fp(stderr); + warnx("Error performing SSL handshake with client"); + SSL_free(ssl); + continue; + } + +With the handshake complete, the server loops echoing client input back to the +client: + + while (SSL_read_ex(ssl, buf, sizeof(buf), &nread) > 0) { + if (SSL_write_ex(ssl, buf, nread, &nwritten) > 0 && + nwritten == nread) { + total += nwritten; + continue; + } + warnx("Error echoing client input"); + break; + } + +Once the client closes its connection, we report the number of bytes sent to +B and free the SSL handle, which also frees the B and +closes the underlying socket. + + fprintf(stderr, "Client connection closed, %zu bytes sent\n", total); + SSL_free(ssl); + +The server is now ready to accept the next client connection. + +=head2 Final clean up + +If the server could somehow manage to break out of the infinite loop, and +be ready to exit, it would first deallocate the constructed B. + + /* + * Unreachable placeholder cleanup code, the above loop runs forever. + */ + SSL_CTX_free(ctx); + return EXIT_SUCCESS; + +=head1 SEE ALSO + +L, L, +L, L, +L, L + +=head1 COPYRIGHT + +Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut From 5aec3f4a72604d76970581f1ea445b331beda608 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 25 Apr 2024 20:05:22 +0200 Subject: [PATCH 019/138] CMP app: fix combination of -certout and -chainout with equal filename argument Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/24267) --- apps/cmp.c | 27 ++++++++++++++----- doc/man1/openssl-cmp.pod.in | 6 +++++ doc/man3/OSSL_CMP_CTX_new.pod | 2 ++ .../80-test_cmp_http_data/test_enrollment.csv | 4 ++- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/apps/cmp.c b/apps/cmp.c index 7639ab2cf8b22..8d880c50c8eeb 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -3594,13 +3594,28 @@ int cmp_main(int argc, char **argv) opt_extracertsout, "extra") < 0) goto err; if (newcert != NULL && (opt_cmd == CMP_IR || opt_cmd == CMP_CR - || opt_cmd == CMP_KUR || opt_cmd == CMP_P10CR)) - if (!save_cert_or_delete(newcert, opt_certout, "newly enrolled") - || save_free_certs(OSSL_CMP_CTX_get1_newChain(cmp_ctx), - opt_chainout, "chain") < 0 - || save_free_certs(OSSL_CMP_CTX_get1_caPubs(cmp_ctx), - opt_cacertsout, "CA") < 0) + || opt_cmd == CMP_KUR || opt_cmd == CMP_P10CR)) { + STACK_OF(X509) *newchain = OSSL_CMP_CTX_get1_newChain(cmp_ctx); + + if (newcert != NULL && newchain != NULL /* NULL is on error only */ + && opt_certout != NULL && opt_chainout != NULL + && strcmp(opt_certout, opt_chainout) == 0) { + if (!X509_add_cert(newchain, newcert, X509_ADD_FLAG_PREPEND + | X509_ADD_FLAG_UP_REF)) { + sk_X509_pop_free(newchain, X509_free); + goto err; + } + if (!save_free_certs(newchain, opt_chainout, "newly enrolled cert and chain")) + goto err; + } else { + if (save_free_certs(newchain, opt_chainout, "chain") < 0 + || !save_cert_or_delete(newcert, opt_certout, "newly enrolled")) + goto err; + } + if (save_free_certs(OSSL_CMP_CTX_get1_caPubs(cmp_ctx), + opt_cacertsout, "CA") < 0) goto err; + } if (!OSSL_CMP_CTX_reinit(cmp_ctx)) goto err; } diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index 5b36e821befdf..d42666331ad0b 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -420,6 +420,12 @@ The file where any newly enrolled certificate should be saved. =item B<-chainout> I The file where the chain of any newly enrolled certificate should be saved. +This chain excludes the leaf certificate, i.e., the newly enrolled certificate. +Also the trust anchor (the root certificate) is not included. + +If the B<-certout> option is given, too, with equal I argument, +then the file produced contains both outputs concatenated: +the newly enrolled certificate followed by its chain. =back diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index 2f8e8dee513ec..b9d89dbc3d831 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -647,6 +647,8 @@ If the callback argument is NULL the function tries building an approximate chain as far as possible using the same untrusted certificates from the I, and if this fails it takes the received extraCerts as fallback. The resulting cert chain can be retrieved using OSSL_CMP_CTX_get1_newChain(). +This chain excludes the leaf certificate, i.e., the newly enrolled certificate. +Also the trust anchor (the root certificate) is not included. OSSL_CMP_CTX_set_certConf_cb() sets the callback used for evaluating the newly enrolled certificate before the library sends, depending on its result, diff --git a/test/recipes/80-test_cmp_http_data/test_enrollment.csv b/test/recipes/80-test_cmp_http_data/test_enrollment.csv index 3d14c78a462d4..a66afdc837e19 100644 --- a/test/recipes/80-test_cmp_http_data/test_enrollment.csv +++ b/test/recipes/80-test_cmp_http_data/test_enrollment.csv @@ -66,7 +66,9 @@ expected,description, -section,val, -cmd,val, -newkey,val,val, -newkeypass,val, 1,disable_confirm, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -disable_confirm,, -certout,_RESULT_DIR/test.certout_disable.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, 0,disable_confirm with parameter, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -disable_confirm,abc, -certout,_RESULT_DIR/test.certout_disable1.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -1,use certout (and chainout), -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, ,,, -out_trusted,root.crt,,BLANK,,BLANK,,,,-cert,_RESULT_DIR/test.certout_newkey.pem,-untrusted,_RESULT_DIR/test.chainout.pem +1,use certout (and chainout) , -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, ,,, -out_trusted,root.crt,,BLANK,,BLANK,,,,-cert,_RESULT_DIR/test.certout_newkey.pem,-untrusted,_RESULT_DIR/test.chainout.pem +1,certout and chainout sent to same file, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, ,,, -out_trusted,root.crt,,BLANK,,BLANK,,,,-certout,_RESULT_DIR/test.certout_chainout.pem,,-chainout,_RESULT_DIR/test.certout_chainout.pem +1,use certout and chainout from same file, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, ,,, -out_trusted,root.crt,,BLANK,,BLANK,,,,-cert,_RESULT_DIR/test.certout_chainout.pem,-untrusted,"""" 0,no certout, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,"""",, -out_trusted,root.crt,,BLANK,,BLANK,,, 0,certout missing arg, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,,, -out_trusted,root.crt,,BLANK,,BLANK,,, 0,certout is non-existing directory and file, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,idontexist/idontexist,, -out_trusted,root.crt,,BLANK,,BLANK,,, From f159d861e2761ffc6421b0486fdd482f37215f9f Mon Sep 17 00:00:00 2001 From: Jaime Hablutzel Date: Mon, 17 Jun 2024 11:40:08 -0500 Subject: [PATCH 020/138] Fix typo in openssl-verification-options documentation. CLA: trivial Reviewed-by: Tom Cosgrove Reviewed-by: Kurt Roeckx Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24662) --- doc/man1/openssl-verification-options.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man1/openssl-verification-options.pod b/doc/man1/openssl-verification-options.pod index 05bb560d8674a..4bb4e9c471436 100644 --- a/doc/man1/openssl-verification-options.pod +++ b/doc/man1/openssl-verification-options.pod @@ -430,7 +430,7 @@ This option may be used multiple times. =item B<-policy> I Enable policy processing and add I to the user-initial-policy-set (see -RFC5280). The policy I can be an object name an OID in numeric form. +RFC5280). The policy I can be an object name or an OID in numeric form. This argument can appear more than once. =item B<-explicit_policy> From d5412c94a399d3923b2dec2431ead60288d857c8 Mon Sep 17 00:00:00 2001 From: Et7f3 Date: Sat, 6 Apr 2024 21:09:30 +0200 Subject: [PATCH 021/138] ossl_store.pod: Correct the example of OSSL_STORE API usage Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24056) --- doc/man7/ossl_store.pod | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/man7/ossl_store.pod b/doc/man7/ossl_store.pod index a2c6260061fdc..d613d80364255 100644 --- a/doc/man7/ossl_store.pod +++ b/doc/man7/ossl_store.pod @@ -44,7 +44,11 @@ other encoding is undefined. =head2 A generic call - OSSL_STORE_CTX *ctx = OSSL_STORE_open("file:/foo/bar/data.pem"); + #include /* for UI_get_default_method */ + #include + + OSSL_STORE_CTX *ctx = OSSL_STORE_open("file:/foo/bar/data.pem", + UI_get_default_method(), NULL, NULL, NULL); /* * OSSL_STORE_eof() simulates file semantics for any repository to signal @@ -65,6 +69,7 @@ other encoding is undefined. PEM_write_X509(stdout, OSSL_STORE_INFO_get0_CERT(info)); break; } + OSSL_STORE_INFO_free(info); } OSSL_STORE_close(ctx); From e2a4d68a03b8a3576b0fe917a602b3a283d105a5 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Mon, 17 Jun 2024 16:53:50 -0400 Subject: [PATCH 022/138] docs: fix SSL_CTX_set_tlsext_ticket_key_cb typos * "shortcuts the TLS" -> "shortcuts the TLS handshake" * "don't occur" -> "doesn't occur" * "storing client certificate" -> "storing the client certificate" * "an all other" -> "and all other" CLA: trivial Reviewed-by: Kurt Roeckx Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24674) --- doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod b/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod index f289383c78152..69cb110c3114d 100644 --- a/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod +++ b/doc/man3/SSL_CTX_set_tlsext_ticket_key_cb.pod @@ -126,9 +126,9 @@ The I key material can be set using L. =head1 NOTES -Session resumption shortcuts the TLS so that the client certificate -negotiation don't occur. It makes up for this by storing client certificate -an all other negotiated state information encrypted within the ticket. In a +Session resumption shortcuts the TLS handshake so that the client certificate +negotiation doesn't occur. It makes up for this by storing the client certificate +and all other negotiated state information encrypted within the ticket. In a resumed session the applications will have all this state information available exactly as if a full negotiation had occurred. From 6a3579e190fd52f49b1e5eafb4d002684eb0ff42 Mon Sep 17 00:00:00 2001 From: Rajeev Ranjan Date: Wed, 15 May 2024 13:11:09 +0200 Subject: [PATCH 023/138] CMP: add support for requesting cert template using genm/genp Reviewed-by: David von Oheimb Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24409) --- apps/cmp.c | 177 ++++++++++++++ apps/lib/cmp_mock_srv.c | 44 +++- crypto/cmp/cmp_asn.c | 231 ++++++++++++++++++ crypto/cmp/cmp_err.c | 3 + crypto/cmp/cmp_genm.c | 33 +++ crypto/cmp/cmp_local.h | 13 + crypto/crmf/crmf_asn.c | 7 + crypto/crmf/crmf_local.h | 32 +-- crypto/err/openssl.txt | 2 + doc/build.info | 6 + doc/man1/openssl-cmp.pod.in | 18 +- doc/man3/OSSL_CMP_ATAV_set0.pod | 118 +++++++++ doc/man3/OSSL_CMP_ITAV_new_caCerts.pod | 43 +++- doc/man3/OSSL_CMP_exec_certreq.pod | 22 +- doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod | 1 - doc/man3/X509_dup.pod | 6 + doc/man3/d2i_X509.pod | 2 + include/internal/crmf.h | 51 ++++ include/openssl/cmp.h.in | 30 +++ include/openssl/cmperr.h | 2 + include/openssl/crmf.h.in | 7 + .../80-test_cmp_http_data/test_commands.csv | 8 + util/libcrypto.num | 20 ++ util/other.syms | 3 + 24 files changed, 834 insertions(+), 45 deletions(-) create mode 100644 doc/man3/OSSL_CMP_ATAV_set0.pod create mode 100644 include/internal/crmf.h diff --git a/apps/cmp.c b/apps/cmp.c index 8d880c50c8eeb..dc2a1c3a6aee0 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -97,6 +97,8 @@ static char *opt_oldwithnew = NULL; static char *opt_crlcert = NULL; static char *opt_oldcrl = NULL; static char *opt_crlout = NULL; +static char *opt_template = NULL; +static char *opt_keyspec = NULL; /* client authentication */ static char *opt_ref = NULL; @@ -225,6 +227,7 @@ typedef enum OPTION_choice { OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY, OPT_CMD, OPT_INFOTYPE, OPT_PROFILE, OPT_GENINFO, + OPT_TEMPLATE, OPT_KEYSPEC, OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT, OPT_DAYS, OPT_REQEXTS, @@ -313,6 +316,10 @@ const OPTIONS cmp_options[] = { "Comma-separated list of OID and value to place in generalInfo PKIHeader"}, {OPT_MORE_STR, 0, 0, "of form :int: or :str:, e.g. \'1.2.3.4:int:56789, id-kp:str:name'"}, + { "template", OPT_TEMPLATE, 's', + "File to save certTemplate received in genp of type certReqTemplate"}, + { "keyspec", OPT_KEYSPEC, 's', + "Optional file to save Key specification received in genp of type certReqTemplate"}, OPT_SECTION("Certificate enrollment"), {"newkey", OPT_NEWKEY, 's', @@ -620,6 +627,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_config}, {&opt_section}, {(char **)&opt_verbosity}, {&opt_cmd_s}, {&opt_infotype_s}, {&opt_profile}, {&opt_geninfo}, + {&opt_template}, {&opt_keyspec}, {&opt_newkey}, {&opt_newkeypass}, {&opt_subject}, {(char **)&opt_days}, {&opt_reqexts}, @@ -2176,6 +2184,17 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_oldwithnew != NULL) CMP_warn1("-oldwithnew %s", msg); } + if (opt_cmd != CMP_GENM || opt_infotype != NID_id_it_certReqTemplate) { + const char *msg = "option is ignored unless -cmd 'genm' and -infotype 'certReqTemplate' is given"; + + if (opt_template != NULL) + CMP_warn1("-template %s", msg); + if (opt_keyspec != NULL) + CMP_warn1("-keyspec %s", msg); + } else { + if (opt_template == NULL) + CMP_err("missing -template option for genm with infotype certReqTemplate"); + } if (!setup_verification_ctx(ctx)) goto err; @@ -2420,6 +2439,57 @@ static int save_crl_or_delete(X509_CRL *crl, const char *file, const char *desc) return (crl == NULL) ? delete_file(file, desc) : save_crl(crl, file, desc); } +static int save_template(const char *file, const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + BIO *bio = BIO_new_file(file, "wb"); + + if (bio == NULL) { + CMP_err1("error saving certTemplate from genp: cannot open file %s", + file); + return 0; + } + if (!ASN1_i2d_bio_of(OSSL_CRMF_CERTTEMPLATE, i2d_OSSL_CRMF_CERTTEMPLATE, + bio, tmpl)) { + CMP_err1("error saving certTemplate from genp: cannot write file %s", + file); + return 0; + } else { + CMP_info1("stored certTemplate from genp to file '%s'", file); + } + BIO_free(bio); + return 1; +} + +static int save_keyspec(const char *file, const OSSL_CMP_ATAVS *keyspec) +{ + BIO *bio = BIO_new_file(file, "wb"); + + if (bio == NULL) { + CMP_err1("error saving keySpec from genp: cannot open file %s", file); + return 0; + } + + if (!ASN1_i2d_bio_of(OSSL_CMP_ATAVS, i2d_OSSL_CMP_ATAVS, bio, keyspec)) { + CMP_err1("error saving keySpec from genp: cannot write file %s", file); + return 0; + } else { + CMP_info1("stored keySpec from genp to file '%s'", file); + } + BIO_free(bio); + return 1; +} + +static const char *nid_name(int nid) +{ + const char *name = OBJ_nid2ln(nid); + + if (name == NULL) + name = OBJ_nid2sn(nid); + if (name == NULL) + name = ""; + return name; +} + static int print_itavs(const STACK_OF(OSSL_CMP_ITAV) *itavs) { int i, ret = 1; @@ -2845,6 +2915,12 @@ static int get_opts(int argc, char **argv) case OPT_GENINFO: opt_geninfo = opt_str(); break; + case OPT_TEMPLATE: + opt_template = opt_str(); + break; + case OPT_KEYSPEC: + opt_keyspec = opt_str(); + break; case OPT_NEWKEY: opt_newkey = opt_str(); @@ -3154,6 +3230,71 @@ static int cmp_server(OSSL_CMP_CTX *srv_cmp_ctx) } #endif +static void print_keyspec(OSSL_CMP_ATAVS *keySpec) +{ + const char *desc = "specifications contained in keySpec from genp"; + BIO *mem; + int i; + const char *p; + long len; + + if (keySpec == NULL) { + CMP_info1("No %s", desc); + return; + } + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + CMP_err1("Out of memory - cannot dump key %s", desc); + return; + } + BIO_printf(mem, "Key %s:\n", desc); + + for (i = 0; i < sk_OSSL_CMP_ATAV_num(keySpec); i++) { + OSSL_CMP_ATAV *atav = sk_OSSL_CMP_ATAV_value(keySpec, i); + ASN1_OBJECT *type = OSSL_CMP_ATAV_get0_type(atav /* may be NULL */); + int nid = OBJ_obj2nid(type); + + switch (nid) { + case NID_id_regCtrl_algId: + { + X509_ALGOR *alg = OSSL_CMP_ATAV_get0_algId(atav); + const ASN1_OBJECT *oid; + int paramtype; + const void *param; + + X509_ALGOR_get0(&oid, ¶mtype, ¶m, alg); + BIO_printf(mem, "Key algorithm: "); + i2a_ASN1_OBJECT(mem, oid); + if (paramtype == V_ASN1_UNDEF || alg->parameter == NULL) { + BIO_printf(mem, "\n"); + } else { + BIO_printf(mem, " - "); + ASN1_item_print(mem, (ASN1_VALUE *)alg, + 0, ASN1_ITEM_rptr(X509_ALGOR), NULL); + } + } + break; + case NID_id_regCtrl_rsaKeyLen: + BIO_printf(mem, "Key algorithm: RSA %d\n", + OSSL_CMP_ATAV_get_rsaKeyLen(atav)); + break; + default: + BIO_printf(mem, "Invalid key spec: %s\n", nid_name(nid)); + break; + } + } + BIO_printf(mem, "End of key %s", desc); + + len = BIO_get_mem_data(mem, &p); + if (len > INT_MAX) + CMP_err1("Info too large - cannot dump key %s", desc); + else + CMP_info2("%.*s", (int)len, p); + BIO_free(mem); + return; +} + static void print_status(void) { /* print PKIStatusInfo */ @@ -3300,6 +3441,42 @@ static int do_genm(OSSL_CMP_CTX *ctx) X509_CRL_free(crl); return res; + } else if (opt_infotype == NID_id_it_certReqTemplate) { + OSSL_CRMF_CERTTEMPLATE *certTemplate; + OSSL_CMP_ATAVS *keySpec; + int res = 0; + + if (!OSSL_CMP_get1_certReqTemplate(ctx, &certTemplate, &keySpec)) + return 0; + + if (certTemplate == NULL) { + CMP_warn("no certificate request template available"); + if (!delete_file(opt_template, "certTemplate from genp")) + return 0; + if (opt_keyspec != NULL + && !delete_file(opt_keyspec, "keySpec from genp")) + return 0; + return 1; + } + if (!save_template(opt_template, certTemplate)) + goto tmpl_end; + + print_keyspec(keySpec); + if (opt_keyspec != NULL) { + if (keySpec == NULL) { + CMP_warn("no key specifications available"); + if (!delete_file(opt_keyspec, "keySpec from genp")) + goto tmpl_end; + } else if (!save_keyspec(opt_keyspec, keySpec)) { + goto tmpl_end; + } + } + + res = 1; + tmpl_end: + OSSL_CRMF_CERTTEMPLATE_free(certTemplate); + sk_OSSL_CMP_ATAV_pop_free(keySpec, OSSL_CMP_ATAV_free); + return res; } else { OSSL_CMP_ITAV *req; STACK_OF(OSSL_CMP_ITAV) *itavs; diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c index b69d29a678d64..ce62af2b007aa 100644 --- a/apps/lib/cmp_mock_srv.c +++ b/apps/lib/cmp_mock_srv.c @@ -451,7 +451,7 @@ static int check_client_crl(const STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList, static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid, const OSSL_CMP_ITAV *req) { - OSSL_CMP_ITAV *rsp; + OSSL_CMP_ITAV *rsp = NULL; switch (req_nid) { case NID_id_it_caCerts: @@ -490,6 +490,48 @@ static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid, rsp = OSSL_CMP_ITAV_new_crls(res == 0 ? NULL : ctx->crlOut); } break; + case NID_id_it_certReqTemplate: + { + OSSL_CRMF_CERTTEMPLATE *reqtemp; + OSSL_CMP_ATAVS *keyspec = NULL; + X509_ALGOR *keyalg = NULL; + OSSL_CMP_ATAV *rsakeylen, *eckeyalg; + int ok = 0; + + if ((reqtemp = OSSL_CRMF_CERTTEMPLATE_new()) == NULL) + return NULL; + + if (!OSSL_CRMF_CERTTEMPLATE_fill(reqtemp, NULL, NULL, + X509_get_issuer_name(ctx->refCert), + NULL)) + goto crt_err; + + if ((keyalg = X509_ALGOR_new()) == NULL) + goto crt_err; + + (void)X509_ALGOR_set0(keyalg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), + V_ASN1_UNDEF, NULL); /* cannot fail */ + + eckeyalg = OSSL_CMP_ATAV_new_algId(keyalg); + rsakeylen = OSSL_CMP_ATAV_new_rsaKeyLen(4096); + ok = OSSL_CMP_ATAV_push1(&keyspec, eckeyalg) + && OSSL_CMP_ATAV_push1(&keyspec, rsakeylen); + OSSL_CMP_ATAV_free(eckeyalg); + OSSL_CMP_ATAV_free(rsakeylen); + X509_ALGOR_free(keyalg); + + if (!ok) + goto crt_err; + + rsp = OSSL_CMP_ITAV_new0_certReqTemplate(reqtemp, keyspec); + return rsp; + + crt_err: + OSSL_CRMF_CERTTEMPLATE_free(reqtemp); + OSSL_CMP_ATAVS_free(keyspec); + return NULL; + } + break; default: rsp = OSSL_CMP_ITAV_dup(req); } diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c index f20e5098ca9ca..3bdb3ce688def 100644 --- a/crypto/cmp/cmp_asn.c +++ b/crypto/cmp/cmp_asn.c @@ -12,6 +12,7 @@ #include #include "cmp_local.h" +#include "internal/crmf.h" /* explicit #includes not strictly needed since implied by the above: */ #include @@ -117,6 +118,9 @@ ASN1_ADB(OSSL_CMP_ITAV) = { ADB_ENTRY(NID_id_it_rootCaKeyUpdate, ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaKeyUpdate, OSSL_CMP_ROOTCAKEYUPDATE)), + ADB_ENTRY(NID_id_it_certReqTemplate, + ASN1_OPT(OSSL_CMP_ITAV, infoValue.certReqTemplate, + OSSL_CMP_CERTREQTEMPLATE)), ADB_ENTRY(NID_id_it_certProfile, ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.certProfile, ASN1_UTF8STRING)), @@ -143,6 +147,19 @@ ASN1_SEQUENCE(OSSL_CMP_ROOTCAKEYUPDATE) = { } ASN1_SEQUENCE_END(OSSL_CMP_ROOTCAKEYUPDATE) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE) +ASN1_ITEM_TEMPLATE(OSSL_CMP_ATAVS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, + OSSL_CMP_ATAVS, OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +ASN1_ITEM_TEMPLATE_END(OSSL_CMP_ATAVS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ATAVS) + +ASN1_SEQUENCE(OSSL_CMP_CERTREQTEMPLATE) = { + ASN1_SIMPLE(OSSL_CMP_CERTREQTEMPLATE, certTemplate, OSSL_CRMF_CERTTEMPLATE), + ASN1_SEQUENCE_OF_OPT(OSSL_CMP_CERTREQTEMPLATE, keySpec, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +} ASN1_SEQUENCE_END(OSSL_CMP_CERTREQTEMPLATE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CERTREQTEMPLATE) + ASN1_CHOICE(OSSL_CMP_CRLSOURCE) = { ASN1_EXP(OSSL_CMP_CRLSOURCE, value.dpn, DIST_POINT_NAME, 0), ASN1_EXP(OSSL_CMP_CRLSOURCE, value.issuer, GENERAL_NAMES, 1), @@ -358,6 +375,220 @@ int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, return 1; } +OSSL_CMP_ITAV +*OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec) +{ + OSSL_CMP_ITAV *itav; + OSSL_CMP_CERTREQTEMPLATE *tmpl; + + if (certTemplate == NULL && keySpec != NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + if ((itav = OSSL_CMP_ITAV_new()) == NULL) + return NULL; + itav->infoType = OBJ_nid2obj(NID_id_it_certReqTemplate); + if (certTemplate == NULL) + return itav; + + if ((tmpl = OSSL_CMP_CERTREQTEMPLATE_new()) == NULL) { + OSSL_CMP_ITAV_free(itav); + return NULL; + } + itav->infoValue.certReqTemplate = tmpl; + tmpl->certTemplate = certTemplate; + tmpl->keySpec = keySpec; + return itav; +} + +int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec) +{ + OSSL_CMP_CERTREQTEMPLATE *tpl; + + if (itav == NULL || certTemplate == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + + *certTemplate = NULL; + if (keySpec != NULL) + *keySpec = NULL; + + if (OBJ_obj2nid(itav->infoType) != NID_id_it_certReqTemplate) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + tpl = itav->infoValue.certReqTemplate; + if (tpl == NULL) /* no requirements available */ + return 1; + + if ((*certTemplate = OSSL_CRMF_CERTTEMPLATE_dup(tpl->certTemplate)) == NULL) + return 0; + if (keySpec != NULL && tpl->keySpec != NULL) { + int i, n = sk_OSSL_CMP_ATAV_num(tpl->keySpec); + + *keySpec = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_reserve(NULL, n); + if (*keySpec == NULL) + goto err; + for (i = 0; i < n; i++) { + OSSL_CMP_ATAV *atav = sk_OSSL_CMP_ATAV_value(tpl->keySpec, i); + ASN1_OBJECT *type = OSSL_CMP_ATAV_get0_type(atav /* may be NULL */); + int nid; + const char *name; + + if (type == NULL) { + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC, + "keySpec with index %d in certReqTemplate does not exist", + i); + goto err; + } + nid = OBJ_obj2nid(type); + + if (nid != NID_id_regCtrl_algId + && nid != NID_id_regCtrl_rsaKeyLen) { + name = OBJ_nid2ln(nid); + if (name == NULL) + name = OBJ_nid2sn(nid); + if (name == NULL) + name = ""; + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC, + "keySpec with index %d in certReqTemplate has invalid type %s", + i, name); + goto err; + } + OSSL_CMP_ATAV_push1(keySpec, atav); + } + } + return 1; + + err: + OSSL_CRMF_CERTTEMPLATE_free(*certTemplate); + *certTemplate = NULL; + sk_OSSL_CMP_ATAV_pop_free(*keySpec, OSSL_CMP_ATAV_free); + if (keySpec != NULL) + *keySpec = NULL; + return 0; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value) +{ + OSSL_CMP_ATAV *atav; + + if ((atav = OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new()) == NULL) + return NULL; + OSSL_CMP_ATAV_set0(atav, type, value); + return atav; +} + +void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *atav, ASN1_OBJECT *type, + ASN1_TYPE *value) +{ + atav->type = type; + atav->value.other = value; +} + +ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL) + return NULL; + return atav->type; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg) +{ + X509_ALGOR *dup; + OSSL_CMP_ATAV *res; + + if (alg == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + if ((dup = X509_ALGOR_dup(alg)) == NULL) + return NULL; + res = OSSL_CMP_ATAV_create(OBJ_nid2obj(NID_id_regCtrl_algId), + (ASN1_TYPE *)dup); + if (res == NULL) + X509_ALGOR_free(dup); + return res; +} + +X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL || OBJ_obj2nid(atav->type) != NID_id_regCtrl_algId) + return NULL; + return atav->value.algId; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len) +{ + ASN1_INTEGER *aint; + OSSL_CMP_ATAV *res = NULL; + + if (len <= 0) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + if ((aint = ASN1_INTEGER_new()) == NULL) + return NULL; + if (!ASN1_INTEGER_set(aint, len) + || (res = OSSL_CMP_ATAV_create(OBJ_nid2obj(NID_id_regCtrl_rsaKeyLen), + (ASN1_TYPE *)aint)) == NULL) + ASN1_INTEGER_free(aint); + return res; +} + +int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav) +{ + int64_t val; + + if (atav == NULL || OBJ_obj2nid(atav->type) != NID_id_regCtrl_rsaKeyLen + || !ASN1_INTEGER_get_int64(&val, atav->value.rsaKeyLen)) + return -1; + if (val <= 0 || val > INT_MAX) + return -2; + return (int)val; +} + +ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL) + return NULL; + return atav->value.other; +} + +int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav) +{ + int created = 0; + OSSL_CMP_ATAV *dup; + + if (sk_p == NULL || atav == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + goto err; + } + + if (*sk_p == NULL) { + if ((*sk_p = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_null()) == NULL) + goto err; + created = 1; + } + + if ((dup = OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup((OSSL_CRMF_ATTRIBUTETYPEANDVALUE *)atav)) == NULL) + goto err; + if (sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push(*sk_p, dup)) + return 1; + OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(dup); + + err: + if (created) { + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(*sk_p); + *sk_p = NULL; + } + return 0; +} + OSSL_CMP_ITAV *OSSL_CMP_ITAV_new0_crlStatusList(STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList) { diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index 689aa6a9520f7..5cec9438f6145 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -85,12 +85,15 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "failure obtaining random"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE), "fail info out of range"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GENERATE_CERTREQTEMPLATE), + "generate certreqtemplate"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GENERATE_CRLSTATUS), "error creating crlstatus"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GETTING_GENP), "getting genp"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GET_ITAV), "get itav"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_GENP), "invalid genp"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_KEYSPEC), "invalid keyspec"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_OPTION), "invalid option"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ROOTCAKEYUPDATE), "invalid rootcakeyupdate"}, diff --git a/crypto/cmp/cmp_genm.c b/crypto/cmp/cmp_genm.c index 17f2f1d3acc57..c68cddad05f01 100644 --- a/crypto/cmp/cmp_genm.c +++ b/crypto/cmp/cmp_genm.c @@ -406,3 +406,36 @@ int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, OSSL_CMP_ITAV_free(itav); return res; } + +int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec) +{ + OSSL_CMP_ITAV *req, *itav = NULL; + int res = 0; + + if (keySpec != NULL) + *keySpec = NULL; + if (certTemplate == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + *certTemplate = NULL; + + if ((req = OSSL_CMP_ITAV_new0_certReqTemplate(NULL, NULL)) == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_GENERATE_CERTREQTEMPLATE); + return 0; + } + + if ((itav = get_genm_itav(ctx, req, NID_id_it_certReqTemplate, + "certReqTemplate")) == NULL) + return 0; + + if (!OSSL_CMP_ITAV_get1_certReqTemplate(itav, certTemplate, keySpec)) + goto end; + + res = 1; + end: + OSSL_CMP_ITAV_free(itav); + return res; +} diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 9ebd1858a5574..597080379701e 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -294,6 +294,8 @@ struct ossl_cmp_itav_st { X509 *rootCaCert; /* NID_id_it_rootCaKeyUpdate - Root CA Certificate Update */ OSSL_CMP_ROOTCAKEYUPDATE *rootCaKeyUpdate; + /* NID_id_it_certReqTemplate - Certificate Request Template */ + OSSL_CMP_CERTREQTEMPLATE *certReqTemplate; /* NID_id_it_crlStatusList - CRL Update Retrieval */ STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList; /* NID_id_it_crls - Certificate Status Lists */ @@ -800,6 +802,17 @@ struct ossl_cmp_rootcakeyupdate_st { } /* OSSL_CMP_ROOTCAKEYUPDATE */; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE) +/*- + * CertReqTemplateContent ::= SEQUENCE { + * certTemplate CertTemplate, + * keySpec Controls OPTIONAL + * } + */ +struct ossl_cmp_certreqtemplate_st { + OSSL_CRMF_CERTTEMPLATE *certTemplate; + OSSL_CMP_ATAVS *keySpec; +} /* OSSL_CMP_CERTREQTEMPLATE */; + /* from cmp_asn.c */ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a); diff --git a/crypto/crmf/crmf_asn.c b/crypto/crmf/crmf_asn.c index 85b4213934a92..55b0c39bf82d6 100644 --- a/crypto/crmf/crmf_asn.c +++ b/crypto/crmf/crmf_asn.c @@ -146,6 +146,12 @@ ASN1_ADB(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) = { ADB_ENTRY(NID_id_regCtrl_protocolEncrKey, ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, value.protocolEncrKey, X509_PUBKEY)), + ADB_ENTRY(NID_id_regCtrl_algId, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.algId, X509_ALGOR)), + ADB_ENTRY(NID_id_regCtrl_rsaKeyLen, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.rsaKeyLen, ASN1_INTEGER)), ADB_ENTRY(NID_id_regInfo_utf8Pairs, ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, value.utf8Pairs, ASN1_UTF8STRING)), @@ -194,6 +200,7 @@ ASN1_SEQUENCE(OSSL_CRMF_CERTTEMPLATE) = { X509_EXTENSION, 9), } ASN1_SEQUENCE_END(OSSL_CRMF_CERTTEMPLATE) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTTEMPLATE) ASN1_SEQUENCE(OSSL_CRMF_CERTREQUEST) = { ASN1_SIMPLE(OSSL_CRMF_CERTREQUEST, certReqId, ASN1_INTEGER), diff --git a/crypto/crmf/crmf_local.h b/crypto/crmf/crmf_local.h index e8937b4231e64..cfa01ab3992cf 100644 --- a/crypto/crmf/crmf_local.h +++ b/crypto/crmf/crmf_local.h @@ -16,6 +16,7 @@ # include # include +# include "internal/crmf.h" /* for ossl_crmf_attributetypeandvalue_st */ /* explicit #includes not strictly needed since implied by the above: */ # include @@ -335,37 +336,6 @@ struct ossl_crmf_certrequest_st { DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTREQUEST) DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTREQUEST) -struct ossl_crmf_attributetypeandvalue_st { - ASN1_OBJECT *type; - union { - /* NID_id_regCtrl_regToken */ - ASN1_UTF8STRING *regToken; - - /* NID_id_regCtrl_authenticator */ - ASN1_UTF8STRING *authenticator; - - /* NID_id_regCtrl_pkiPublicationInfo */ - OSSL_CRMF_PKIPUBLICATIONINFO *pkiPublicationInfo; - - /* NID_id_regCtrl_oldCertID */ - OSSL_CRMF_CERTID *oldCertID; - - /* NID_id_regCtrl_protocolEncrKey */ - X509_PUBKEY *protocolEncrKey; - - /* NID_id_regInfo_utf8Pairs */ - ASN1_UTF8STRING *utf8Pairs; - - /* NID_id_regInfo_certReq */ - OSSL_CRMF_CERTREQUEST *certReq; - - ASN1_TYPE *other; - } value; -} /* OSSL_CRMF_ATTRIBUTETYPEANDVALUE */; -DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) -DEFINE_STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) -DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) - /*- * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg * CertReqMsg ::= SEQUENCE { diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index c2bcf98f8bf8b..3279f49199f89 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -234,11 +234,13 @@ CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range +CMP_R_GENERATE_CERTREQTEMPLATE:197:generate certreqtemplate CMP_R_GENERATE_CRLSTATUS:198:error creating crlstatus CMP_R_GETTING_GENP:192:getting genp CMP_R_GET_ITAV:199:get itav CMP_R_INVALID_ARGS:100:invalid args CMP_R_INVALID_GENP:193:invalid genp +CMP_R_INVALID_KEYSPEC:202:invalid keyspec CMP_R_INVALID_OPTION:174:invalid option CMP_R_INVALID_ROOTCAKEYUPDATE:195:invalid rootcakeyupdate CMP_R_MISSING_CERTID:165:missing certid diff --git a/doc/build.info b/doc/build.info index f84364dba24be..3a8adb1c66e3e 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1599,6 +1599,10 @@ DEPEND[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod GENERATE[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod DEPEND[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod GENERATE[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod +DEPEND[html/man3/OSSL_CMP_ATAV_set0.html]=man3/OSSL_CMP_ATAV_set0.pod +GENERATE[html/man3/OSSL_CMP_ATAV_set0.html]=man3/OSSL_CMP_ATAV_set0.pod +DEPEND[man/man3/OSSL_CMP_ATAV_set0.3]=man3/OSSL_CMP_ATAV_set0.pod +GENERATE[man/man3/OSSL_CMP_ATAV_set0.3]=man3/OSSL_CMP_ATAV_set0.pod DEPEND[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod GENERATE[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod DEPEND[man/man3/OSSL_CMP_CTX_new.3]=man3/OSSL_CMP_CTX_new.pod @@ -3379,6 +3383,7 @@ html/man3/OPENSSL_secure_malloc.html \ html/man3/OPENSSL_strcasecmp.html \ html/man3/OSSL_ALGORITHM.html \ html/man3/OSSL_CALLBACK.html \ +html/man3/OSSL_CMP_ATAV_set0.html \ html/man3/OSSL_CMP_CTX_new.html \ html/man3/OSSL_CMP_HDR_get0_transactionID.html \ html/man3/OSSL_CMP_ITAV_new_caCerts.html \ @@ -4036,6 +4041,7 @@ man/man3/OPENSSL_secure_malloc.3 \ man/man3/OPENSSL_strcasecmp.3 \ man/man3/OSSL_ALGORITHM.3 \ man/man3/OSSL_CALLBACK.3 \ +man/man3/OSSL_CMP_ATAV_set0.3 \ man/man3/OSSL_CMP_CTX_new.3 \ man/man3/OSSL_CMP_HDR_get0_transactionID.3 \ man/man3/OSSL_CMP_ITAV_new_caCerts.3 \ diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index d42666331ad0b..bf153e579eec6 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -19,6 +19,8 @@ Generic message options: [B<-infotype> I] [B<-profile> I] [B<-geninfo> I] +[B<-template> I] +[B<-keyspec> I] Certificate enrollment options: @@ -252,8 +254,8 @@ ITAV Bs is printed to stdout. Set InfoType name to use for requesting specific info in B, e.g., C. -So far, there is specific support for C, C -and C. +There is specific support for C, C, +C, and C (CRL update retrieval). =item B<-profile> I @@ -268,6 +270,18 @@ Each InfoTypeAndValue gives an OID and an integer or string value of the form I:int:I or I:str:I, e.g., C<'1.2.3.4:int:56789, id-kp:str:name'>. +=item B<-template> I + +The file to save any CRMF certTemplate in DER format +received in a genp message with id-it-certReqTemplate. + +=item B<-keyspec> I + +It is optional and used to specify the file to save any keySpec if +present in a genp message with id-it-keyGenParameters. + +Note: any keySpec field contents received are logged as INFO. + =back =head2 Certificate enrollment options diff --git a/doc/man3/OSSL_CMP_ATAV_set0.pod b/doc/man3/OSSL_CMP_ATAV_set0.pod new file mode 100644 index 0000000000000..8ab11df260cc2 --- /dev/null +++ b/doc/man3/OSSL_CMP_ATAV_set0.pod @@ -0,0 +1,118 @@ +=pod + +=head1 NAME + +OSSL_CMP_ATAV, +OSSL_CMP_ATAV_create, +OSSL_CMP_ATAV_set0, +OSSL_CMP_ATAV_get0_type, +OSSL_CMP_ATAV_get0_value, +OSSL_CMP_ATAV_new_algId, +OSSL_CMP_ATAV_get0_algId, +OSSL_CMP_ATAV_new_rsaKeyLen, +OSSL_CMP_ATAV_get_rsaKeyLen, +OSSL_CMP_ATAVS, +OSSL_CMP_ATAV_push1, +OSSL_CMP_ATAV_free +- OSSL_CMP_ATAV utility functions + +=head1 SYNOPSIS + + #include + + typedef OSSL_CRMF_ATTRIBUTETYPEANDVALUE OSSL_CMP_ATAV; + OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value); + void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *atav, ASN1_OBJECT *type, + ASN1_TYPE *value); + ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *atav); + ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *atav); + + OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg); + X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav); + OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len); + int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav); + + typedef STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) OSSL_CMP_ATAVS; + int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav); + void OSSL_CMP_ATAV_free(OSSL_CMP_ATAV *atav); + +=head1 DESCRIPTION + +B is a short hand of B, +defined in RFC 4211 Appendix B. +It is typically used in CertRequest structures, +but also in CertReqTemplateContent structures for key specifications. + +OSSL_CMP_ATAV_create() creates a new B structure and fills it in. +It combines OSSL_CMP_ATAV_new() and OSSL_CMP_ATAV_set0(). + +OSSL_CMP_ATAV_set0() sets the I with an infoType of I and an +infoValue of I. +The pointers I and I may be NULL, otherwise +they must B be freed up after the call because their ownership +is transferred to I. The I pointer must not be NULL. + +OSSL_CMP_ATAV_get0_type() returns a direct pointer to the infoType +in the I unless it is NULL. + +OSSL_CMP_ATAV_get0_value() returns a direct pointer to the infoValue +in the I as generic B pointer unless I is NULL. + +OSSL_CMP_ATAV_new_algId() creates a new B structure of type +B and fills it in with a copy of the given I. + +OSSL_CMP_ATAV_get0_algId() returns +a direct pointer to the algId infoValue in the I of type B +or NULL if I is NULL or does not contain an algId. + +OSSL_CMP_ATAV_new_rsaKeyLen() creates a new B structure of type +B and fills it in with the given I, which must be positive. + +OSSL_CMP_ATAV_get_rsaKeyLen() returns +the RSA key length in rsaKeyLen infoValue in the I, +-1 if I is NULL or does not contain an rsaKeyLen or cannot be parsed, +or -2 if the value is less than 1 or is greater than INT_MAX. + +OSSL_CMP_ATAV_push1() pushes a copy of I to the stack of B +pointed to by I<*sk_p>. It creates a new stack if I<*sk_p> points to NULL. + +OSSL_CMP_ATAV_free() deallocates I. It is defined as a macro. + +=head1 NOTES + +CMP is defined in RFC 4210. CRMF is defined in RFC 4211. + +=head1 RETURN VALUES + +OSSL_CMP_ATAV_create(), +OSSL_CMP_ATAV_new_algId(), and OSSL_CMP_ATAV_new_rsaKeyLen() +return a pointer to the ATAV structure on success, or NULL on error. + +OSSL_CMP_ATAV_set0() and OSSL_CMP_ATAV_free() do not return a value. + +OSSL_CMP_ATAV_get0_type(), OSSL_CMP_ATAV_get0_value(), and +OSSL_CMP_ATAV_get0_algId() +return the respective pointer or NULL if their input is NULL. + +OSSL_CMP_ATAV_get_rsaKeyLen() return a key length in bits or < 0 on error. + +OSSL_CMP_ATAV_push1() returns 1 on success, 0 on error. + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +The B type and related functions were added in OpenSSL 3.4. + +=head1 COPYRIGHT + +Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod index 209c56929e2e3..6fc1cf6f4f0ea 100644 --- a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod +++ b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod @@ -14,7 +14,9 @@ OSSL_CMP_CRLSTATUS_get0, OSSL_CMP_ITAV_new0_crlStatusList, OSSL_CMP_ITAV_get0_crlStatusList, OSSL_CMP_ITAV_new_crls, -OSSL_CMP_ITAV_get0_crls +OSSL_CMP_ITAV_get0_crls, +OSSL_CMP_ITAV_new0_certReqTemplate, +OSSL_CMP_ITAV_get1_certReqTemplate - CMP utility functions for handling specific genm and genp messages =head1 SYNOPSIS @@ -48,6 +50,12 @@ OSSL_CMP_ITAV_get0_crls STACK_OF(OSSL_CMP_CRLSTATUS) **out); OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crl); int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *itav, STACK_OF(X509_CRL) **out); + OSSL_CMP_ITAV + *OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec); + int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); =head1 DESCRIPTION @@ -100,6 +108,27 @@ Data from I, if present, is preferred over data from I. If no distribution point names are available, candidate issuer names are taken from following sources, as far as present: +OSSL_CMP_ITAV_new0_certReqTemplate() creates an B structure +of type B. +If I is NULL then also I must be NULL, +and the resulting ITAV can be used in a B message to obtain the +requirements a PKI has on the certificate template used to request certificates, +or in a B message stating that there are no such requirements. +Otherwise the resulting ITAV includes a CertReqTemplateValue structure +with I of type B and an optional list +of key specifications I, each being of type B, and +the resulting ATAV can be used in a B message to provide requirements. + +OSSL_CMP_ITAV_get1_certReqTemplate() +requires that I has type B. +If assigns NULL to I<*certTemplate> if no B structure +with a certificate template value is in I, +otherwise a copy of the certTemplate field value. +If I is not NULL, it is assigned NULL +if the structure is not present in I or the keySpec field is absent. +Otherwise, the function checks that all elements of keySpec field are of type +B or B and assigns to I<*keySpec> a copy of the keySpec field. + =over 4 =item the list of distribution points in the first cRLDistributionPoints @@ -150,13 +179,14 @@ CMP is defined in RFC 4210. OSSL_CMP_ITAV_new_caCerts(), OSSL_CMP_ITAV_new_rootCaCert(), OSSL_CMP_ITAV_new_rootCaKeyUpdate(), OSSL_CMP_CRLSTATUS_new1(), -OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_ITAV_new0_crlStatusList() -and OSSL_CMP_ITAV_new_crls() +OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_ITAV_new0_crlStatusList(), +OSSL_CMP_ITAV_new_crls() and OSSL_CMP_ITAV_new0_certReqTemplate() return a pointer to the new ITAV structure on success, or NULL on error. OSSL_CMP_ITAV_get0_caCerts(), OSSL_CMP_ITAV_get0_rootCaCert(), OSSL_CMP_ITAV_get0_rootCaKeyUpdate(), OSSL_CMP_CRLSTATUS_get0(), -OSSL_CMP_ITAV_get0_crlStatusList() and OSSL_CMP_ITAV_get0_crls() +OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_get0_crls() +and OSSL_CMP_ITAV_get1_certReqTemplate() return 1 on success, 0 on error. =head1 SEE ALSO @@ -172,8 +202,9 @@ were added in OpenSSL 3.2. OSSL_CMP_CRLSTATUS_new1(), OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_CRLSTATUS_get0(), OSSL_CMP_ITAV_new0_crlStatusList(), -OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_new_crls() -and OSSL_CMP_ITAV_get0_crls() were added in OpenSSL 3.4. +OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_new_crls(), +OSSL_CMP_ITAV_get0_crls(), OSSL_CMP_ITAV_new0_certReqTemplate() +and OSSL_CMP_ITAV_get1_certReqTemplate() were added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CMP_exec_certreq.pod b/doc/man3/OSSL_CMP_exec_certreq.pod index a264ec88275ad..c1428be90e1d1 100644 --- a/doc/man3/OSSL_CMP_exec_certreq.pod +++ b/doc/man3/OSSL_CMP_exec_certreq.pod @@ -16,7 +16,8 @@ OSSL_CMP_exec_RR_ses, OSSL_CMP_exec_GENM_ses, OSSL_CMP_get1_caCerts, OSSL_CMP_get1_rootCaKeyUpdate, -OSSL_CMP_get1_crlUpdate +OSSL_CMP_get1_crlUpdate, +OSSL_CMP_get1_certReqTemplate - functions implementing CMP client transactions =head1 SYNOPSIS @@ -45,7 +46,9 @@ OSSL_CMP_get1_crlUpdate int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, const X509_CRL *last_crl, X509_CRL **crl); - + int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); =head1 DESCRIPTION This is the OpenSSL API for doing CMP (Certificate Management Protocol) @@ -169,6 +172,15 @@ On success it assigns to I<*crl> the CRL received. NULL means that no CRL was provided by the server. The CRL obtained this way must be freed by the caller. +OSSL_CMP_get1_certReqTemplate() uses a genm request message with +infoType certReqTemplate to obtain a certificate request template from the +CMP server referenced by I. On success it assigns to I<*certTemplate> +the certificate template received. NULL output means that no certificate +request template was provided by the server. +The optional I output parameter is assigned the key specification +if received, otherwise it set to NULL. +Both must be freed by the caller. + =head1 NOTES CMP is defined in RFC 4210 (and CRMF in RFC 4211). @@ -205,7 +217,8 @@ and the output parameter I has been used to assign the received value unless I is NULL. OSSL_CMP_exec_RR_ses(), OSSL_CMP_get1_caCerts(), -OSSL_CMP_get1_rootCaKeyUpdate() and OSSL_CMP_get1_crlUpdate() +OSSL_CMP_get1_rootCaKeyUpdate(), OSSL_CMP_get1_crlUpdate() +and OSSL_CMP_get1_certReqTemplate() return 1 on success, 0 on error. OSSL_CMP_exec_GENM_ses() returns NULL on error, @@ -235,7 +248,8 @@ were added in OpenSSL 3.2. Support for delayed delivery of all types of response messages was added in OpenSSL 3.3. -OSSL_CMP_get1_crlUpdate() was added in OpenSSL 3.4. +OSSL_CMP_get1_crlUpdate() and OSSL_CMP_get1_certReqTemplate() +were added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod b/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod index d0769ac61b490..9d57719a485ab 100644 --- a/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod +++ b/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod @@ -41,7 +41,6 @@ OSSL_CRMF_MSG_get_certReqId int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm); - =head1 DESCRIPTION OSSL_CRMF_MSG_get0_tmpl() retrieves the certificate template of I. diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index 6333ba698585f..dc43c46aa9ab9 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -136,6 +136,9 @@ OCSP_SIGNATURE_free, OCSP_SIGNATURE_new, OCSP_SINGLERESP_free, OCSP_SINGLERESP_new, +OSSL_CMP_ATAVS_new, +OSSL_CMP_ATAVS_free, +OSSL_CMP_ATAVS_it, OSSL_CMP_CRLSTATUS_free, OSSL_CMP_ITAV_dup, OSSL_CMP_ITAV_free, @@ -157,6 +160,9 @@ OSSL_CRMF_CERTID_new, OSSL_CRMF_CERTTEMPLATE_free, OSSL_CRMF_CERTTEMPLATE_it, OSSL_CRMF_CERTTEMPLATE_new, +OSSL_CRMF_CERTTEMPLATE_dup, +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup, +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free, OSSL_CRMF_ENCRYPTEDVALUE_free, OSSL_CRMF_ENCRYPTEDVALUE_it, OSSL_CRMF_ENCRYPTEDVALUE_new, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 373962e135161..38181e764bb43 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -89,6 +89,7 @@ d2i_OCSP_REVOKEDINFO, d2i_OCSP_SERVICELOC, d2i_OCSP_SIGNATURE, d2i_OCSP_SINGLERESP, +d2i_OSSL_CMP_ATAVS, d2i_OSSL_CMP_MSG, d2i_OSSL_CMP_PKIHEADER, d2i_OSSL_CMP_PKISI, @@ -270,6 +271,7 @@ i2d_OCSP_REVOKEDINFO, i2d_OCSP_SERVICELOC, i2d_OCSP_SIGNATURE, i2d_OCSP_SINGLERESP, +i2d_OSSL_CMP_ATAVS, i2d_OSSL_CMP_MSG, i2d_OSSL_CMP_PKIHEADER, i2d_OSSL_CMP_PKISI, diff --git a/include/internal/crmf.h b/include/internal/crmf.h new file mode 100644 index 0000000000000..9e37320d83305 --- /dev/null +++ b/include/internal/crmf.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef OSSL_CRYPTO_CRMF_H +# define OSSL_CRYPTO_CRMF_H +# pragma once + +# include + +struct ossl_crmf_attributetypeandvalue_st { + ASN1_OBJECT *type; + union { + /* NID_id_regCtrl_regToken */ + ASN1_UTF8STRING *regToken; + + /* NID_id_regCtrl_authenticator */ + ASN1_UTF8STRING *authenticator; + + /* NID_id_regCtrl_pkiPublicationInfo */ + OSSL_CRMF_PKIPUBLICATIONINFO *pkiPublicationInfo; + + /* NID_id_regCtrl_oldCertID */ + OSSL_CRMF_CERTID *oldCertID; + + /* NID_id_regCtrl_protocolEncrKey */ + X509_PUBKEY *protocolEncrKey; + + /* NID_id_regCtrl_algId */ + X509_ALGOR *algId; + + /* NID_id_regCtrl_rsaKeyLen */ + ASN1_INTEGER *rsaKeyLen; + + /* NID_id_regInfo_utf8Pairs */ + ASN1_UTF8STRING *utf8Pairs; + + /* NID_id_regInfo_certReq */ + OSSL_CRMF_CERTREQUEST *certReq; + + ASN1_TYPE *other; + } value; +} /* OSSL_CRMF_ATTRIBUTETYPEANDVALUE */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) + +#endif /* OSSL_CRYPTO_CRMF_H */ diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in index c46b9ab594fa7..d659331fa38fa 100644 --- a/include/openssl/cmp.h.in +++ b/include/openssl/cmp.h.in @@ -234,6 +234,16 @@ typedef struct ossl_cmp_crlstatus_st OSSL_CMP_CRLSTATUS; generate_stack_macros("OSSL_CMP_CRLSTATUS"); -} +typedef OSSL_CRMF_ATTRIBUTETYPEANDVALUE OSSL_CMP_ATAV; +# define OSSL_CMP_ATAV_free OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free +typedef STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) OSSL_CMP_ATAVS; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ATAVS) +# define stack_st_OSSL_CMP_ATAV stack_st_OSSL_CRMF_ATTRIBUTETYPEANDVALUE +# define sk_OSSL_CMP_ATAV_num sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_num +# define sk_OSSL_CMP_ATAV_value sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_value +# define sk_OSSL_CMP_ATAV_push sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push +# define sk_OSSL_CMP_ATAV_pop_free sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_pop_free + typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT; typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI) @@ -299,6 +309,23 @@ int OSSL_CMP_ITAV_get0_crlStatusList(const OSSL_CMP_ITAV *itav, STACK_OF(OSSL_CMP_CRLSTATUS) **out); OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crls); int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *it, STACK_OF(X509_CRL) **out); +OSSL_CMP_ITAV +*OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec); +int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value); +void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *itav, ASN1_OBJECT *type, + ASN1_TYPE *value); +ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *itav); +ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *itav); +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg); +X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav); +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len); +int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav); +int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav); void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg); @@ -546,6 +573,9 @@ int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, const X509_CRL *last_crl, X509_CRL **crl); +int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); # ifdef __cplusplus } diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index 700ffbeb7beb6..d196924f74767 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -60,11 +60,13 @@ # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 # define CMP_R_FAIL_INFO_OUT_OF_RANGE 129 +# define CMP_R_GENERATE_CERTREQTEMPLATE 197 # define CMP_R_GENERATE_CRLSTATUS 198 # define CMP_R_GETTING_GENP 192 # define CMP_R_GET_ITAV 199 # define CMP_R_INVALID_ARGS 100 # define CMP_R_INVALID_GENP 193 +# define CMP_R_INVALID_KEYSPEC 202 # define CMP_R_INVALID_OPTION 174 # define CMP_R_INVALID_ROOTCAKEYUPDATE 195 # define CMP_R_MISSING_CERTID 165 diff --git a/include/openssl/crmf.h.in b/include/openssl/crmf.h.in index 43411fa42f66f..54a70ebc858e3 100644 --- a/include/openssl/crmf.h.in +++ b/include/openssl/crmf.h.in @@ -54,6 +54,12 @@ DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_MSG) generate_stack_macros("OSSL_CRMF_MSG"); -} typedef struct ossl_crmf_attributetypeandvalue_st OSSL_CRMF_ATTRIBUTETYPEANDVALUE; +void OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(OSSL_CRMF_ATTRIBUTETYPEANDVALUE *v); +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +{- + generate_stack_macros("OSSL_CRMF_ATTRIBUTETYPEANDVALUE"); +-} + typedef struct ossl_crmf_pbmparameter_st OSSL_CRMF_PBMPARAMETER; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PBMPARAMETER) typedef struct ossl_crmf_poposigningkey_st OSSL_CRMF_POPOSIGNINGKEY; @@ -71,6 +77,7 @@ typedef struct ossl_crmf_singlepubinfo_st OSSL_CRMF_SINGLEPUBINFO; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_SINGLEPUBINFO) typedef struct ossl_crmf_certtemplate_st OSSL_CRMF_CERTTEMPLATE; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTTEMPLATE) typedef STACK_OF(OSSL_CRMF_MSG) OSSL_CRMF_MSGS; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_MSGS) diff --git a/test/recipes/80-test_cmp_http_data/test_commands.csv b/test/recipes/80-test_cmp_http_data/test_commands.csv index 69dff91b7d809..26b985bf65d32 100644 --- a/test/recipes/80-test_cmp_http_data/test_commands.csv +++ b/test/recipes/80-test_cmp_http_data/test_commands.csv @@ -96,6 +96,14 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty 0,genm crlStatusList missing -crlcert & -oldcrl, -section,, -cmd,genm,, BLANK,,, -infotype,crlStatusList,,,,,,,, -crlout, _RESULT_DIR/test.crlout.pem 0,genm crlStatusList with wrong cert and correct crl, -section,, -cmd,genm,, BLANK,,, -infotype,crlStatusList,, -crlcert, server.crt, -oldcrl, oldcrl.pem,,, -crlout, _RESULT_DIR/test.crlout.pem ,,,,,,,,,,,,,,,,,,,,,, +1,genm certReqTemplate, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,_RESULT_DIR/test.keyspec.der, -infotype,certReqTemplate,,BLANK,,BLANK,,BLANK,,, -expect_sender, """" +0,genm certReqTemplate missing template option, -section,, -cmd,genm,, -template,"""", -keyspec,_RESULT_DIR/test.keyspec.der, -infotype,certReqTemplate,,BLANK,,BLANK, +1,genm certReqTemplate without optional keyspec option, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,"""",, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate missing template arg , -section,, -cmd,genm,, -template,BLANK, -keyspec,_RESULT_DIR/test.keyspec.der, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate template extra arg , -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der,_RESULT_DIR/test.template.der, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate template arg non-ex dir, -section,, -cmd,genm,, -template,idontexist/idontexist,, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate keyspec arg non-ex dir, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,idontexist/idontexist,, -infotype,certReqTemplate,,BLANK,,BLANK, +,,,,,,,,,,,,,,,,,,,,,, 1,profile, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,BLANK,,BLANK, 0,profile wrong value, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile2,BLANK,,BLANK, 0,profile missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,,,,, diff --git a/util/libcrypto.num b/util/libcrypto.num index 526cc59355dce..681183a9f4c58 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5559,6 +5559,26 @@ OSSL_CMP_ITAV_get0_crls ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_ITAV_new0_crlStatusList ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_ITAV_new_crls ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_get1_crlUpdate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_new0_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_get1_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_create ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_set0 ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_type ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_value ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_new_algId ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_algId ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_new_rsaKeyLen ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get_rsaKeyLen ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_push1 ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_get1_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +d2i_OSSL_CMP_ATAVS ? 3_4_0 EXIST::FUNCTION:CMP +i2d_OSSL_CMP_ATAVS ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_free ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_new ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_it ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_CERTTEMPLATE_dup ? 3_4_0 EXIST::FUNCTION:CRMF CRYPTO_atomic_store ? 3_4_0 EXIST::FUNCTION: CRYPTO_aligned_alloc ? 3_4_0 EXIST::FUNCTION: d2i_X509_ACERT ? 3_4_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index acb7f5f1d8c03..143b3a33d1a38 100644 --- a/util/other.syms +++ b/util/other.syms @@ -461,6 +461,9 @@ OSSL_CMP_LOG_WARNING define OSSL_CMP_MSTR_HELPER define OSSL_CMP_MSTR define OSSL_CMP_P10CR define +OSSL_CMP_ATAV define +OSSL_CMP_ATAV_free define +OSSL_CMP_ATAVS define OSSL_CMP_certConf_cb_t datatype OSSL_CMP_log_cb_t datatype OSSL_CMP_severity datatype From fa495604516a610d988f02298c8d97a6ac4777bb Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Tue, 28 May 2024 13:59:44 +0200 Subject: [PATCH 024/138] Fix handling of max_fragment_length extension for PSK A psk session was assumed to be a resumption which failed a check when parsing the max_fragment_length extension hello from the client. Relevant code from PR#18130 which was a suggested fix to the issue was cherry-picked. Fixes #18121 Reviewed-by: Matt Caswell Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24513) --- include/openssl/tls1.h | 2 ++ ssl/ssl_sess.c | 1 + ssl/statem/extensions.c | 12 +++--------- ssl/statem/extensions_srvr.c | 29 +++++++++++++++++------------ ssl/t1_lib.c | 2 ++ 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 8ff39e3956bb9..8a963f62f6d5c 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -231,6 +231,8 @@ extern "C" { # define TLSEXT_max_fragment_length_1024 2 # define TLSEXT_max_fragment_length_2048 3 # define TLSEXT_max_fragment_length_4096 4 +/* OpenSSL value for unset maximum fragment length extension */ +# define TLSEXT_max_fragment_length_UNSPECIFIED 255 /* * TLS Certificate Type (for RFC7250) diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index d326eadb048d1..12c64d8b7ae66 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -109,6 +109,7 @@ SSL_SESSION *SSL_SESSION_new(void) if (ss == NULL) return NULL; + ss->ext.max_fragment_len_mode = TLSEXT_max_fragment_length_UNSPECIFIED; ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ /* 5 minute timeout by default */ ss->timeout = ossl_seconds2time(60 * 5 + 4); diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 0a64ca2246987..a52b9096efde9 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -1741,15 +1741,9 @@ static int final_early_data(SSL_CONNECTION *s, unsigned int context, int sent) static int final_maxfragmentlen(SSL_CONNECTION *s, unsigned int context, int sent) { - /* - * Session resumption on server-side with MFL extension active - * BUT MFL extension packet was not resent (i.e. sent == 0) - */ - if (s->server && s->hit && USE_MAX_FRAGMENT_LENGTH_EXT(s->session) - && !sent ) { - SSLfatal(s, SSL_AD_MISSING_EXTENSION, SSL_R_BAD_EXTENSION); - return 0; - } + /* MaxFragmentLength defaults to disabled */ + if (s->session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED) + s->session->ext.max_fragment_len_mode = TLSEXT_max_fragment_length_DISABLED; if (s->session && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) { s->rlayer.rrlmethod->set_max_frag_len(s->rlayer.rrl, diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 2962a0bdcd316..699cc202c344e 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -192,21 +192,26 @@ int tls_parse_ctos_maxfragmentlen(SSL_CONNECTION *s, PACKET *pkt, } /* - * RFC 6066: The negotiated length applies for the duration of the session + * When doing a full handshake or a renegotiation max_fragment_len_mode will + * be TLSEXT_max_fragment_length_UNSPECIFIED + * + * In case of a resumption max_fragment_len_mode will be one of + * TLSEXT_max_fragment_length_DISABLED, TLSEXT_max_fragment_length_512, + * TLSEXT_max_fragment_length_1024, TLSEXT_max_fragment_length_2048. + * TLSEXT_max_fragment_length_4096 + * + * RFC 6066: The negotiated length applies for the duration of the session * including session resumptions. - * We should receive the same code as in resumed session ! + * + * So we only set the value in case it is unspecified. */ - if (s->hit && s->session->ext.max_fragment_len_mode != value) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, - SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH); - return 0; - } + if (s->session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED) + /* + * Store it in session, so it'll become binding for us + * and we'll include it in a next Server Hello. + */ + s->session->ext.max_fragment_len_mode = value; - /* - * Store it in session, so it'll become binding for us - * and we'll include it in a next Server Hello. - */ - s->session->ext.max_fragment_len_mode = value; return 1; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index cb9eefb5058ad..14e9cee0ee496 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -3930,6 +3930,8 @@ int SSL_set_tlsext_max_fragment_length(SSL *ssl, uint8_t mode) uint8_t SSL_SESSION_get_max_fragment_length(const SSL_SESSION *session) { + if (session->ext.max_fragment_len_mode == TLSEXT_max_fragment_length_UNSPECIFIED) + return TLSEXT_max_fragment_length_DISABLED; return session->ext.max_fragment_len_mode; } From f7252d736da65ffa41cd81c6e0ec5ee58160eeb4 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 17 Jun 2024 14:12:46 -0400 Subject: [PATCH 025/138] Some minor nit corrections in the thread code for rcu Reviewed-by: Paul Dale Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24630) (cherry picked from commit d38d2642287ef9a22f20e662a19c217c227043a6) --- crypto/threads_none.c | 3 ++- crypto/threads_pthread.c | 2 ++ crypto/threads_win.c | 1 + test/threadstest.c | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crypto/threads_none.c b/crypto/threads_none.c index e0387650fece8..c2e6173bcac3f 100644 --- a/crypto/threads_none.c +++ b/crypto/threads_none.c @@ -23,7 +23,8 @@ struct rcu_lock_st { struct rcu_cb_item *cb_items; }; -CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) +CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, + ossl_unused OSSL_LIB_CTX *ctx) { struct rcu_lock_st *lock; diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 2a6e7aaf537ac..0628db542f642 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -409,7 +409,9 @@ static void ossl_rcu_free_local_data(void *arg) OSSL_LIB_CTX *ctx = arg; CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(ctx); struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); + OPENSSL_free(data); + CRYPTO_THREAD_set_local(lkey, NULL); } void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock) diff --git a/crypto/threads_win.c b/crypto/threads_win.c index a36e3752f655f..5ee0751b041df 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -190,6 +190,7 @@ static void ossl_rcu_free_local_data(void *arg) CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(ctx); struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); OPENSSL_free(data); + CRYPTO_THREAD_set_local(lkey, NULL); } void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock) diff --git a/test/threadstest.c b/test/threadstest.c index 2d05255132d3b..b2b1ec2555ae5 100644 --- a/test/threadstest.c +++ b/test/threadstest.c @@ -436,7 +436,7 @@ static int _torture_rcu(void) rcu_torture_result = 1; rcu_lock = ossl_rcu_lock_new(1, NULL); - if (!rcu_lock) + if (rcu_lock == NULL) goto out; TEST_info("Staring rcu torture"); From c0088b993711a37516060abd42243feaf27c65b0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 17 Jun 2024 12:35:39 +0200 Subject: [PATCH 026/138] Add CHANGES.md entry for the EC/DSA nonce generation fixes Reviewed-by: Matt Caswell Reviewed-by: Tom Cosgrove Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/24660) (cherry picked from commit 72bff68f6acc4f420e283bcc77db76eb1917d7bf) --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9918e10c972ba..9eed55ab76268 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -145,6 +145,14 @@ OpenSSL 3.3 *Tomáš Mráz* + * Improved EC/DSA nonce generation routines to avoid bias and timing + side channel leaks. + + Thanks to Florian Sieck from Universität zu Lübeck and George Pantelakis + and Hubert Kario from Red Hat for reporting the issues. + + *Tomáš Mráz and Paul Dale* + ### Changes between 3.2 and 3.3.0 [9 Apr 2024] * The `-verify` option to the `openssl crl` and `openssl req` will make From 2e9cd409c0411e890cabf3827770ac3d4a235b82 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Tue, 18 Jun 2024 14:11:15 -0400 Subject: [PATCH 027/138] Add comp.h to gitignore Signed-off-by: Todd Short Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24676) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d2de49876dde9..0d0899e32a14b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ /include/openssl/bio.h /include/openssl/cmp.h /include/openssl/cms.h +/include/openssl/comp.h /include/openssl/conf.h /include/openssl/configuration.h /include/openssl/crmf.h From a7ed61ce8b0565483e6b0e44ed9b13682305e609 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Mon, 17 Jun 2024 21:40:30 +0000 Subject: [PATCH 028/138] feat: add delegatedNameConstraints and holderNameConstraints exts Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24664) --- crypto/x509/ext_dat.h | 2 ++ crypto/x509/standard_exts.h | 4 +++- crypto/x509/v3_ncons.c | 20 +++++++++++++++++ test/certs/ext-delegatedNameConstraints.pem | 12 +++++++++++ test/certs/ext-holderNameConstraints.pem | 12 +++++++++++ test/recipes/25-test_x509.t | 24 ++++++++++++++++++++- 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/certs/ext-delegatedNameConstraints.pem create mode 100644 test/certs/ext-holderNameConstraints.pem diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index 8d34e829dc5f2..befb8e444aad7 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -32,3 +32,5 @@ extern const X509V3_EXT_METHOD ossl_v3_no_rev_avail; extern const X509V3_EXT_METHOD ossl_v3_single_use; extern const X509V3_EXT_METHOD ossl_v3_indirect_issuer; extern const X509V3_EXT_METHOD ossl_v3_targeting_information; +extern const X509V3_EXT_METHOD ossl_v3_holder_name_constraints; +extern const X509V3_EXT_METHOD ossl_v3_delegated_name_constraints; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index eba9e31dec819..f399bde8b3c6a 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -74,11 +74,13 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_issuer_sign_tool, &ossl_v3_tls_feature, &ossl_v3_ext_admission, + &ossl_v3_delegated_name_constraints, &ossl_v3_soa_identifier, &ossl_v3_indirect_issuer, &ossl_v3_no_assertion, &ossl_v3_single_use, - &ossl_v3_group_ac + &ossl_v3_group_ac, + &ossl_v3_holder_name_constraints, }; /* Number of standard extensions */ diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c index a6817b9e177f3..de51771c2b737 100644 --- a/crypto/x509/v3_ncons.c +++ b/crypto/x509/v3_ncons.c @@ -53,6 +53,26 @@ const X509V3_EXT_METHOD ossl_v3_name_constraints = { NULL }; +const X509V3_EXT_METHOD ossl_v3_holder_name_constraints = { + NID_holder_name_constraints, 0, + ASN1_ITEM_ref(NAME_CONSTRAINTS), + 0, 0, 0, 0, + 0, 0, + 0, v2i_NAME_CONSTRAINTS, + i2r_NAME_CONSTRAINTS, 0, + NULL +}; + +const X509V3_EXT_METHOD ossl_v3_delegated_name_constraints = { + NID_delegated_name_constraints, 0, + ASN1_ITEM_ref(NAME_CONSTRAINTS), + 0, 0, 0, 0, + 0, 0, + 0, v2i_NAME_CONSTRAINTS, + i2r_NAME_CONSTRAINTS, 0, + NULL +}; + ASN1_SEQUENCE(GENERAL_SUBTREE) = { ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME), ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0), diff --git a/test/certs/ext-delegatedNameConstraints.pem b/test/certs/ext-delegatedNameConstraints.pem new file mode 100644 index 0000000000000..0646f7a231470 --- /dev/null +++ b/test/certs/ext-delegatedNameConstraints.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAZygAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMxMDI0 +MTA0WhgPMjAyMTA4MzEwMjQxMDRaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABozcwNTAzBgNVHSoELDAqoCgwJqQe +MBwxGjAYBgNVBAMMEVdpbGRib2FyIFNvZnR3YXJlgAEBgQEDMAsGCSqGSIb3DQEB +BQMBAA== +-----END CERTIFICATE----- diff --git a/test/certs/ext-holderNameConstraints.pem b/test/certs/ext-holderNameConstraints.pem new file mode 100644 index 0000000000000..002bb65361f62 --- /dev/null +++ b/test/certs/ext-holderNameConstraints.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsDCCAZygAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMxMDI0 +MTA0WhgPMjAyMTA4MzEwMjQxMDRaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABozcwNTAzBgNVHUUELDAqoCgwJqQe +MBwxGjAYBgNVBAMMEVdpbGRib2FyIFNvZnR3YXJlgAEBgQEDMAsGCSqGSIb3DQEB +BQMBAA== +-----END CERTIFICATE----- diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 2ae13df615adb..860a97080537a 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 60; +plan tests => 66; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -172,6 +172,28 @@ cert_contains($tgt_info_cert, "Digest Type: Public Key", 1, 'X.509 Targeting Information Object Digest Type'); +my $hnc_cert = srctop_file(@certs, "ext-holderNameConstraints.pem"); +cert_contains($hnc_cert, + "X509v3 Holder Name Constraints", + 1, 'X.509 Holder Name Constraints'); +cert_contains($hnc_cert, + "Permitted:", + 1, 'X.509 Holder Name Constraints Permitted'); +cert_contains($hnc_cert, + "DirName:CN = Wildboar", + 1, 'X.509 Holder Name Constraint'); + +my $dnc_cert = srctop_file(@certs, "ext-delegatedNameConstraints.pem"); +cert_contains($dnc_cert, + "X509v3 Delegated Name Constraints", + 1, 'X.509 Delegated Name Constraints'); +cert_contains($dnc_cert, + "Permitted:", + 1, 'X.509 Delegated Name Constraints Permitted'); +cert_contains($dnc_cert, + "DirName:CN = Wildboar", + 1, 'X.509 Delegated Name Constraint'); + sub test_errors { # actually tests diagnostics of OSSL_STORE my ($expected, $cert, @opts) = @_; my $infile = srctop_file(@certs, $cert); From 8d380f85da215012570347f156e642d69909877a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 6 Jun 2024 15:36:00 +0200 Subject: [PATCH 029/138] ASN1_item_verify_ctx(): Return -1 on fatal errors Fixes #24575 Reviewed-by: Tom Cosgrove Reviewed-by: Neil Horman Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/24576) --- crypto/asn1/a_verify.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c index 94d29e7c2736c..f754216eb7e51 100644 --- a/crypto/asn1/a_verify.c +++ b/crypto/asn1/a_verify.c @@ -202,10 +202,12 @@ int ASN1_item_verify_ctx(const ASN1_ITEM *it, const X509_ALGOR *alg, inl = ASN1_item_i2d(data, &buf_in, it); if (inl <= 0) { ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR); + ret = -1; goto err; } if (buf_in == NULL) { ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); + ret = -1; goto err; } inll = inl; From 2f0b4974dfbd9bc71e1164e0742fc7fdb2b2b70e Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 17 Jun 2024 12:19:45 +0200 Subject: [PATCH 030/138] Add test for ASN1_item_verify() This is a test for https://github.com/openssl/openssl/issues/24575 Original idea by Theo Buehler. Reviewed-by: Tom Cosgrove Reviewed-by: Neil Horman Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/24576) --- test/certs/ee-self-signed-pss.pem | 21 +++++++++ test/certs/setup.sh | 4 ++ test/recipes/25-test_x509.t | 4 +- test/x509_test.c | 72 +++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 test/certs/ee-self-signed-pss.pem diff --git a/test/certs/ee-self-signed-pss.pem b/test/certs/ee-self-signed-pss.pem new file mode 100644 index 0000000000000..fab433321ce4c --- /dev/null +++ b/test/certs/ee-self-signed-pss.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhTCCAjmgAwIBAgIUZxTKBh9L8ApVNcsI5ontnHRbv8wwQQYJKoZIhvcNAQEK +MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF +AKIDAgEgMB0xGzAZBgNVBAMMEmVlLXNlbGYtc2lnbmVkLXBzczAgFw0yNDA2MTcx +MTA5NTRaGA8yMTI0MDYxODExMDk1NFowHTEbMBkGA1UEAwwSZWUtc2VsZi1zaWdu +ZWQtcHNzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqP+JWGGFrt7b +LA/Vc/vit6gbenVgK9R9PHN2ta7eky9/JJBtyRz0ijjNn6KAFlbLtCy7k+UXH/8N +xkP+MTT4KNh16aO7iILvo3LiU2IFRU3gMZfvqp0Q0lgNngaeMrsbCFZdZQ8/Zo7C +NqAR/8BZNf1JHN0cQjMGeK4EOCPl53Vn05StWqlAH6xZEPUMwWStSsTGNVOzlmqC +GxWL0Zmr5J5vlKrSluVX+4yRZIo8JBbG0hm+gmATO2Kw7T4ds8r5a98xuXqeS0do +pynHP0riIie075Bj1+/Qckk+W625G9Qrb4Zo3dVzErhDydxBD6KjRk+LZ4iED2H+ +eTQfSokftwIDAQABo1MwUTAdBgNVHQ4EFgQU55viKq2KbDrLdlHljgeYIpfhc6Iw +HwYDVR0jBBgwFoAU55viKq2KbDrLdlHljgeYIpfhc6IwDwYDVR0TAQH/BAUwAwEB +/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEI +MA0GCWCGSAFlAwQCAQUAogMCASADggEBADjXHPnAha0YQKFCfQZqy8LLgxoQDbfP +5XKQJ8/FfeJXO9yjEmqOEoWM/QQIlM1gpepOOw8ZRhxcwx93eO+XtvJUA3bW+H73 +jwnqiX5mu1SpA/2IHcifxuOuXUwUh7vtOJGFATHusAn7dS3+tnJSkS+6pvSsJjDu +0x3fV8rLq1gL9gOC2MdzkLxyp7xmdgibQMI+PyPNgU1e1Qm88Cp5dVNRMdgQ+3CL +E3h7qfSpSkUCM9rNBc2/rqavQ/UPq5H6r8R9gYd9yR7uGL88B9QI4DQDR8T6x9JG +0ebWYLuH2xWP9Njl2IbwN3uqQSeRSSqy7UlNo51O+nkvU1vCJGy6aXw= +-----END CERTIFICATE----- diff --git a/test/certs/setup.sh b/test/certs/setup.sh index d517384301975..4280ac3a8d30c 100755 --- a/test/certs/setup.sh +++ b/test/certs/setup.sh @@ -226,6 +226,10 @@ OPENSSL_KEYBITS=8192 \ # self-signed end-entity cert with explicit keyUsage not including KeyCertSign openssl req -new -x509 -key ee-key.pem -subj /CN=ee-self-signed -out ee-self-signed.pem -addext keyUsage=digitalSignature -days 36525 +# self-signed end-entity cert signed with RSA-PSS +openssl req -new -x509 -key ee-key.pem -subj /CN=ee-self-signed-pss -out ee-self-signed-pss.pem -days 36525 \ + -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest + # Proxy certificates, off of ee-client # Start with some good ones ./mkcert.sh req pc1-key "0.CN = server.example" "1.CN = proxy 1" | \ diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 860a97080537a..52ba7d1821398 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -355,5 +355,7 @@ ok(run(app(["openssl", "x509", "-req", "-text", SKIP: { skip "EC is not supported by this OpenSSL build", 1 if disabled("ec"); - ok(run(test(["x509_test"])), "running x509_test"); + my $psscert = srctop_file(@certs, "ee-self-signed-pss.pem"); + + ok(run(test(["x509_test", $psscert])), "running x509_test"); } diff --git a/test/x509_test.c b/test/x509_test.c index f5a67c63d994d..3996d5010df32 100644 --- a/test/x509_test.c +++ b/test/x509_test.c @@ -7,7 +7,14 @@ * https://www.openssl.org/source/license.html */ +#define OPENSSL_SUPPRESS_DEPRECATED /* EVP_PKEY_get1/set1_RSA */ + #include +#include +#include +#include +#include +#include "crypto/x509.h" /* x509_st definition */ #include "testutil.h" static EVP_PKEY *pubkey = NULL; @@ -114,9 +121,73 @@ static int test_x509_crl_tbs_cache(void) return ret; } +static int test_asn1_item_verify(void) +{ + int ret = 0; + BIO *bio = NULL; + X509 *x509 = NULL; + const char *certfile; + const ASN1_BIT_STRING *sig = NULL; + const X509_ALGOR *alg = NULL; + EVP_PKEY *pkey; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + RSA *rsa = NULL; +#endif + + if (!TEST_ptr(certfile = test_get_argument(0)) + || !TEST_ptr(bio = BIO_new_file(certfile, "r")) + || !TEST_ptr(x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) + || !TEST_ptr(pkey = X509_get0_pubkey(x509))) + goto err; + +#ifndef OPENSSL_NO_DEPRECATED_3_0 + /* Issue #24575 requires legacy key but the test is useful anyway */ + if (!TEST_ptr(rsa = EVP_PKEY_get1_RSA(pkey))) + goto err; + + if (!TEST_int_gt(EVP_PKEY_set1_RSA(pkey, rsa), 0)) + goto err; +#endif + + X509_get0_signature(&sig, &alg, x509); + + if (!TEST_int_gt(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), + (X509_ALGOR *)alg, (ASN1_BIT_STRING *)sig, + &x509->cert_info, pkey), 0)) + goto err; + + ERR_set_mark(); + if (!TEST_int_lt(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), + (X509_ALGOR *)alg, (ASN1_BIT_STRING *)sig, + NULL, pkey), 0)) { + ERR_clear_last_mark(); + goto err; + } + ERR_pop_to_mark(); + + ret = 1; + + err: +#ifndef OPENSSL_NO_DEPRECATED_3_0 + RSA_free(rsa); +#endif + X509_free(x509); + BIO_free(bio); + return ret; +} + +OPT_TEST_DECLARE_USAGE("\n") + int setup_tests(void) { const unsigned char *p; + int cnt; + + cnt = test_get_argument_count(); + if (cnt != 1) { + TEST_error("Must specify a certificate file self-signed with RSA-PSS.\n"); + return 0; + } p = pubkeydata; pubkey = d2i_PUBKEY(NULL, &p, sizeof(pubkeydata)); @@ -138,6 +209,7 @@ int setup_tests(void) ADD_TEST(test_x509_tbs_cache); ADD_TEST(test_x509_crl_tbs_cache); + ADD_TEST(test_asn1_item_verify); return 1; } From 79886c85b378d73aec4d96f8e258f12915faddf7 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 18 Jun 2024 14:43:26 +0000 Subject: [PATCH 031/138] Fix data race between SSL_SESSION_list_add and ssl_session_dup Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24673) --- ssl/ssl_sess.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 12c64d8b7ae66..4d3bbe84032a6 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -139,7 +139,15 @@ static SSL_SESSION *ssl_session_dup_intern(const SSL_SESSION *src, int ticket) dest = OPENSSL_malloc(sizeof(*dest)); if (dest == NULL) return NULL; - memcpy(dest, src, sizeof(*dest)); + + /* + * Copy until prev ptr, because it's a part of sessons cache which can be modified + * concurrently. Other fields filled in the code bellow. + */ + memcpy(dest, src, offsetof(SSL_SESSION, prev)); + dest->ext = src->ext; + dest->ticket_appdata_len = src->ticket_appdata_len; + dest->flags = src->flags; /* * Set the various pointers to NULL so that we can call SSL_SESSION_free in From 8d934a75929d058bbc4566a6ebc9f804e1dd081f Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 18 Jun 2024 20:31:14 +0000 Subject: [PATCH 032/138] Incorporate review feedback Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24673) --- ssl/ssl_local.h | 11 ++++++----- ssl/ssl_sess.c | 7 ++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 9083ec2f3bb63..3a96c6a1361bf 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -540,11 +540,6 @@ struct ssl_session_st { * load the 'cipher' structure */ unsigned int kex_group; /* TLS group from key exchange */ CRYPTO_EX_DATA ex_data; /* application specific data */ - /* - * These are used to make removal of session-ids more efficient and to - * implement a maximum cache size. - */ - struct ssl_session_st *prev, *next; struct { char *hostname; @@ -574,6 +569,12 @@ struct ssl_session_st { size_t ticket_appdata_len; uint32_t flags; SSL_CTX *owner; + + /* + * These are used to make removal of session-ids more efficient and to + * implement a maximum cache size. + */ + struct ssl_session_st *prev, *next; }; /* Extended master secret support */ diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 4d3bbe84032a6..6b5d9bbb24552 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -141,13 +141,10 @@ static SSL_SESSION *ssl_session_dup_intern(const SSL_SESSION *src, int ticket) return NULL; /* - * Copy until prev ptr, because it's a part of sessons cache which can be modified - * concurrently. Other fields filled in the code bellow. + * src is logically read-only but the prev/next pointers are not, they are + * part of the session cache and can be modified concurrently. */ memcpy(dest, src, offsetof(SSL_SESSION, prev)); - dest->ext = src->ext; - dest->ticket_appdata_len = src->ticket_appdata_len; - dest->flags = src->flags; /* * Set the various pointers to NULL so that we can call SSL_SESSION_free in From af82623d32962b3eff5b0f0b0dedec5eb730b231 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 19 Jun 2024 08:40:16 +0000 Subject: [PATCH 033/138] Incorporate more review feedback Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24673) --- ssl/ssl_local.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 3a96c6a1361bf..0d979ae7237a8 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -530,7 +530,6 @@ struct ssl_session_st { * certificate is not ok, we must remember the error for session reuse: */ long verify_result; /* only for servers */ - CRYPTO_REF_COUNT references; OSSL_TIME timeout; OSSL_TIME time; OSSL_TIME calc_timeout; @@ -572,9 +571,10 @@ struct ssl_session_st { /* * These are used to make removal of session-ids more efficient and to - * implement a maximum cache size. + * implement a maximum cache size. Access requires protection of ctx->lock. */ struct ssl_session_st *prev, *next; + CRYPTO_REF_COUNT references; }; /* Extended master secret support */ From 663dbc9c9c897392a9f9d18aa9a8400ca024dc5d Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 17 Jun 2024 16:48:26 +0200 Subject: [PATCH 034/138] Fix regression of EVP_PKEY_CTX_add1_hkdf_info() with older providers If there is no get_ctx_params() implemented in the key exchange provider implementation the fallback will not work. Instead check the gettable_ctx_params() to see if the fallback should be performed. Fixes #24611 Reviewed-by: Paul Dale Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/24661) --- crypto/evp/pmeth_lib.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 0a561323f166e..71485c949cefd 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -1008,6 +1008,7 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback, int datalen) { OSSL_PARAM os_params[2]; + const OSSL_PARAM *gettables; unsigned char *info = NULL; size_t info_len = 0; size_t info_alloc = 0; @@ -1031,6 +1032,12 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback, return 1; } + /* Check for older provider that doesn't support getting this parameter */ + gettables = EVP_PKEY_CTX_gettable_params(ctx); + if (gettables == NULL || OSSL_PARAM_locate_const(gettables, param) == NULL) + return evp_pkey_ctx_set1_octet_string(ctx, fallback, param, op, ctrl, + data, datalen); + /* Get the original value length */ os_params[0] = OSSL_PARAM_construct_octet_string(param, NULL, 0); os_params[1] = OSSL_PARAM_construct_end(); @@ -1038,9 +1045,9 @@ static int evp_pkey_ctx_add1_octet_string(EVP_PKEY_CTX *ctx, int fallback, if (!EVP_PKEY_CTX_get_params(ctx, os_params)) return 0; - /* Older provider that doesn't support getting this parameter */ + /* This should not happen but check to be sure. */ if (os_params[0].return_size == OSSL_PARAM_UNMODIFIED) - return evp_pkey_ctx_set1_octet_string(ctx, fallback, param, op, ctrl, data, datalen); + return 0; info_alloc = os_params[0].return_size + datalen; if (info_alloc == 0) From 03448ba21b5e720f59f7d349fcffd26c53323414 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Thu, 20 Jun 2024 17:48:35 +0200 Subject: [PATCH 035/138] s_client: use the full buffer for reads Use full allocated buffer for reads to not call into switch() over and over; also increase the size of the buffer to 16 kiB (max for TLS records). The server side already is using 16 kiB buffers. Signed-off-by: Hubert Kario Reviewed-by: Neil Horman Reviewed-by: Matt Caswell Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/24688) --- apps/s_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/s_client.c b/apps/s_client.c index 78a44755cb54f..b52c69d0b2042 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -55,7 +55,7 @@ typedef unsigned int u_int; #endif #undef BUFSIZZ -#define BUFSIZZ 1024*8 +#define BUFSIZZ 1024*16 #define S_CLIENT_IRC_READ_TIMEOUT 8 #define USER_DATA_MODE_NONE 0 @@ -3172,7 +3172,7 @@ int s_client_main(int argc, char **argv) } } #endif - k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); + k = SSL_read(con, sbuf, BUFSIZZ); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: From 7fab3c7d61b0064dcf50db39fb490970c60d9a34 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Wed, 19 Jun 2024 14:02:06 +0200 Subject: [PATCH 036/138] Add Version Check for CSR Verification Fixes #5738: This change introduces a check for the version number of a CSR document before its signature is verified. If the version number is not 1 (encoded as zero), the verification function fails with an `X509_R_UNSUPPORTED_VERSION` error. To minimize impact, this check is only applied when verifying a certificate signing request using the `-verify` argument, resulting in a `X509_REQ_verify` call. This ensures that malformed certificate requests are rejected by a certification authority, enhancing security and preventing potential issues. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24677) --- crypto/err/openssl.txt | 1 + crypto/x509/x509_err.c | 4 +++- crypto/x509/x_all.c | 5 +++++ include/openssl/x509err.h | 3 ++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 3279f49199f89..93dfbeeea5ef0 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1841,5 +1841,6 @@ X509_R_UNKNOWN_PURPOSE_ID:121:unknown purpose id X509_R_UNKNOWN_SIGID_ALGS:144:unknown sigid algs X509_R_UNKNOWN_TRUST_ID:120:unknown trust id X509_R_UNSUPPORTED_ALGORITHM:111:unsupported algorithm +X509_R_UNSUPPORTED_VERSION:145:unsupported version X509_R_WRONG_LOOKUP_TYPE:112:wrong lookup type X509_R_WRONG_TYPE:122:wrong type diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index 226e45a737b85..607d38f3be3c2 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -79,6 +79,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = { {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_TRUST_ID), "unknown trust id"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNSUPPORTED_ALGORITHM), "unsupported algorithm"}, + {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNSUPPORTED_VERSION), + "unsupported version"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_WRONG_LOOKUP_TYPE), "wrong lookup type"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_WRONG_TYPE), "wrong type"}, {0, NULL} diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index 3083eb1dca9b7..55d3dca1f2d94 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -43,6 +43,11 @@ int X509_verify(X509 *a, EVP_PKEY *r) int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *r, OSSL_LIB_CTX *libctx, const char *propq) { + if (X509_REQ_get_version(a) != X509_REQ_VERSION_1) { + ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_VERSION); + return -1; + } + return ASN1_item_verify_ex(ASN1_ITEM_rptr(X509_REQ_INFO), &a->sig_alg, a->signature, &a->req_info, a->distinguishing_id, r, libctx, propq); diff --git a/include/openssl/x509err.h b/include/openssl/x509err.h index 71b557a3e6b37..77b91c8b2cff3 100644 --- a/include/openssl/x509err.h +++ b/include/openssl/x509err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -63,6 +63,7 @@ # define X509_R_UNKNOWN_SIGID_ALGS 144 # define X509_R_UNKNOWN_TRUST_ID 120 # define X509_R_UNSUPPORTED_ALGORITHM 111 +# define X509_R_UNSUPPORTED_VERSION 145 # define X509_R_WRONG_LOOKUP_TYPE 112 # define X509_R_WRONG_TYPE 122 From 895ecd0ce86c17fc696ad58c9f4b2ac1b821c5d4 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Wed, 19 Jun 2024 14:02:53 +0200 Subject: [PATCH 037/138] Add Test for Verification Failure on Incorrect X509 Version Tests #5738: Introduce a new test to verify that a malformed X509 request with the version field set to version 6 fails either early when reading from data or later when `X509_REQ_verify` is called. Adding a new test recipe `60-test_x509_req.t` Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24677) --- test/build.info | 6 ++- test/recipes/60-test_x509_req.t | 11 +++++ test/x509_req_test.c | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/recipes/60-test_x509_req.t create mode 100644 test/x509_req_test.c diff --git a/test/build.info b/test/build.info index e2b09ae9650b1..80394085b96dc 100644 --- a/test/build.info +++ b/test/build.info @@ -64,7 +64,7 @@ IF[{- !$disabled{tests} -}] ca_internals_test bio_tfo_test membio_test bio_dgram_test list_test \ fips_version_test x509_test hpke_test pairwise_fail_test \ nodefltctxtest evp_xof_test x509_load_cert_file_test bio_meth_test \ - x509_acert_test + x509_acert_test x509_req_test IF[{- !$disabled{'rpk'} -}] PROGRAMS{noinst}=rpktest @@ -1211,6 +1211,10 @@ ENDIF INCLUDE[x509_acert_test]=../include ../apps/include DEPEND[x509_acert_test]=../libcrypto libtestutil.a + SOURCE[x509_req_test]=x509_req_test.c + INCLUDE[x509_req_test]=../include ../apps/include + DEPEND[x509_req_test]=../libcrypto libtestutil.a + {- use File::Spec::Functions; use File::Basename; diff --git a/test/recipes/60-test_x509_req.t b/test/recipes/60-test_x509_req.t new file mode 100644 index 0000000000000..5f8b664946598 --- /dev/null +++ b/test/recipes/60-test_x509_req.t @@ -0,0 +1,11 @@ +#! /usr/bin/env perl +# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use OpenSSL::Test::Simple; + +simple_test("test_x509_req_test", "x509_req_test", "x509_req"); diff --git a/test/x509_req_test.c b/test/x509_req_test.c new file mode 100644 index 0000000000000..7a839d1e84ca2 --- /dev/null +++ b/test/x509_req_test.c @@ -0,0 +1,76 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include + +#include "testutil.h" + +static const char bad_csr_version_6[] = + "-----BEGIN CERTIFICATE REQUEST-----\n" + "MIICoTCCAYkCAQUwXDELMAkGA1UEBhMCQ0gxDTALBgNVBAgMBEJlcm4xDTALBgNV\n" + "BAcMBEJlcm4xFDASBgNVBAoMC0VyYnNsYW5kREVWMRkwFwYDVQQDDBB0ZXN0Lm9w\n" + "ZW5zc2wub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgnKT31X7\n" + "GG1doZXQ0cHY32OjExJT5z/AhZNHt44AdZmrGDwcANBa68mK1pJ4zbLStsa0ABfC\n" + "clPnoq4jqPcoMqPu5SNGR29lBWSQr8AzzHFOalHfYmdsTwRxy2fM56WVfrmi/HY5\n" + "8pZ0LgAuF7Kb8hjUkqBbWzAo0GJaYqWitkrDdproLMLz65GJYYlxXcPd79yt+SHk\n" + "TdfRANcjinRK/EKgkWYVu5yE/lqWl9lwgxY9YAeDp6/WZ7K5wGueiMNYsKoud0MP\n" + "al00AgaBgicIBMfVPdN19p8ZC4u2BuJlM1oq2eZbaP35rAlB1InbPtFIGL0c0h0o\n" + "6prLD6FgYHd1PQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBADQIUWrf2wnUlKK4\n" + "Q2kuK6EtC2CYblmUqV8kUx/sWkfaG2zD7ekyTVJg80IhnsrVJ3VQwOUtbWltgskF\n" + "ZzrwXbIIVkHzeI51jrt/jUXzskCjyDkxjeRgCxSJ1bIlN+OkIeXf/jjDJ+ebyeJl\n" + "oRgg/KtbaJVb9niFjbxdyMNEI5qZAmocFpE2t5S9GlosTEIPNbowZAe8+AeUXGJB\n" + "7SPJZ3U+Rk7Yx6cW2Hc5litIDzJlIN8D86v26lgJ1VEoYGD81wPEhIjHTkRBWhp6\n" + "kGV0EojP8ntSjDFHIH184MQAJYyr6YlEM3DcCYPwydLN/rkEHQVAxKKuSCrpcUMH\n" + "hfcdPO4=\n" + "-----END CERTIFICATE REQUEST-----"; + +/* + * Test for the missing X509 version check discussed in issue #5738 and + * added in PR #24677. + * This test tries to verify a malformed CSR with the X509 version set + * version 6, instead of 1. As this request is malformed, even its + * signature is valid, the verification must fail. + */ +static int test_x509_req_detect_invalid_version(void) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + X509_REQ *req = NULL; + int ret = 0; + + if (!TEST_ptr(bio = BIO_new_mem_buf(bad_csr_version_6, sizeof(bad_csr_version_6) - 1))) + goto err; + req = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL); + if (req == NULL) { + ret = 1; /* success, reading PEM with invalid CSR data is allowed to fail. */ + goto err; + } + if (!TEST_ptr(pkey = X509_REQ_get_pubkey(req))) + goto err; + /* Verification MUST fail at this point. ret != 1. */ + if (!TEST_int_ne(X509_REQ_verify(req, pkey), 1)) + goto err; + ret = 1; /* success */ +err: + EVP_PKEY_free(pkey); + X509_REQ_free(req); + BIO_free(bio); + return ret; +} + +int setup_tests(void) +{ + ADD_TEST(test_x509_req_detect_invalid_version); + return 1; +} + +void cleanup_tests(void) +{ +} From 7d2c0a4b1feb152ee1190dfedc65dfd1c928f9e5 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Wed, 19 Jun 2024 19:09:15 +0200 Subject: [PATCH 038/138] Make x509_req_test ANSI Compatible Update the `x509_req_test` to ensure ANSI compatibility. The integrated certificate string was too long, so the PEM certificate has been moved to `certs/x509-req-detect-invalid-version.pem`. The test have been updated to load this certificate from the file on disk. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24677) --- .../certs/x509-req-detect-invalid-version.pem | 17 ++++++++++ test/recipes/60-test_x509_req.t | 11 ++++-- test/x509_req_test.c | 34 ++++++++----------- 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 test/certs/x509-req-detect-invalid-version.pem diff --git a/test/certs/x509-req-detect-invalid-version.pem b/test/certs/x509-req-detect-invalid-version.pem new file mode 100644 index 0000000000000..8d40c405d9694 --- /dev/null +++ b/test/certs/x509-req-detect-invalid-version.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICoTCCAYkCAQUwXDELMAkGA1UEBhMCQ0gxDTALBgNVBAgMBEJlcm4xDTALBgNV +BAcMBEJlcm4xFDASBgNVBAoMC0VyYnNsYW5kREVWMRkwFwYDVQQDDBB0ZXN0Lm9w +ZW5zc2wub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgnKT31X7 +GG1doZXQ0cHY32OjExJT5z/AhZNHt44AdZmrGDwcANBa68mK1pJ4zbLStsa0ABfC +clPnoq4jqPcoMqPu5SNGR29lBWSQr8AzzHFOalHfYmdsTwRxy2fM56WVfrmi/HY5 +8pZ0LgAuF7Kb8hjUkqBbWzAo0GJaYqWitkrDdproLMLz65GJYYlxXcPd79yt+SHk +TdfRANcjinRK/EKgkWYVu5yE/lqWl9lwgxY9YAeDp6/WZ7K5wGueiMNYsKoud0MP +al00AgaBgicIBMfVPdN19p8ZC4u2BuJlM1oq2eZbaP35rAlB1InbPtFIGL0c0h0o +6prLD6FgYHd1PQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBADQIUWrf2wnUlKK4 +Q2kuK6EtC2CYblmUqV8kUx/sWkfaG2zD7ekyTVJg80IhnsrVJ3VQwOUtbWltgskF +ZzrwXbIIVkHzeI51jrt/jUXzskCjyDkxjeRgCxSJ1bIlN+OkIeXf/jjDJ+ebyeJl +oRgg/KtbaJVb9niFjbxdyMNEI5qZAmocFpE2t5S9GlosTEIPNbowZAe8+AeUXGJB +7SPJZ3U+Rk7Yx6cW2Hc5litIDzJlIN8D86v26lgJ1VEoYGD81wPEhIjHTkRBWhp6 +kGV0EojP8ntSjDFHIH184MQAJYyr6YlEM3DcCYPwydLN/rkEHQVAxKKuSCrpcUMH +hfcdPO4= +-----END CERTIFICATE REQUEST----- diff --git a/test/recipes/60-test_x509_req.t b/test/recipes/60-test_x509_req.t index 5f8b664946598..362a14845be0c 100644 --- a/test/recipes/60-test_x509_req.t +++ b/test/recipes/60-test_x509_req.t @@ -6,6 +6,13 @@ # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html -use OpenSSL::Test::Simple; +use OpenSSL::Test::Utils; +use OpenSSL::Test qw/:DEFAULT srctop_dir/; -simple_test("test_x509_req_test", "x509_req_test", "x509_req"); +BEGIN { + setup("test_x509_req"); +} + +plan tests => 1; + +ok(run(test(["x509_req_test", srctop_dir("test", "certs")])), "running x509_req_test"); diff --git a/test/x509_req_test.c b/test/x509_req_test.c index 7a839d1e84ca2..742b62836b968 100644 --- a/test/x509_req_test.c +++ b/test/x509_req_test.c @@ -12,24 +12,8 @@ #include "testutil.h" -static const char bad_csr_version_6[] = - "-----BEGIN CERTIFICATE REQUEST-----\n" - "MIICoTCCAYkCAQUwXDELMAkGA1UEBhMCQ0gxDTALBgNVBAgMBEJlcm4xDTALBgNV\n" - "BAcMBEJlcm4xFDASBgNVBAoMC0VyYnNsYW5kREVWMRkwFwYDVQQDDBB0ZXN0Lm9w\n" - "ZW5zc2wub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgnKT31X7\n" - "GG1doZXQ0cHY32OjExJT5z/AhZNHt44AdZmrGDwcANBa68mK1pJ4zbLStsa0ABfC\n" - "clPnoq4jqPcoMqPu5SNGR29lBWSQr8AzzHFOalHfYmdsTwRxy2fM56WVfrmi/HY5\n" - "8pZ0LgAuF7Kb8hjUkqBbWzAo0GJaYqWitkrDdproLMLz65GJYYlxXcPd79yt+SHk\n" - "TdfRANcjinRK/EKgkWYVu5yE/lqWl9lwgxY9YAeDp6/WZ7K5wGueiMNYsKoud0MP\n" - "al00AgaBgicIBMfVPdN19p8ZC4u2BuJlM1oq2eZbaP35rAlB1InbPtFIGL0c0h0o\n" - "6prLD6FgYHd1PQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBADQIUWrf2wnUlKK4\n" - "Q2kuK6EtC2CYblmUqV8kUx/sWkfaG2zD7ekyTVJg80IhnsrVJ3VQwOUtbWltgskF\n" - "ZzrwXbIIVkHzeI51jrt/jUXzskCjyDkxjeRgCxSJ1bIlN+OkIeXf/jjDJ+ebyeJl\n" - "oRgg/KtbaJVb9niFjbxdyMNEI5qZAmocFpE2t5S9GlosTEIPNbowZAe8+AeUXGJB\n" - "7SPJZ3U+Rk7Yx6cW2Hc5litIDzJlIN8D86v26lgJ1VEoYGD81wPEhIjHTkRBWhp6\n" - "kGV0EojP8ntSjDFHIH184MQAJYyr6YlEM3DcCYPwydLN/rkEHQVAxKKuSCrpcUMH\n" - "hfcdPO4=\n" - "-----END CERTIFICATE REQUEST-----"; +static char *certsDir = NULL; +static char *certFilePath = NULL; /* * Test for the missing X509 version check discussed in issue #5738 and @@ -45,7 +29,10 @@ static int test_x509_req_detect_invalid_version(void) X509_REQ *req = NULL; int ret = 0; - if (!TEST_ptr(bio = BIO_new_mem_buf(bad_csr_version_6, sizeof(bad_csr_version_6) - 1))) + certFilePath = test_mk_file_path(certsDir, "x509-req-detect-invalid-version.pem"); + if (certFilePath == NULL) + goto err; + if (!TEST_ptr(bio = BIO_new_file(certFilePath, "r"))) goto err; req = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL); if (req == NULL) { @@ -65,8 +52,17 @@ static int test_x509_req_detect_invalid_version(void) return ret; } +OPT_TEST_DECLARE_USAGE("certdir\n") + int setup_tests(void) { + if (!test_skip_common_options()) { + TEST_error("Error parsing test options\n"); + return 0; + } + if (!TEST_ptr(certsDir = test_get_argument(0))) + return 0; + ADD_TEST(test_x509_req_detect_invalid_version); return 1; } From b23cd39f0a4e3cfe142694402a5246a498a3574f Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 19 Jun 2024 08:06:45 +0200 Subject: [PATCH 039/138] [DOCS] Correct history in doc/man3/OSSL_STORE_LOADER.pod Bulk editing had history wrongly specify current functions as deprecated, among other small errors. Fixes #24678 Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24680) --- doc/man3/OSSL_STORE_LOADER.pod | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/man3/OSSL_STORE_LOADER.pod b/doc/man3/OSSL_STORE_LOADER.pod index c008e397e1608..176d39f6981cf 100644 --- a/doc/man3/OSSL_STORE_LOADER.pod +++ b/doc/man3/OSSL_STORE_LOADER.pod @@ -105,7 +105,6 @@ see L: typedef int (*OSSL_STORE_close_fn)(OSSL_STORE_LOADER_CTX *ctx); int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *store_loader, OSSL_STORE_close_fn store_close_function); - void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *store_loader); int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader); OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme); @@ -358,21 +357,25 @@ L =head1 HISTORY OSSL_STORE_LOADER_fetch(), OSSL_STORE_LOADER_up_ref(), -OSSL_STORE_LOADER_free(), OSSL_STORE_LOADER_get0_provider(), -OSSL_STORE_LOADER_get0_properties(), OSSL_STORE_LOADER_is_a(), -OSSL_STORE_LOADER_do_all_provided() and -OSSL_STORE_LOADER_names_do_all() were added in OpenSSL 3.0. +OSSL_STORE_LOADER_get0_provider(), OSSL_STORE_LOADER_get0_properties(), +OSSL_STORE_LOADER_get0_description(), OSSL_STORE_LOADER_is_a(), +OSSL_STORE_LOADER_do_all_provided() and OSSL_STORE_LOADER_names_do_all() +were added in OpenSSL 3.0. -OSSL_STORE_open_ex_fn() was added in OpenSSL 3.0. +B and OSSL_STORE_LOADER_free() were added in OpenSSL +1.1.1. -B, B, OSSL_STORE_LOADER_new(), +OSSL_STORE_LOADER_set_open_ex() and OSSL_STORE_open_ex_fn() were added in +OpenSSL 3.0, and are deprecated. + +B, OSSL_STORE_LOADER_new(), OSSL_STORE_LOADER_set0_scheme(), OSSL_STORE_LOADER_get0_scheme(), OSSL_STORE_LOADER_get0_engine(), OSSL_STORE_LOADER_set_expect(), OSSL_STORE_LOADER_set_find(), OSSL_STORE_LOADER_set_attach(), OSSL_STORE_LOADER_set_open_ex(), OSSL_STORE_LOADER_set_open(), OSSL_STORE_LOADER_set_ctrl(), OSSL_STORE_LOADER_set_load(), OSSL_STORE_LOADER_set_eof(), -OSSL_STORE_LOADER_set_close(), OSSL_STORE_LOADER_free(), +OSSL_STORE_LOADER_set_close(), OSSL_STORE_register_loader(), OSSL_STORE_LOADER_set_error(), OSSL_STORE_unregister_loader(), OSSL_STORE_open_fn(), OSSL_STORE_ctrl_fn(), OSSL_STORE_load_fn(), OSSL_STORE_eof_fn() and OSSL_STORE_close_fn() From 89c9c3b857b5d68d835c3c3d371dc74a26f568fd Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Thu, 20 Jun 2024 20:44:00 +0200 Subject: [PATCH 040/138] Extend `mask` of `ssl_method_st` to 64-bit Fixes #23260: The bit count for `SSL_OP_*` flags has exceeded 32 bits, making it impossible to handle newer flags and protocol extensions with the existing 32-bit variables. This commit extends the `mask` field in the `ssl_method_st` structure to 64-bit, aligning them with the previously extended 64-bit `options` field. Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24692) --- ssl/ssl_local.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 0d979ae7237a8..daab329133cb8 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -419,7 +419,7 @@ struct ssl_cipher_st { struct ssl_method_st { int version; unsigned flags; - unsigned long mask; + uint64_t mask; SSL *(*ssl_new) (SSL_CTX *ctx); void (*ssl_free) (SSL *s); int (*ssl_reset) (SSL *s); From 8f250985ad1ac4efc25621ce2504c52ef0cbe283 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Thu, 20 Jun 2024 20:42:46 +0200 Subject: [PATCH 041/138] Fix typos found by codespell Reviewed-by: Paul Dale Reviewed-by: Kurt Roeckx (Merged from https://github.com/openssl/openssl/pull/24691) --- CHANGES.md | 8 ++++---- NEWS.md | 2 +- apps/include/platform.h | 2 +- crypto/hashtable/hashtable.c | 2 +- doc/man3/OPENSSL_riscvcap.pod | 2 +- fuzz/hashtable.c | 2 +- ssl/ssl_lib.c | 2 +- test/evp_kdf_test.c | 2 +- test/recipes/25-test_x509.t | 2 +- test/tls-provider.c | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9eed55ab76268..0f3701c6d5140 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -318,7 +318,7 @@ OpenSSL 3.3 *Fisher Yu* - * Enable AES and SHA3 optimisations on Applie Silicon M3-based MacOS systems + * Enable AES and SHA3 optimisations on Apple Silicon M3-based MacOS systems similar to M1/M2. *Tom Cosgrove* @@ -3092,7 +3092,7 @@ breaking changes, and mappings for the large list of deprecated functions. this switch breaks interoperability with correct implementations. * Fix a use after free bug in d2i_X509_PUBKEY when overwriting a - re-used X509_PUBKEY object if the second PUBKEY is malformed. + reused X509_PUBKEY object if the second PUBKEY is malformed. *Bernd Edlinger* @@ -4426,7 +4426,7 @@ OpenSSL 1.1.0 *Billy Bob Brumley, Nicola Tuveri* * Fix a use after free bug in d2i_X509_PUBKEY when overwriting a - re-used X509_PUBKEY object if the second PUBKEY is malformed. + reused X509_PUBKEY object if the second PUBKEY is malformed. *Bernd Edlinger* @@ -16546,7 +16546,7 @@ s-cbc 3624.96k 5258.21k 5530.91k 5624.30k 5628.26k *Bodo Moeller* * Store verify_result within SSL_SESSION also for client side to - avoid potential security hole. (Re-used sessions on the client side + avoid potential security hole. (Reused sessions on the client side always resulted in verify_result==X509_V_OK, not using the original result of the server certificate verification.) diff --git a/NEWS.md b/NEWS.md index bc8b40ee7353c..11e1057b87d1d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -116,7 +116,7 @@ changes: * Optimized AES-CTR for ARM Neoverse V1 and V2 - * Enable AES and SHA3 optimisations on Applie Silicon M3-based MacOS systems + * Enable AES and SHA3 optimisations on Apple Silicon M3-based MacOS systems similar to M1/M2. * Various optimizations for cryptographic routines using RISC-V vector crypto diff --git a/apps/include/platform.h b/apps/include/platform.h index 491559df31528..6ba26a7d69f5a 100644 --- a/apps/include/platform.h +++ b/apps/include/platform.h @@ -16,7 +16,7 @@ /* * VMS C only for now, implemented in vms_decc_init.c * If other C compilers forget to terminate argv with NULL, this function - * can be re-used. + * can be reused. */ char **copy_argv(int *argc, char *argv[]); # endif diff --git a/crypto/hashtable/hashtable.c b/crypto/hashtable/hashtable.c index dace86e13f7eb..67c9b190cf8f2 100644 --- a/crypto/hashtable/hashtable.c +++ b/crypto/hashtable/hashtable.c @@ -68,7 +68,7 @@ #include "internal/numbers.h" /* - * When we do a lookup/insert/delete, there is a high likelyhood + * When we do a lookup/insert/delete, there is a high likelihood * that we will iterate over at least part of the neighborhood list * As such, because we design a neighborhood entry to fit into a single * cache line it is advantageous, when supported to fetch the entire diff --git a/doc/man3/OPENSSL_riscvcap.pod b/doc/man3/OPENSSL_riscvcap.pod index e1a2aa5337ff7..1ebf20826a7f1 100644 --- a/doc/man3/OPENSSL_riscvcap.pod +++ b/doc/man3/OPENSSL_riscvcap.pod @@ -120,7 +120,7 @@ Could be detected using hwprobe for Linux kernel >= 6.8 =item V -Vector Extention for Application Processors +Vector Extension for Application Processors Could be detected using hwprobe for Linux kernel >= 6.5 diff --git a/fuzz/hashtable.c b/fuzz/hashtable.c index 35cf9c8f3ba74..b58d48b225052 100644 --- a/fuzz/hashtable.c +++ b/fuzz/hashtable.c @@ -130,7 +130,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) /* * We need at least 11 bytes to be able to do anything here - * 1 byte to detect the operation to preform, 2 bytes + * 1 byte to detect the operation to perform, 2 bytes * for the lookup key, and 8 bytes of value */ if (len < 11) { diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 05047e916390f..37a307b9927c3 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -6395,7 +6395,7 @@ int ssl_validate_ct(SSL_CONNECTION *s) end: CT_POLICY_EVAL_CTX_free(ctx); /* - * With SSL_VERIFY_NONE the session may be cached and re-used despite a + * With SSL_VERIFY_NONE the session may be cached and reused despite a * failure return code here. Also the application may wish the complete * the handshake, and then disconnect cleanly at a higher layer, after * checking the verification status of the completed connection. diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 858c79660216e..67de1cc7a7486 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -1771,7 +1771,7 @@ static int test_kdf_get_kdf(void) || !TEST_ptr(kdf2 = EVP_KDF_fetch(NULL, LN_tls1_prf, NULL)) || !test_kdfs_same(kdf1, kdf2)) ok = 0; - /* kdf1 is re-used below, so don't free it here */ + /* kdf1 is reused below, so don't free it here */ EVP_KDF_free(kdf2); kdf2 = NULL; diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 52ba7d1821398..f5e5919eab945 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -305,7 +305,7 @@ ok(run(app(["openssl", "x509", "-req", "-text", "-CAcreateserial", "-in", $b_csr]))); ok(-e $ca_serial_dot_in_dir); -# Tests for explict start and end dates of certificates +# Tests for explicit start and end dates of certificates my %today = (strftime("%Y-%m-%d", gmtime) => 1); my $enddate; ok(run(app(["openssl", "x509", "-req", "-text", diff --git a/test/tls-provider.c b/test/tls-provider.c index d8ec7c2dc2ae8..967a2495e1ed3 100644 --- a/test/tls-provider.c +++ b/test/tls-provider.c @@ -1115,7 +1115,7 @@ static const OSSL_DISPATCH xor_keymgmt_functions[] = { OSSL_DISPATCH_END }; -/* We're re-using most XOR keymgmt functions also for signature operations: */ +/* We're reusing most XOR keymgmt functions also for signature operations: */ static void *xor_xorhmacsig_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) { XORKEY *k = xor_gen(genctx, osslcb, cbarg); From be5adfd6e36817fe8d5b5793f8c23189dc412045 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Tue, 18 Jun 2024 09:08:40 +0000 Subject: [PATCH 042/138] Support subjectDirectoryAttributes and associatedInformation exts Added tests for SDA and AI extensions. Added internal function ossl_print_attribute_value() with documentation. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24669) --- crypto/x509/build.info | 2 +- crypto/x509/ext_dat.h | 2 + crypto/x509/standard_exts.h | 2 + crypto/x509/v3_sda.c | 90 +++++++ crypto/x509/x_attrib.c | 226 ++++++++++++++++++ .../man3/ossl_print_attribute_value.pod | 52 ++++ doc/man3/X509_dup.pod | 3 + doc/man3/d2i_X509.pod | 2 + include/crypto/x509.h | 6 + include/openssl/x509v3.h.in | 3 + test/certs/ext-associatedInformation.pem | 10 + test/certs/ext-subjectDirectoryAttributes.pem | 10 + test/recipes/25-test_x509.t | 53 +++- util/libcrypto.num | 5 + 14 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 crypto/x509/v3_sda.c create mode 100644 doc/internal/man3/ossl_print_attribute_value.pod create mode 100644 test/certs/ext-associatedInformation.pem create mode 100644 test/certs/ext-subjectDirectoryAttributes.pem diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 1184329b2052f..ff648e99976f5 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -16,7 +16,7 @@ SOURCE[../../libcrypto]=\ pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \ v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_no_rev_avail.c \ v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ - x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c + x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c v3_sda.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index befb8e444aad7..f3ad5afbf054e 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -34,3 +34,5 @@ extern const X509V3_EXT_METHOD ossl_v3_indirect_issuer; extern const X509V3_EXT_METHOD ossl_v3_targeting_information; extern const X509V3_EXT_METHOD ossl_v3_holder_name_constraints; extern const X509V3_EXT_METHOD ossl_v3_delegated_name_constraints; +extern const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs; +extern const X509V3_EXT_METHOD ossl_v3_associated_info; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index f399bde8b3c6a..655dd21e1e7aa 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -62,6 +62,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_name_constraints, &ossl_v3_policy_mappings, &ossl_v3_inhibit_anyp, + &ossl_v3_subj_dir_attrs, &ossl_v3_idp, &ossl_v3_alt[2], &ossl_v3_freshest_crl, @@ -81,6 +82,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_single_use, &ossl_v3_group_ac, &ossl_v3_holder_name_constraints, + &ossl_v3_associated_info, }; /* Number of standard extensions */ diff --git a/crypto/x509/v3_sda.c b/crypto/x509/v3_sda.c new file mode 100644 index 0000000000000..35602fc6811f0 --- /dev/null +++ b/crypto/x509/v3_sda.c @@ -0,0 +1,90 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "ext_dat.h" + +ASN1_ITEM_TEMPLATE(ATTRIBUTES_SYNTAX) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Attributes, X509_ATTRIBUTE) +ASN1_ITEM_TEMPLATE_END(ATTRIBUTES_SYNTAX) + +IMPLEMENT_ASN1_FUNCTIONS(ATTRIBUTES_SYNTAX) + +static int i2r_ATTRIBUTES_SYNTAX(X509V3_EXT_METHOD *method, + ATTRIBUTES_SYNTAX *attrlst, + BIO *out, int indent) +{ + X509_ATTRIBUTE *attr; + ASN1_TYPE *av; + int i, j, attr_nid; + + if (!attrlst) { + if (BIO_printf(out, "\n") <= 0) + return 0; + return 1; + } + if (!sk_X509_ATTRIBUTE_num(attrlst)) { + if (BIO_printf(out, "\n") <= 0) + return 0; + return 1; + } + + for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { + ASN1_OBJECT *attr_obj; + attr = sk_X509_ATTRIBUTE_value(attrlst, i); + attr_obj = X509_ATTRIBUTE_get0_object(attr); + attr_nid = OBJ_obj2nid(attr_obj); + if (indent && BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + if (attr_nid == NID_undef) { + if (i2a_ASN1_OBJECT(out, attr_obj) <= 0) + return 0; + if (BIO_puts(out, ":\n") <= 0) + return 0; + } else if (BIO_printf(out, "%s:\n", OBJ_nid2ln(attr_nid)) <= 0) { + return 0; + } + + if (X509_ATTRIBUTE_count(attr)) { + for (j = 0; j < X509_ATTRIBUTE_count(attr); j++) + { + av = X509_ATTRIBUTE_get0_type(attr, j); + if (ossl_print_attribute_value(out, attr_nid, av, indent + 4) <= 0) + return 0; + if (BIO_puts(out, "\n") <= 0) + return 0; + } + } else if (BIO_printf(out, "%*s\n", indent + 4, "") <= 0) { + return 0; + } + } + return 1; +} + +const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs = { + NID_subject_directory_attributes, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(ATTRIBUTES_SYNTAX), + 0, 0, 0, 0, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_ATTRIBUTES_SYNTAX, + 0, + NULL +}; + +const X509V3_EXT_METHOD ossl_v3_associated_info = { + NID_associated_information, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(ATTRIBUTES_SYNTAX), + 0, 0, 0, 0, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_ATTRIBUTES_SYNTAX, + 0, + NULL +}; diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c index 5c7e622d1a0bc..4bae377905886 100644 --- a/crypto/x509/x_attrib.c +++ b/crypto/x509/x_attrib.c @@ -13,6 +13,7 @@ #include #include #include "x509_local.h" +#include /*- * X509_ATTRIBUTE: this has the following form: @@ -56,3 +57,228 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value) ASN1_TYPE_free(val); return NULL; } + +static int print_hex(BIO *out, unsigned char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (BIO_printf(out, "%02X ", buf[i]) <= 0) { + return 0; + } + } + return 1; +} + +static int asn1_integer_print_bio(BIO *bio, const ASN1_INTEGER *num) +{ + BIGNUM *num_bn; + int result = 0; + char *hex; + + num_bn = ASN1_INTEGER_to_BN(num, NULL); + if (num_bn == NULL) + return -1; + if ((hex = BN_bn2hex(num_bn)) != NULL) { + result = BIO_write(bio, "0x", 2) > 0; + result = result && BIO_write(bio, hex, strlen(hex)) > 0; + OPENSSL_free(hex); + } else { + return -1; + } + BN_free(num_bn); + + return result; +} + +static int print_oid (BIO *out, ASN1_OBJECT *oid) { + const char *ln; + char objbuf[80]; + int rc; + + if (OBJ_obj2txt(objbuf, sizeof(objbuf), oid, 1) <= 0) + return 0; + ln = OBJ_nid2ln(OBJ_obj2nid(oid)); + rc = (ln != NULL) + ? BIO_printf(out, "%s (%s)", objbuf, ln) + : BIO_printf(out, "%s", objbuf); + if (rc < 0) + return 0; + return 1; +} + +int ossl_print_attribute_value(BIO *out, + int obj_nid, + const ASN1_TYPE *av, + int indent) +{ + ASN1_STRING *str; + unsigned char *value; + X509_NAME *xn = NULL; + int64_t int_val; + + /* + * This switch-case is only for syntaxes that are not encoded as a single + * primitively-constructed value universal ASN.1 type. + */ + switch (obj_nid) { + case NID_undef: /* Unrecognized OID. */ + break; + /* Attribute types with DN syntax. */ + case NID_member: + case NID_roleOccupant: + case NID_seeAlso: + case NID_manager: + case NID_documentAuthor: + case NID_secretary: + case NID_associatedName: + case NID_dITRedirect: + case NID_owner: + value = av->value.sequence->data; + xn = d2i_X509_NAME(NULL, + (const unsigned char**)&(av->value.sequence->data), + av->value.sequence->length); + if (xn == NULL) { + BIO_puts(out, "(COULD NOT DECODE DISTINGUISHED NAME)\n"); + return 0; + } + /* + * d2i_ functions increment the ppin pointer. See doc/man3/d2i_X509.pod. + * This resets the pointer. We don't want to corrupt this value. + */ + av->value.sequence->data = value; + if (X509_NAME_print_ex(out, xn, indent, XN_FLAG_SEP_CPLUS_SPC) <= 0) + return 0; + X509_NAME_free(xn); + return 1; + + default: + break; + } + + switch (av->type) { + case V_ASN1_BOOLEAN: + if (av->value.boolean) { + return BIO_printf(out, "%*sTRUE", indent, ""); + } else { + return BIO_printf(out, "%*sFALSE", indent, ""); + } + + case V_ASN1_INTEGER: + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + if (ASN1_INTEGER_get_int64(&int_val, av->value.integer) > 0) { + return BIO_printf(out, "%lld", (long long int)int_val); + } else { + str = av->value.integer; + return asn1_integer_print_bio(out, str); + } + + case V_ASN1_ENUMERATED: + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + if (ASN1_ENUMERATED_get_int64(&int_val, av->value.enumerated) > 0) { + return BIO_printf(out, "%lld", (long long int)int_val); + } else { + str = av->value.enumerated; + return asn1_integer_print_bio(out, str); + } + + case V_ASN1_BIT_STRING: + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + return print_hex(out, av->value.bit_string->data, + av->value.bit_string->length); + + case V_ASN1_OCTET_STRING: + case V_ASN1_VIDEOTEXSTRING: + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + return print_hex(out, av->value.octet_string->data, + av->value.octet_string->length); + + case V_ASN1_NULL: + return BIO_printf(out, "%*sNULL", indent, ""); + + case V_ASN1_OBJECT: + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + return print_oid(out, av->value.object); + + /* + * ObjectDescriptor is an IMPLICIT GraphicString, but GeneralString is a + * superset supported by OpenSSL, so we will use that anywhere a + * GraphicString is needed here. + */ + case V_ASN1_GENERALSTRING: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_OBJECT_DESCRIPTOR: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.generalstring->length, + av->value.generalstring->data); + + /* EXTERNAL would go here. */ + /* EMBEDDED PDV would go here. */ + + case V_ASN1_UTF8STRING: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.utf8string->length, + av->value.utf8string->data); + + case V_ASN1_REAL: + return BIO_printf(out, "%*sREAL", indent, ""); + + /* RELATIVE-OID would go here. */ + /* TIME would go here. */ + + case V_ASN1_SEQUENCE: + return ASN1_parse_dump(out, av->value.sequence->data, + av->value.sequence->length, indent, 1); + + case V_ASN1_SET: + return ASN1_parse_dump(out, av->value.set->data, + av->value.set->length, indent, 1); + + /* + * UTCTime ::= [UNIVERSAL 23] IMPLICIT VisibleString + * GeneralizedTime ::= [UNIVERSAL 24] IMPLICIT VisibleString + * VisibleString is a superset for NumericString, so it will work for that. + */ + case V_ASN1_VISIBLESTRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_NUMERICSTRING: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.visiblestring->length, + av->value.visiblestring->data); + + case V_ASN1_PRINTABLESTRING: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.printablestring->length, + av->value.printablestring->data); + + case V_ASN1_T61STRING: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.t61string->length, + av->value.t61string->data); + + case V_ASN1_IA5STRING: + return BIO_printf(out, "%*s%.*s", indent, "", + av->value.ia5string->length, + av->value.ia5string->data); + + /* UniversalString would go here. */ + /* CHARACTER STRING would go here. */ + /* BMPString would go here. */ + /* DATE would go here. */ + /* TIME-OF-DAY would go here. */ + /* DATE-TIME would go here. */ + /* DURATION would go here. */ + /* OID-IRI would go here. */ + /* RELATIVE-OID-IRI would go here. */ + + /* Would it be approriate to just hexdump? */ + default: + return BIO_printf(out, "%*s", indent, "", av->type); + } +} diff --git a/doc/internal/man3/ossl_print_attribute_value.pod b/doc/internal/man3/ossl_print_attribute_value.pod new file mode 100644 index 0000000000000..1816f838e918c --- /dev/null +++ b/doc/internal/man3/ossl_print_attribute_value.pod @@ -0,0 +1,52 @@ +=pod + +=head1 NAME + +ossl_print_attribute_value +- Print an X.500 directory attribute value + +=head1 SYNOPSIS + + #include + + int ossl_print_attribute_value(BIO *out, int obj_nid, const ASN1_TYPE *av, int indent); + +=head1 DESCRIPTION + +ossl_print_attribute_value() prints an X.500 directory value, which is an +ASN.1 value and an associated attribute type that informs its interpretation, +syntax, display characteristics, comparison, sorting, and substring searching +behaviors, among other things. This attribute type is identified by an ASN.1 +object identifier. + +X.500 directory values are used in the relative distinguished names in a +distinguished name, as seen in the C and C fields of an X.509 +public key certificate. They also appear in the attributes of an X.509 +attribute certificate, as well as in the subjectDirectoryAttributes or +associatedInformation X.509v3 extensions. + +The I argument is a B pointer for printing the output. The I +argument is the NID of the attribute type object identifier. The ASN.1 value +itself is passed in I and the level of desired indentation in terms of the +number of spaces is specified in I. + +This function generally prints values in such a way as to keep them on a single +line, but this is not always the case. Unrecognized attribute types whose syntax +is a C or C will be printed on multiple lines, for instance. Not +all ASN.1 syntaxes are currently supported, and there is no guarantee for what +printed values will look like in future versions. + +=head1 RETURN VALUES + +Returns 1 if it succeeds in printing, and 0 if it failed. + +=head1 COPYRIGHT + +Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index dc43c46aa9ab9..f350d74a7196f 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -19,6 +19,9 @@ ASIdentifiers_free, ASIdentifiers_new, ASRange_free, ASRange_new, +ATTRIBUTES_SYNTAX_free, +ATTRIBUTES_SYNTAX_it, +ATTRIBUTES_SYNTAX_new, AUTHORITY_INFO_ACCESS_free, AUTHORITY_INFO_ACCESS_new, AUTHORITY_KEYID_free, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 38181e764bb43..86a653ad148ad 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -38,6 +38,7 @@ d2i_ASN1_UTCTIME, d2i_ASN1_UTF8STRING, d2i_ASN1_VISIBLESTRING, d2i_ASRange, +d2i_ATTRIBUTES_SYNTAX, d2i_AUTHORITY_INFO_ACCESS, d2i_AUTHORITY_KEYID, d2i_BASIC_CONSTRAINTS, @@ -220,6 +221,7 @@ i2d_ASN1_UTF8STRING, i2d_ASN1_VISIBLESTRING, i2d_ASN1_bio_stream, i2d_ASRange, +i2d_ATTRIBUTES_SYNTAX, i2d_AUTHORITY_INFO_ACCESS, i2d_AUTHORITY_KEYID, i2d_BASIC_CONSTRAINTS, diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 18eb2f7c63f99..81d543a7a1389 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -388,4 +388,10 @@ STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) int type, const unsigned char *bytes, int len); + +int ossl_print_attribute_value(BIO *out, + int obj_nid, + const ASN1_TYPE *av, + int indent); + #endif /* OSSL_CRYPTO_X509_H */ diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 7c2313e424881..10fc663e6dc56 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1021,6 +1021,9 @@ void PROFESSION_INFO_set0_registrationNumber( int OSSL_GENERAL_NAMES_print(BIO *out, GENERAL_NAMES *gens, int indent); +typedef STACK_OF(X509_ATTRIBUTE) ATTRIBUTES_SYNTAX; +DECLARE_ASN1_FUNCTIONS(ATTRIBUTES_SYNTAX) + # ifdef __cplusplus } # endif diff --git a/test/certs/ext-associatedInformation.pem b/test/certs/ext-associatedInformation.pem new file mode 100644 index 0000000000000..e9278e1381882 --- /dev/null +++ b/test/certs/ext-associatedInformation.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBYzCCAU2gAwIBAgIEDCI4TjANBgkqhkiG9w0BAQEFADARMQ8wDQYDVQQDDAZI +aSBtb20wIhgPMjAyMjEwMjkwMTIzNDNaGA8yMDIyMTAyOTAxMjM0M1owETEPMA0G +A1UEAwwGSGkgbW9tMAowBQYDKgMEAwEAo4HaMIHXMIHUBgNVHUsEgcwwgckwgX8G +A1UEAzF4DAtTdGV2ZSBCcnVsZQwPRHIuIFN0ZXZlIEJydWxlDCJEci4gU3RldmUg +QnJ1bGUsIGZyb20gQnJ1bGVzIFJ1bGVzDDRUaGUgZ2l2ZW5OYW1lIGF0dHJpYnV0 +ZSBiZWxvdyBpcyBpbnRlbnRpb25hbGx5IGVtcHR5MAwGA1UEajEFBgNVBAMwGgYD +VQQgMRMwETEPMA0GA1UEAwwGSGkgbW9tMAcGA1UEKjEAMBIGA1UEBzELDAlGdW5r +eXRvd24wDQYJKoZIhvcNAQEBBQADAQA= +-----END CERTIFICATE----- diff --git a/test/certs/ext-subjectDirectoryAttributes.pem b/test/certs/ext-subjectDirectoryAttributes.pem new file mode 100644 index 0000000000000..4dcb43dbb8aae --- /dev/null +++ b/test/certs/ext-subjectDirectoryAttributes.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBYzCCAU2gAwIBAgIEDCI4TjANBgkqhkiG9w0BAQEFADARMQ8wDQYDVQQDDAZI +aSBtb20wIhgPMjAyMjEwMjkwMTI0NDlaGA8yMDIyMTAyOTAxMjQ0OVowETEPMA0G +A1UEAwwGSGkgbW9tMAowBQYDKgMEAwEAo4HaMIHXMIHUBgNVHQkEgcwwgckwgX8G +A1UEAzF4DAtTdGV2ZSBCcnVsZQwPRHIuIFN0ZXZlIEJydWxlDCJEci4gU3RldmUg +QnJ1bGUsIGZyb20gQnJ1bGVzIFJ1bGVzDDRUaGUgZ2l2ZW5OYW1lIGF0dHJpYnV0 +ZSBiZWxvdyBpcyBpbnRlbnRpb25hbGx5IGVtcHR5MAwGA1UEajEFBgNVBAMwGgYD +VQQgMRMwETEPMA0GA1UEAwwGSGkgbW9tMAcGA1UEKjEAMBIGA1UEBzELDAlGdW5r +eXRvd24wDQYJKoZIhvcNAQEBBQADAQA= +-----END CERTIFICATE----- diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index f5e5919eab945..579f90278d160 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 66; +plan tests => 82; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -193,6 +193,57 @@ cert_contains($dnc_cert, cert_contains($dnc_cert, "DirName:CN = Wildboar", 1, 'X.509 Delegated Name Constraint'); +my $sda_cert = srctop_file(@certs, "ext-subjectDirectoryAttributes.pem"); +cert_contains($sda_cert, + "Steve Brule", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "CN=Hi mom", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "Funkytown", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "commonName", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "owner", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "givenName", + 1, 'X.509 Subject Directory Attributes'); +cert_contains($sda_cert, + "localityName", + 1, 'X.509 Subject Directory Attributes'); + +my $ass_info_cert = srctop_file(@certs, "ext-associatedInformation.pem"); +cert_contains($ass_info_cert, + "Steve Brule", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "CN=Hi mom", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "Funkytown", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "commonName", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "owner", + 1, 'X509v3 Associated Information'); +cert_contains($sda_cert, + "givenName", + 1, 'X509v3 Associated Information'); +cert_contains($ass_info_cert, + "localityName", + 1, 'X509v3 Associated Information'); sub test_errors { # actually tests diagnostics of OSSL_STORE my ($expected, $cert, @opts) = @_; diff --git a/util/libcrypto.num b/util/libcrypto.num index 681183a9f4c58..2c9292d4abe0a 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5683,3 +5683,8 @@ OSSL_TARGETING_INFORMATION_free ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_new ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_it ? 3_4_0 EXIST::FUNCTION: OSSL_GENERAL_NAMES_print ? 3_4_0 EXIST::FUNCTION: +d2i_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: +i2d_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: +ATTRIBUTES_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: +ATTRIBUTES_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: +ATTRIBUTES_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: From 94567d6889b8b48ac618cd8a90911e6732d0e4df Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 31 May 2024 14:59:21 +0200 Subject: [PATCH 043/138] Add Provider compatibility on PR CI job Reviewed-by: Paul Dale Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/24537) --- .github/workflows/prov-compat-label.yml | 266 ++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 .github/workflows/prov-compat-label.yml diff --git a/.github/workflows/prov-compat-label.yml b/.github/workflows/prov-compat-label.yml new file mode 100644 index 0000000000000..f12d31593751d --- /dev/null +++ b/.github/workflows/prov-compat-label.yml @@ -0,0 +1,266 @@ +# Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +# This verifies that FIPS and legacy providers built against some earlier +# released versions continue to run against the current branch. + +name: Provider compatibility for PRs + +on: [pull_request] + +permissions: + contents: read + +env: + opts: enable-rc5 enable-md2 enable-ssl3 enable-weak-ssl-ciphers enable-zlib + +jobs: + fips-releases: + if: ${{ contains(github.event.pull_request.labels.*.name,'extended tests') }} + strategy: + matrix: + release: [ + # Formally released versions should be added here. + # `dir' it the directory inside the tarball. + # `tgz' is the name of the tarball. + # `url' is the download URL. + { + dir: openssl-3.0.0, + tgz: openssl-3.0.0.tar.gz, + url: "https://www.openssl.org/source/old/3.0/openssl-3.0.0.tar.gz", + }, + { + dir: openssl-3.0.8, + tgz: openssl-3.0.8.tar.gz, + url: "https://www.openssl.org/source/openssl-3.0.8.tar.gz", + }, + { + dir: openssl-3.0.9, + tgz: openssl-3.0.9.tar.gz, + url: "https://www.openssl.org/source/openssl-3.0.9.tar.gz", + }, + { + dir: openssl-3.1.2, + tgz: openssl-3.1.2.tar.gz, + url: "https://www.openssl.org/source/openssl-3.1.2.tar.gz", + }, + ] + + runs-on: ubuntu-latest + steps: + - name: create download directory + run: mkdir downloads + - name: download release source + run: wget --no-verbose ${{ matrix.release.url }} + working-directory: downloads + - name: unpack release source + run: tar xzf downloads/${{ matrix.release.tgz }} + + - name: localegen + run: sudo locale-gen tr_TR.UTF-8 + + - name: config release + run: | + ./config --banner=Configured enable-shared enable-fips ${{ env.opts }} + working-directory: ${{ matrix.release.dir }} + - name: config dump release + run: ./configdata.pm --dump + working-directory: ${{ matrix.release.dir }} + + - name: make release + run: make -s -j4 + working-directory: ${{ matrix.release.dir }} + + - name: create release artifacts + run: | + tar cz -H posix -f ${{ matrix.release.tgz }} ${{ matrix.release.dir }} + + - name: show module versions from release + run: | + ./util/wrap.pl -fips apps/openssl list -provider-path providers \ + -provider base \ + -provider default \ + -provider fips \ + -provider legacy \ + -providers + working-directory: ${{ matrix.release.dir }} + + - uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.release.tgz }} + path: ${{ matrix.release.tgz }} + retention-days: 7 + + development-branches: + if: ${{ contains(github.event.pull_request.labels.*.name,'extended tests') }} + strategy: + matrix: + branch: [ + # Currently supported FIPS capable branches should be added here. + # `name' is the branch name used to checkout out. + # `dir' directory that will be used to build and test in. + # `tgz' is the name of the tarball use to keep the artifacts of + # the build. + { + name: '', + dir: PR, + tgz: PR.tar.gz, + }, { + name: openssl-3.0, + dir: branch-3.0, + tgz: branch-3.0.tar.gz, + }, { + name: openssl-3.1, + dir: branch-3.1, + tgz: branch-3.1.tar.gz, + }, { + name: openssl-3.2, + dir: branch-3.2, + tgz: branch-3.2.tar.gz, + }, { + name: openssl-3.3, + dir: branch-3.3, + tgz: branch-3.3.tar.gz, + }, { + name: master, + dir: branch-master, + tgz: branch-master.tar.gz, + }, + ] + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ matrix.branch.dir }} + repository: openssl/openssl + ref: ${{ matrix.branch.name }} + - name: localegen + run: sudo locale-gen tr_TR.UTF-8 + + - name: config branch + run: | + ./config --banner=Configured enable-shared enable-fips ${{ env.opts }} + working-directory: ${{ matrix.branch.dir }} + - name: config dump current + run: ./configdata.pm --dump + working-directory: ${{ matrix.branch.dir }} + + - name: make branch + run: make -s -j4 + working-directory: ${{ matrix.branch.dir }} + + - name: create branch artifacts + run: | + tar cz -H posix -f ${{ matrix.branch.tgz }} ${{ matrix.branch.dir }} + + - name: show module versions from branch + run: | + ./util/wrap.pl -fips apps/openssl list -provider-path providers \ + -provider base \ + -provider default \ + -provider fips \ + -provider legacy \ + -providers + working-directory: ${{ matrix.branch.dir }} + + - name: get cpu info + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + working-directory: ${{ matrix.branch.dir }} + + - uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.branch.tgz }} + path: ${{ matrix.branch.tgz }} + retention-days: 7 + + cross-testing: + if: ${{ contains(github.event.pull_request.labels.*.name,'extended tests') }} + needs: [fips-releases, development-branches] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # These can't be figured out earlier and included here as a variable + # substitution. + # + # Note that releases are not used as a test environment for + # later providers. Problems in these situations ought to be + # caught by cross branch testing before the release. + tree_a: [ branch-master, branch-3.3, branch-3.2, branch-3.1, branch-3.0, + openssl-3.0.0, openssl-3.0.8, openssl-3.0.9, openssl-3.1.2 ] + tree_b: [ PR ] + include: + - tree_a: PR + tree_b: branch-master + - tree_a: PR + tree_b: branch-3.3 + - tree_a: PR + tree_b: branch-3.2 + - tree_a: PR + tree_b: branch-3.1 + - tree_a: PR + tree_b: branch-3.0 + steps: + - name: early exit checks + id: early_exit + run: | + if [ "${{ matrix.tree_a }}" = "${{ matrix.tree_b }}" ]; \ + then \ + echo "Skipping because both are the same version"; \ + exit 1; \ + fi + continue-on-error: true + + - uses: actions/download-artifact@v3 + if: steps.early_exit.outcome == 'success' + with: + name: ${{ matrix.tree_a }}.tar.gz + - name: unpack first build + if: steps.early_exit.outcome == 'success' + run: tar xzf "${{ matrix.tree_a }}.tar.gz" + + - uses: actions/download-artifact@v3 + if: steps.early_exit.outcome == 'success' + with: + name: ${{ matrix.tree_b }}.tar.gz + - name: unpack second build + if: steps.early_exit.outcome == 'success' + run: tar xzf "${{ matrix.tree_b }}.tar.gz" + + - name: set up cross validation of FIPS from A with tree from B + if: steps.early_exit.outcome == 'success' + run: | + cp providers/fips.so ../${{ matrix.tree_b }}/providers/ + cp providers/fipsmodule.cnf ../${{ matrix.tree_b }}/providers/ + working-directory: ${{ matrix.tree_a }} + + - name: show module versions from cross validation + if: steps.early_exit.outcome == 'success' + run: | + ./util/wrap.pl -fips apps/openssl list -provider-path providers \ + -provider base \ + -provider default \ + -provider fips \ + -provider legacy \ + -providers + working-directory: ${{ matrix.tree_b }} + + - name: get cpu info + if: steps.early_exit.outcome == 'success' + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + working-directory: ${{ matrix.tree_b }} + + - name: run cross validation tests of FIPS from A with tree from B + if: steps.early_exit.outcome == 'success' + run: | + make test HARNESS_JOBS=${HARNESS_JOBS:-4} + working-directory: ${{ matrix.tree_b }} From 3fc784835cdb8489117c2680e867cd32b3b70fbe Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 20 May 2024 14:25:17 +0200 Subject: [PATCH 044/138] stricter parser for ipv4_from_asc reject invalid IPv4 addresses in ipv4_from_asc The old scanf-based parser accepted all kinds of invalid inputs like: "1.2.3.4.5" "1.2.3.4 " "1.2.3. 4" " 1.2.3.4" "1.2.3.4." "1.2.3.+4" "1.2.3.4.example.test" "1.2.3.01" "1.2.3.0x1" Thanks to Amir Mohamadi for pointing this out. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24438) --- crypto/x509/v3_utl.c | 67 ++++++++++++++++++++++++------- test/x509_internal_test.c | 84 +++++++++++++++++++++++++++++++++++---- 2 files changed, 129 insertions(+), 22 deletions(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index a036e9e9ad822..0d956eec3ced6 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1151,23 +1151,60 @@ int ossl_a2i_ipadd(unsigned char *ipout, const char *ipasc) } } -static int ipv4_from_asc(unsigned char *v4, const char *in) -{ - const char *p; - int a0, a1, a2, a3, n; +/* + * get_ipv4_component consumes one IPv4 component, terminated by either '.' or + * the end of the string, from *str. On success, it returns one, sets *out + * to the component, and advances *str to the first unconsumed character. On + * invalid input, it returns zero. + */ +static int get_ipv4_component(uint8_t *out_byte, const char **str) { + /* Store a slightly larger intermediary so the overflow check is easier. */ + uint32_t out = 0; - if (sscanf(in, "%d.%d.%d.%d%n", &a0, &a1, &a2, &a3, &n) != 4) - return 0; - if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255) - || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255)) - return 0; - p = in + n; - if (!(*p == '\0' || ossl_isspace(*p))) + for (;;) { + if (!ossl_isdigit(**str)) { + return 0; + } + out = (out * 10) + (**str - '0'); + if (out > 255) { + /* Components must be 8-bit. */ + return 0; + } + (*str)++; + if ((**str) == '.' || (**str) == '\0') { + *out_byte = (uint8_t)out; + return 1; + } + if (out == 0) { + /* Reject extra leading zeros. Parsers sometimes treat them as + * octal, so accepting them would misinterpret input. + */ + return 0; + } + } +} + +/* + * get_ipv4_dot consumes a '.' from *str and advances it. It returns one on + * success and zero if *str does not point to a '.'. + */ +static int get_ipv4_dot(const char **str) +{ + if (**str != '.') { return 0; - v4[0] = a0; - v4[1] = a1; - v4[2] = a2; - v4[3] = a3; + } + (*str)++; + return 1; +} + +static int ipv4_from_asc(unsigned char *v4, const char *in) +{ + if (!get_ipv4_component(&v4[0], &in) || !get_ipv4_dot(&in) + || !get_ipv4_component(&v4[1], &in) || !get_ipv4_dot(&in) + || !get_ipv4_component(&v4[2], &in) || !get_ipv4_dot(&in) + || !get_ipv4_component(&v4[3], &in) || *in != '\0') { + return 0; + } return 1; } diff --git a/test/x509_internal_test.c b/test/x509_internal_test.c index be43537329bbc..6c2e2c3b08570 100644 --- a/test/x509_internal_test.c +++ b/test/x509_internal_test.c @@ -58,22 +58,92 @@ static IP_TESTDATA a2i_ipaddress_tests[] = { {"127.0.0.1", "\x7f\x00\x00\x01", 4}, {"1.2.3.4", "\x01\x02\x03\x04", 4}, {"1.2.3.255", "\x01\x02\x03\xff", 4}, - {"1.2.3", NULL, 0}, - {"1.2.3 .4", NULL, 0}, + {"255.255.255.255", "\xff\xff\xff\xff", 4}, + {"::", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16}, {"::1", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16}, + {"::01", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16}, + {"::0001", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16}, + {"ffff::", "\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16}, + {"ffff::1", "\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16}, + {"1::2", "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", 16}, {"1:1:1:1:1:1:1:1", "\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01", 16}, {"2001:db8::ff00:42:8329", "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00\x42\x83\x29", 16}, + {"::1.2.3.4", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04", 16}, + {"ffff:ffff:ffff:ffff:ffff:ffff:1.2.3.4", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x02\x03\x04", 16}, + {"1:1:1:1:1:1:1:1.test", NULL, 0}, {":::1", NULL, 0}, {"2001::123g", NULL, 0}, - {"example.test", NULL, 0}, + /* Too few IPv4 components. */ + {"1", NULL, 0 }, + {"1.", NULL, 0 }, + {"1.2", NULL, 0 }, + {"1.2.", NULL, 0 }, + {"1.2.3", NULL, 0 }, + {"1.2.3.", NULL, 0 }, + + /* Invalid embedded IPv4 address. */ + {"::1.2.3", NULL, 0 }, + + /* IPv4 literals take the place of two IPv6 components. */ + {"1:2:3:4:5:6:7:1.2.3.4", NULL, 0 }, + + /* '::' should have fewer than 16 components or it is redundant. */ + {"1:2:3:4:5:6:7::8", NULL, 0 }, + + /* Embedded IPv4 addresses must be at the end. */ + {"::1.2.3.4:1", NULL, 0 }, + + /* Too many components. */ + {"1.2.3.4.5", NULL, 0 }, + {"1:2:3:4:5:6:7:8:9", NULL, 0 }, + {"1:2:3:4:5::6:7:8:9", NULL, 0 }, + + /* Stray whitespace or other invalid characters. */ + {"1.2.3.4 ", NULL, 0 }, + {"1.2.3 .4", NULL, 0 }, + {"1.2.3. 4", NULL, 0 }, + {" 1.2.3.4", NULL, 0 }, + {"1.2.3.4.", NULL, 0 }, + {"1.2.3.+4", NULL, 0 }, + {"1.2.3.-4", NULL, 0 }, + {"1.2.3.4.example.test", NULL, 0 }, + {"::1 ", NULL, 0 }, + {" ::1", NULL, 0 }, + {":: 1", NULL, 0 }, + {": :1", NULL, 0 }, + {"1.2.3.nope", NULL, 0 }, + {"::nope", NULL, 0 }, + + /* Components too large. */ + {"1.2.3.256", NULL, 0}, /* Overflows when adding */ + {"1.2.3.260", NULL, 0}, /* Overflows when multiplying by 10 */ + {"1.2.3.999999999999999999999999999999999999999999", NULL, 0 }, + {"::fffff", NULL, 0 }, + + /* Although not an overflow, more than four hex digits is an error. */ + {"::00000", NULL, 0 }, + + /* Too many colons. */ + {":::", NULL, 0 }, + {"1:::", NULL, 0 }, + {":::2", NULL, 0 }, + {"1:::2", NULL, 0 }, + + /* Only one group of zeros may be elided. */ + {"1::2::3", NULL, 0 }, + + /* We only support decimal. */ + {"1.2.3.01", NULL, 0 }, + {"1.2.3.0x1", NULL, 0 }, + + /* Random garbage. */ + {"example.test", NULL, 0 }, {"", NULL, 0}, - - {"1.2.3.4 ", "\x01\x02\x03\x04", 4}, - {" 1.2.3.4", "\x01\x02\x03\x04", 4}, - {" 1.2.3.4 ", "\x01\x02\x03\x04", 4}, + {" 1.2.3.4", NULL, 0}, + {" 1.2.3.4 ", NULL, 0}, {"1.2.3.4.example.test", NULL, 0}, }; From d38f62ea118170fc40e10f6f95b180cccbaa7581 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 19 Jun 2024 17:40:21 +0200 Subject: [PATCH 045/138] Allow calling OPENSSL_INIT_free() with NULL argument Reviewed-by: Neil Horman Reviewed-by: Matt Caswell Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24681) --- crypto/conf/conf_lib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crypto/conf/conf_lib.c b/crypto/conf/conf_lib.c index 99e9f8c987b34..24cf40449788c 100644 --- a/crypto/conf/conf_lib.c +++ b/crypto/conf/conf_lib.c @@ -476,6 +476,9 @@ int OPENSSL_INIT_set_config_appname(OPENSSL_INIT_SETTINGS *settings, void OPENSSL_INIT_free(OPENSSL_INIT_SETTINGS *settings) { + if (settings == NULL) + return; + free(settings->filename); free(settings->appname); free(settings); From 42a8ef844e5fca55abb608beb62695abe80c6b6d Mon Sep 17 00:00:00 2001 From: Karol Brzuskiewicz Date: Mon, 10 Jun 2024 01:48:31 -0700 Subject: [PATCH 046/138] Fix usage of deallocated EVP_RAND_CTX after execution of FIPS on-demand self tests Once RNG is used, triggering FIPS on-demand self tests (via OSSL_PROVIDER_self_test() API) crashes the application. This happens because the RNG context is stored before self tests, and restored after their execution. In the meantime - before context restoration - RAND_set0_private() function is called, which decrements the stored RNG context reference counter and frees it. To resolve the issue, the stored RNG context refcount has been incremented via the EVP_RAND_CTX_up_ref() API to avoid its deallocation during the RNG context switch performed by the self test function. The provider_status_test test has been updated to reproduce the issue as a regression test. Signed-off-by: Karol Brzuskiewicz Reviewed-by: Shane Lontis Reviewed-by: Tom Cosgrove Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24599) --- providers/fips/self_test_kats.c | 4 ++++ test/provider_status_test.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index f13c41abd671a..8baa8cc6b1d3d 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -858,8 +858,12 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) EVP_RAND_CTX *saved_rand = ossl_rand_get0_private_noncreating(libctx); int ret = 1; + if (saved_rand != NULL && !EVP_RAND_CTX_up_ref(saved_rand)) + return 0; if (!setup_main_random(libctx) || !RAND_set0_private(libctx, main_rand)) { + /* Decrement saved_rand reference counter */ + EVP_RAND_CTX_free(saved_rand); EVP_RAND_CTX_free(main_rand); return 0; } diff --git a/test/provider_status_test.c b/test/provider_status_test.c index 551277c8e0b26..362ae3803a7ca 100644 --- a/test/provider_status_test.c +++ b/test/provider_status_test.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "testutil.h" typedef enum OPTION_choice { @@ -147,6 +148,8 @@ static int test_provider_status(void) OSSL_PROVIDER *prov = NULL; OSSL_PARAM params[2]; EVP_MD *fetch = NULL; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = NULL; if (!TEST_ptr(prov = OSSL_PROVIDER_load(libctx, provider_name))) goto err; @@ -163,6 +166,16 @@ static int test_provider_status(void) goto err; EVP_MD_free(fetch); fetch = NULL; + /* Use RNG before triggering on-demand self tests */ + if (!TEST_ptr((pctx = EVP_PKEY_CTX_new_from_name(libctx, "RSA", NULL))) + || !TEST_int_gt(EVP_PKEY_keygen_init(pctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048), 0) + || !TEST_int_gt(EVP_PKEY_keygen(pctx, &pkey), 0)) + goto err; + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(pctx); + pkey = NULL; + pctx = NULL; /* Test that the provider self test is ok */ self_test_args.count = 0; From 57b83edc46926662491d63666231ba7ddc954a38 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Sat, 22 Jun 2024 09:14:25 +0200 Subject: [PATCH 047/138] bio_ssl.c: Do not call SSL_shutdown if not inited Fixes #4545 If free is called for an SSL BIO that is in initialization phase, the `SSL_shutdown` call is omitted. Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24705) --- ssl/bio_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/bio_ssl.c b/ssl/bio_ssl.c index aabd047fe580a..ac65a3988bd10 100644 --- a/ssl/bio_ssl.c +++ b/ssl/bio_ssl.c @@ -79,7 +79,7 @@ static int ssl_free(BIO *a) return 0; bs = BIO_get_data(a); if (BIO_get_shutdown(a)) { - if (bs->ssl != NULL) + if (bs->ssl != NULL && !SSL_in_init(bs->ssl)) SSL_shutdown(bs->ssl); if (BIO_get_init(a)) SSL_free(bs->ssl); From a9064366e8dcff56c722d0c8f1306d84d6c3f255 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Mon, 24 Jun 2024 13:46:16 +0200 Subject: [PATCH 048/138] Fix memory leak in x509_req_test Running the x509_req_test with address sanitizer shows a memory leak: ==186455==ERROR: LeakSanitizer: detected memory leaks Direct leak of 53 byte(s) in 1 object(s) allocated from: #0 0x3ffad5f47af in malloc (/lib64/libasan.so.8+0xf47af) (BuildId: 93b3d2536d76f772a95880d76c746c150daabbee) #1 0x3ffac4214fb in CRYPTO_malloc crypto/mem.c:202 #2 0x3ffac421759 in CRYPTO_zalloc crypto/mem.c:222 #3 0x100e58f in test_mk_file_path test/testutil/driver.c:450 #4 0x1004671 in test_x509_req_detect_invalid_version test/x509_req_test.c:32 #5 0x100d247 in run_tests test/testutil/driver.c:342 #6 0x10042e3 in main test/testutil/main.c:31 #7 0x3ffaad34a5b in __libc_start_call_main (/lib64/libc.so.6+0x34a5b) (BuildId: 461b58df774538594b6173825bed67a9247a014d) #8 0x3ffaad34b5d in __libc_start_main@GLIBC_2.2 (/lib64/libc.so.6+0x34b5d) (BuildId: 461b58df774538594b6173825bed67a9247a014d) #9 0x1004569 (/root/openssl/test/x509_req_test+0x1004569) (BuildId: ab6bce0e531df1e3626a8f506d07f6ad7c7c6d57) SUMMARY: AddressSanitizer: 53 byte(s) leaked in 1 allocation(s). The certFilePath that is obtained via test_mk_file_path() must be freed when no longer used. While at it, make the certFilePath variable a local variable, there is no need to have this a global static variable. Fixes: https://github.com/openssl/openssl/commit/7d2c0a4b1feb152ee1190dfedc65dfd1c928f9e5 Signed-off-by: Ingo Franzki Reviewed-by: Dmitry Belyavskiy Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24715) --- test/x509_req_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/x509_req_test.c b/test/x509_req_test.c index 742b62836b968..b37fd0599adab 100644 --- a/test/x509_req_test.c +++ b/test/x509_req_test.c @@ -13,7 +13,6 @@ #include "testutil.h" static char *certsDir = NULL; -static char *certFilePath = NULL; /* * Test for the missing X509 version check discussed in issue #5738 and @@ -24,6 +23,7 @@ static char *certFilePath = NULL; */ static int test_x509_req_detect_invalid_version(void) { + char *certFilePath; BIO *bio = NULL; EVP_PKEY *pkey = NULL; X509_REQ *req = NULL; @@ -49,6 +49,7 @@ static int test_x509_req_detect_invalid_version(void) EVP_PKEY_free(pkey); X509_REQ_free(req); BIO_free(bio); + OPENSSL_free(certFilePath); return ret; } From 6e0fd246e7a6e51f92b2ef3520bfc4414b7773c0 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 20 Jun 2024 14:30:16 +0200 Subject: [PATCH 049/138] Give util/mkinstallvars.pl more fine grained control over var dependencies Essentially, we try to do what GNU does. 'prefix' is used to define the defaults for 'exec_prefix' and 'libdir', and these are then used to define further directory values. util/mkinstallvars.pl is changed to reflect that to the best of our ability. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24687) --- exporters/build.info | 2 +- util/mkinstallvars.pl | 133 ++++++++++++++++++++++++++---------------- 2 files changed, 85 insertions(+), 50 deletions(-) diff --git a/exporters/build.info b/exporters/build.info index 86acf2df9467c..9241dc9b0a658 100644 --- a/exporters/build.info +++ b/exporters/build.info @@ -19,7 +19,7 @@ DEPEND[openssl.pc]=libcrypto.pc libssl.pc DEPEND[""]=openssl.pc GENERATE[../installdata.pm]=../util/mkinstallvars.pl \ - "PREFIX=$(INSTALLTOP)" BINDIR=bin "LIBDIR=$(LIBDIR)" \ + "PREFIX=$(INSTALLTOP)" BINDIR=bin "LIBDIR=$(LIBDIR)" "libdir=$(libdir)" \ INCLUDEDIR=include APPLINKDIR=include/openssl \ "ENGINESDIR=$(ENGINESDIR)" "MODULESDIR=$(MODULESDIR)" \ "PKGCONFIGDIR=$(PKGCONFIGDIR)" "CMAKECONFIGDIR=$(CMAKECONFIGDIR)" \ diff --git a/util/mkinstallvars.pl b/util/mkinstallvars.pl index 59a432d28c601..5fadb708e1b77 100644 --- a/util/mkinstallvars.pl +++ b/util/mkinstallvars.pl @@ -11,13 +11,25 @@ # The result is a Perl module creating the package OpenSSL::safe::installdata. use File::Spec; +use List::Util qw(pairs); # These are expected to be set up as absolute directories -my @absolutes = qw(PREFIX); +my @absolutes = qw(PREFIX libdir); # These may be absolute directories, and if not, they are expected to be set up -# as subdirectories to PREFIX -my @subdirs = qw(BINDIR LIBDIR INCLUDEDIR APPLINKDIR ENGINESDIR MODULESDIR - PKGCONFIGDIR CMAKECONFIGDIR); +# as subdirectories to PREFIX or LIBDIR. The order of the pairs is important, +# since the LIBDIR subdirectories depend on the calculation of LIBDIR from +# PREFIX. +my @subdirs = pairs (PREFIX => [ qw(BINDIR LIBDIR INCLUDEDIR APPLINKDIR) ], + LIBDIR => [ qw(ENGINESDIR MODULESDIR PKGCONFIGDIR + CMAKECONFIGDIR) ]); +# For completeness, other expected variables +my @others = qw(VERSION LDLIBS); + +my %all = ( ); +foreach (@absolutes) { $all{$_} = 1 } +foreach (@subdirs) { foreach (@{$_->[1]}) { $all{$_} = 1 } } +foreach (@others) { $all{$_} = 1 } +print STDERR "DEBUG: all keys: ", join(", ", sort keys %all), "\n"; my %keys = (); foreach (@ARGV) { @@ -26,29 +38,47 @@ $ENV{$k} = $v; } -foreach my $k (sort keys %keys) { - my $v = $ENV{$k}; - $v = File::Spec->rel2abs($v) if $v && grep { $k eq $_ } @absolutes; - $ENV{$k} = $v; +# warn if there are missing values, and also if there are unexpected values +foreach my $k (sort keys %all) { + warn "No value given for $k\n" unless $keys{$k}; } foreach my $k (sort keys %keys) { + warn "Unknown variable $k\n" unless $all{$k}; +} + +# This shouldn't be needed, but just in case we get relative paths that +# should be absolute, make sure they actually are. +foreach my $k (@absolutes) { my $v = $ENV{$k} || '.'; + print STDERR "DEBUG: $k = $v => "; + $v = File::Spec->rel2abs($v) if $v; + $ENV{$k} = $v; + print STDERR "$k = $ENV{$k}\n"; +} - # Absolute paths for the subdir variables are computed. This provides - # the usual form of values for names that have become norm, known as GNU - # installation paths. - # For the benefit of those that need it, the subdirectories are preserved - # as they are, using the same variable names, suffixed with '_REL', if they - # are indeed subdirectories. - if (grep { $k eq $_ } @subdirs) { +# Absolute paths for the subdir variables are computed. This provides +# the usual form of values for names that have become norm, known as GNU +# installation paths. +# For the benefit of those that need it, the subdirectories are preserved +# as they are, using the same variable names, suffixed with '_REL_{var}', +# if they are indeed subdirectories. The '{var}' part of the name tells +# which other variable value they are relative to. +foreach my $pair (@subdirs) { + my ($var, $subdir_vars) = @$pair; + foreach my $k (@$subdir_vars) { + my $v = $ENV{$k} || '.'; + print STDERR "DEBUG: $k = $v => "; if (File::Spec->file_name_is_absolute($v)) { - $ENV{"${k}_REL"} = File::Spec->abs2rel($v, $ENV{PREFIX}); + my $kr = "${k}_REL_${var}"; + $ENV{$kr} = File::Spec->abs2rel($v, $ENV{$var}); + print STDERR "$kr = $ENV{$kr}\n"; } else { - $ENV{"${k}_REL"} = $v; - $v = File::Spec->rel2abs($v, $ENV{PREFIX}); + my $kr = "${k}_REL_${var}"; + $ENV{$kr} = $v; + $ENV{$k} = File::Spec->rel2abs($v, $ENV{$var}); + print STDERR "$k = $ENV{$k} , $kr = $v\n"; } } - $ENV{$k} = $v; } print <<_____; @@ -58,36 +88,41 @@ package OpenSSL::safe::installdata; use warnings; use Exporter; our \@ISA = qw(Exporter); -our \@EXPORT = qw(\$PREFIX - \$BINDIR \$BINDIR_REL - \$LIBDIR \$LIBDIR_REL - \$INCLUDEDIR \$INCLUDEDIR_REL - \$APPLINKDIR \$APPLINKDIR_REL - \$ENGINESDIR \$ENGINESDIR_REL - \$MODULESDIR \$MODULESDIR_REL - \$PKGCONFIGDIR \$PKGCONFIGDIR_REL - \$CMAKECONFIGDIR \$CMAKECONFIGDIR_REL - \$VERSION \@LDLIBS); - -our \$PREFIX = '$ENV{PREFIX}'; -our \$BINDIR = '$ENV{BINDIR}'; -our \$BINDIR_REL = '$ENV{BINDIR_REL}'; -our \$LIBDIR = '$ENV{LIBDIR}'; -our \$LIBDIR_REL = '$ENV{LIBDIR_REL}'; -our \$INCLUDEDIR = '$ENV{INCLUDEDIR}'; -our \$INCLUDEDIR_REL = '$ENV{INCLUDEDIR_REL}'; -our \$APPLINKDIR = '$ENV{APPLINKDIR}'; -our \$APPLINKDIR_REL = '$ENV{APPLINKDIR_REL}'; -our \$ENGINESDIR = '$ENV{ENGINESDIR}'; -our \$ENGINESDIR_REL = '$ENV{ENGINESDIR_REL}'; -our \$MODULESDIR = '$ENV{MODULESDIR}'; -our \$MODULESDIR_REL = '$ENV{MODULESDIR_REL}'; -our \$PKGCONFIGDIR = '$ENV{PKGCONFIGDIR}'; -our \$PKGCONFIGDIR_REL = '$ENV{PKGCONFIGDIR_REL}'; -our \$CMAKECONFIGDIR = '$ENV{CMAKECONFIGDIR}'; -our \$CMAKECONFIGDIR_REL = '$ENV{CMAKECONFIGDIR_REL}'; -our \$VERSION = '$ENV{VERSION}'; -our \@LDLIBS = +our \@EXPORT = qw( +_____ + +foreach my $k (@absolutes) { + print " \$$k\n"; +} +foreach my $pair (@subdirs) { + my ($var, $subdir_vars) = @$pair; + foreach my $k (@$subdir_vars) { + my $k2 = "${k}_REL_${var}"; + print " \$$k \$$k2\n"; + } +} + +print <<_____; + \$VERSION \@LDLIBS +); + +_____ + +foreach my $k (@absolutes) { + print "our \$$k" . ' ' x (27 - length($k)) . "= '$ENV{$k}';\n"; +} +foreach my $pair (@subdirs) { + my ($var, $subdir_vars) = @$pair; + foreach my $k (@$subdir_vars) { + my $k2 = "${k}_REL_${var}"; + print "our \$$k" . ' ' x (27 - length($k)) . "= '$ENV{$k}';\n"; + print "our \$$k2" . ' ' x (27 - length($k2)) . "= '$ENV{$k2}';\n"; + } +} + +print <<_____; +our \$VERSION = '$ENV{VERSION}'; +our \@LDLIBS = # Unix and Windows use space separation, VMS uses comma separation split(/ +| *, */, '$ENV{LDLIBS}'); From 30dc37d798a0428fd477d3763086e7e97b3d596f Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 20 Jun 2024 14:33:15 +0200 Subject: [PATCH 050/138] Adapt all the exporter files to the new vars from util/mkinstallvars.pl With this, the pkg-config files take better advantage of relative directory values. Fixes #24298 Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24687) --- exporters/cmake/OpenSSLConfig.cmake.in | 7 ++++--- exporters/pkg-config/libcrypto.pc.in | 12 ++++++++---- exporters/pkg-config/libssl.pc.in | 8 ++++++-- exporters/pkg-config/openssl.pc.in | 8 ++++++-- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/exporters/cmake/OpenSSLConfig.cmake.in b/exporters/cmake/OpenSSLConfig.cmake.in index 2d2321931de1d..06f796158b2fa 100644 --- a/exporters/cmake/OpenSSLConfig.cmake.in +++ b/exporters/cmake/OpenSSLConfig.cmake.in @@ -89,9 +89,10 @@ unset(_ossl_undefined_targets) # Set up the import path, so all other import paths are made relative this file get_filename_component(_ossl_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH) {- - # For each component in $OpenSSL::safe::installdata::CMAKECONFIGDIR_REL, have CMake - # out the parent directory. - my $d = unixify($OpenSSL::safe::installdata::CMAKECONFIGDIR_REL); + # For each component in $OpenSSL::safe::installdata::CMAKECONFIGDIR relative to + # $OpenSSL::safe::installdata::PREFIX, have CMake figure out the parent directory. + my $d = join('/', unixify($OpenSSL::safe::installdata::LIBDIR_REL_PREFIX), + unixify($OpenSSL::safe::installdata::CMAKECONFIGDIR_REL_LIBDIR)); $OUT = ''; $OUT .= 'get_filename_component(_ossl_prefix "${_ossl_prefix}" PATH)' . "\n" foreach (split '/', $d); diff --git a/exporters/pkg-config/libcrypto.pc.in b/exporters/pkg-config/libcrypto.pc.in index 14ed339f3c3a0..fbc8ea4c79b06 100644 --- a/exporters/pkg-config/libcrypto.pc.in +++ b/exporters/pkg-config/libcrypto.pc.in @@ -1,7 +1,11 @@ -libdir={- $OpenSSL::safe::installdata::LIBDIR -} -includedir={- $OpenSSL::safe::installdata::INCLUDEDIR -} -enginesdir={- $OpenSSL::safe::installdata::ENGINESDIR -} -modulesdir={- $OpenSSL::safe::installdata::MODULESDIR -} +prefix={- $OpenSSL::safe::installdata::PREFIX -} +exec_prefix=${prefix} +libdir={- $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + ? '${exec_prefix}/' . $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + : $OpenSSL::safe::installdata::libdir -} +includedir=${prefix}/{- $OpenSSL::safe::installdata::INCLUDEDIR_REL_PREFIX -} +enginesdir=${libdir}/{- $OpenSSL::safe::installdata::ENGINESDIR_REL_LIBDIR -} +modulesdir=${libdir}/{- $OpenSSL::safe::installdata::MODULESDIR_REL_LIBDIR -} Name: OpenSSL-libcrypto Description: OpenSSL cryptography library diff --git a/exporters/pkg-config/libssl.pc.in b/exporters/pkg-config/libssl.pc.in index a7828b3cc6a49..963538807bb2b 100644 --- a/exporters/pkg-config/libssl.pc.in +++ b/exporters/pkg-config/libssl.pc.in @@ -1,5 +1,9 @@ -libdir={- $OpenSSL::safe::installdata::LIBDIR -} -includedir={- $OpenSSL::safe::installdata::INCLUDEDIR -} +prefix={- $OpenSSL::safe::installdata::PREFIX -} +exec_prefix=${prefix} +libdir={- $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + ? '${exec_prefix}/' . $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + : $OpenSSL::safe::installdata::libdir -} +includedir=${prefix}/{- $OpenSSL::safe::installdata::INCLUDEDIR_REL_PREFIX -} Name: OpenSSL-libssl Description: Secure Sockets Layer and cryptography libraries diff --git a/exporters/pkg-config/openssl.pc.in b/exporters/pkg-config/openssl.pc.in index dbb77aa39add2..225bef9e2384d 100644 --- a/exporters/pkg-config/openssl.pc.in +++ b/exporters/pkg-config/openssl.pc.in @@ -1,5 +1,9 @@ -libdir={- $OpenSSL::safe::installdata::LIBDIR -} -includedir={- $OpenSSL::safe::installdata::INCLUDEDIR -} +prefix={- $OpenSSL::safe::installdata::PREFIX -} +exec_prefix=${prefix} +libdir={- $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + ? '${exec_prefix}/' . $OpenSSL::safe::installdata::LIBDIR_REL_PREFIX + : $OpenSSL::safe::installdata::libdir -} +includedir=${prefix}/{- $OpenSSL::safe::installdata::INCLUDEDIR_REL_PREFIX -} Name: OpenSSL Description: Secure Sockets Layer and cryptography libraries and tools From 55c1458303c0fef88e4b2b35a090e9145f3e07eb Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 24 Jun 2024 11:25:12 +0200 Subject: [PATCH 051/138] evp_pkey_ctx_setget_params_to_ctrl(): Always properly set ctx.action_type Fixes #24698 Some applicable translations are bidirectional so they have NONE action_type. However we need to set the real action_type in the ctx. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24709) --- crypto/evp/ctrl_params_translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crypto/evp/ctrl_params_translate.c b/crypto/evp/ctrl_params_translate.c index 54e589054c603..de06348a33781 100644 --- a/crypto/evp/ctrl_params_translate.c +++ b/crypto/evp/ctrl_params_translate.c @@ -2845,7 +2845,7 @@ static int evp_pkey_ctx_setget_params_to_ctrl(EVP_PKEY_CTX *pctx, fixup_args_fn *fixup = default_fixup_args; int ret; - tmpl.action_type = action_type; + ctx.action_type = tmpl.action_type = action_type; tmpl.keytype1 = tmpl.keytype2 = keytype; tmpl.optype = optype; tmpl.param_key = params->key; @@ -2854,7 +2854,6 @@ static int evp_pkey_ctx_setget_params_to_ctrl(EVP_PKEY_CTX *pctx, if (translation != NULL) { if (translation->fixup_args != NULL) fixup = translation->fixup_args; - ctx.action_type = translation->action_type; ctx.ctrl_cmd = translation->ctrl_num; } ctx.pctx = pctx; From 0169bbbd1ce94ea703d5561b30f0e41bb54520a6 Mon Sep 17 00:00:00 2001 From: Kelvin Lee Date: Mon, 24 Jun 2024 21:09:03 +1000 Subject: [PATCH 052/138] MASM: Need to strip arguments after .pdata or .xdata For MASM, .section .pdata,"r" got translated to: .pdata,"r" SEGMENT READONLY ALIGN(4) that breaks ml64. Previous version of x86_64-xlate.pl did strip that ',"r"'. CLA: trivial Reviewed-by: Matt Caswell Reviewed-by: Sasa Nedvedicky Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24714) --- crypto/perlasm/x86_64-xlate.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl index 3befbde019418..f9935dd9aa90d 100755 --- a/crypto/perlasm/x86_64-xlate.pl +++ b/crypto/perlasm/x86_64-xlate.pl @@ -1012,6 +1012,7 @@ $align = $$line; $align =~ s/(.*)(align\s*=\s*\d+$)/$2/; $$line =~ s/(.*)(\s+align\s*=\s*\d+$)/$1/; + $$line =~ s/,.*//; $$line = ".CRT\$XCU" if ($$line eq ".init"); $$line = ".rdata" if ($$line eq ".rodata"); if ($nasm) { From 2b735fe2195938ea6cafbef37c8bcf8a33b04c4b Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Mon, 17 Jun 2024 18:22:08 +0000 Subject: [PATCH 053/138] feat: add acceptablePrivilegePolicies and acceptableCertPolicies exts Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24663) --- crypto/x509/ext_dat.h | 2 ++ crypto/x509/standard_exts.h | 2 ++ crypto/x509/v3_extku.c | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index f3ad5afbf054e..3c59f32baabf6 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -36,3 +36,5 @@ extern const X509V3_EXT_METHOD ossl_v3_holder_name_constraints; extern const X509V3_EXT_METHOD ossl_v3_delegated_name_constraints; extern const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs; extern const X509V3_EXT_METHOD ossl_v3_associated_info; +extern const X509V3_EXT_METHOD ossl_v3_acc_cert_policies; +extern const X509V3_EXT_METHOD ossl_v3_acc_priv_policies; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index 655dd21e1e7aa..879226eabebd0 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -77,6 +77,8 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_ext_admission, &ossl_v3_delegated_name_constraints, &ossl_v3_soa_identifier, + &ossl_v3_acc_cert_policies, + &ossl_v3_acc_priv_policies, &ossl_v3_indirect_issuer, &ossl_v3_no_assertion, &ossl_v3_single_use, diff --git a/crypto/x509/v3_extku.c b/crypto/x509/v3_extku.c index 22c951e251c2a..6053d5e2cb999 100644 --- a/crypto/x509/v3_extku.c +++ b/crypto/x509/v3_extku.c @@ -44,6 +44,30 @@ const X509V3_EXT_METHOD ossl_v3_ocsp_accresp = { NULL }; +/* Acceptable Certificate Policies also is a SEQUENCE OF OBJECT */ +const X509V3_EXT_METHOD ossl_v3_acc_cert_policies = { + NID_acceptable_cert_policies, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0, 0, 0, 0, + 0, 0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0, 0, + NULL +}; + +/* Acceptable Privilege Policies also is a SEQUENCE OF OBJECT */ +const X509V3_EXT_METHOD ossl_v3_acc_priv_policies = { + NID_acceptable_privilege_policies, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0, 0, 0, 0, + 0, 0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0, 0, + NULL +}; + ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT) ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE) From b76a6c26a254b4cc428275fc0ced56759dd5088a Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Mon, 24 Jun 2024 20:23:23 +0000 Subject: [PATCH 054/138] test: add tests for acceptable policies exts Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24663) --- test/certs/ext-acceptableCertPolicies.pem | 11 ++++++++ .../certs/ext-acceptablePrivilegePolicies.pem | 11 ++++++++ test/recipes/25-test_x509.t | 26 ++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 test/certs/ext-acceptableCertPolicies.pem create mode 100644 test/certs/ext-acceptablePrivilegePolicies.pem diff --git a/test/certs/ext-acceptableCertPolicies.pem b/test/certs/ext-acceptableCertPolicies.pem new file mode 100644 index 0000000000000..2930235887786 --- /dev/null +++ b/test/certs/ext-acceptableCertPolicies.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkDCCAXygAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMxMDIy +MDM4WhgPMjAyMTA4MzEwMjIwMzhaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABoxcwFTATBgNVHTQEDDAKBgNVBAsG +A1UEDTALBgkqhkiG9w0BAQUDAQA= +-----END CERTIFICATE----- diff --git a/test/certs/ext-acceptablePrivilegePolicies.pem b/test/certs/ext-acceptablePrivilegePolicies.pem new file mode 100644 index 0000000000000..804086d83aeb5 --- /dev/null +++ b/test/certs/ext-acceptablePrivilegePolicies.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkDCCAXygAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMwMTI1 +NjEyWhgPMjAyMTA4MzAxMjU2MTJaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABoxcwFTATBgNVHTkEDDAKBgNVBAMG +A1UECjALBgkqhkiG9w0BAQUDAQA= +-----END CERTIFICATE----- diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 579f90278d160..22379ec5f9fd3 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 82; +plan tests => 88; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -245,6 +245,30 @@ cert_contains($ass_info_cert, "localityName", 1, 'X509v3 Associated Information'); +my $acc_cert_pol = srctop_file(@certs, "ext-acceptableCertPolicies.pem"); +cert_contains($acc_cert_pol, + "X509v3 Acceptable Certification Policies", + 1, 'X509v3 Acceptable Certification Policies'); +# Yes, I know these OIDs make no sense in a policies extension. It's just a test. +cert_contains($acc_cert_pol, + "organizationalUnitName", + 1, 'X509v3 Acceptable Certification Policies'); +cert_contains($acc_cert_pol, + "description", + 1, 'X509v3 Acceptable Certification Policies'); + +my $acc_priv_pol = srctop_file(@certs, "ext-acceptablePrivilegePolicies.pem"); +cert_contains($acc_priv_pol, + "X509v3 Acceptable Privilege Policies", + 1, 'X509v3 Acceptable Privilege Policies'); +# Yes, I know these OIDs make no sense in a policies extension. It's just a test. +cert_contains($acc_priv_pol, + "commonName", + 1, 'X509v3 Acceptable Certification Policies'); +cert_contains($acc_priv_pol, + "organizationName", + 1, 'X509v3 Acceptable Certification Policies'); + sub test_errors { # actually tests diagnostics of OSSL_STORE my ($expected, $cert, @opts) = @_; my $infile = srctop_file(@certs, $cert); From 2ebbe2d7ca8551c4cb5fbb391ab9af411708090e Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 31 May 2024 11:14:33 +0100 Subject: [PATCH 055/138] Fix SSL_select_next_proto Ensure that the provided client list is non-NULL and starts with a valid entry. When called from the ALPN callback the client list should already have been validated by OpenSSL so this should not cause a problem. When called from the NPN callback the client list is locally configured and will not have already been validated. Therefore SSL_select_next_proto should not assume that it is correctly formatted. We implement stricter checking of the client protocol list. We also do the same for the server list while we are about it. CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- ssl/ssl_lib.c | 63 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 37a307b9927c3..589ed2c64d4f9 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -3535,37 +3535,54 @@ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, unsigned int server_len, const unsigned char *client, unsigned int client_len) { - unsigned int i, j; - const unsigned char *result; - int status = OPENSSL_NPN_UNSUPPORTED; + PACKET cpkt, csubpkt, spkt, ssubpkt; + + if (!PACKET_buf_init(&cpkt, client, client_len) + || !PACKET_get_length_prefixed_1(&cpkt, &csubpkt) + || PACKET_remaining(&csubpkt) == 0) { + *out = NULL; + *outlen = 0; + return OPENSSL_NPN_NO_OVERLAP; + } + + /* + * Set the default opportunistic protocol. Will be overwritten if we find + * a match. + */ + *out = (unsigned char *)PACKET_data(&csubpkt); + *outlen = (unsigned char)PACKET_remaining(&csubpkt); /* * For each protocol in server preference order, see if we support it. */ - for (i = 0; i < server_len;) { - for (j = 0; j < client_len;) { - if (server[i] == client[j] && - memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) { - /* We found a match */ - result = &server[i]; - status = OPENSSL_NPN_NEGOTIATED; - goto found; + if (PACKET_buf_init(&spkt, server, server_len)) { + while (PACKET_get_length_prefixed_1(&spkt, &ssubpkt)) { + if (PACKET_remaining(&ssubpkt) == 0) + continue; /* Invalid - ignore it */ + if (PACKET_buf_init(&cpkt, client, client_len)) { + while (PACKET_get_length_prefixed_1(&cpkt, &csubpkt)) { + if (PACKET_equal(&csubpkt, PACKET_data(&ssubpkt), + PACKET_remaining(&ssubpkt))) { + /* We found a match */ + *out = (unsigned char *)PACKET_data(&ssubpkt); + *outlen = (unsigned char)PACKET_remaining(&ssubpkt); + return OPENSSL_NPN_NEGOTIATED; + } + } + /* Ignore spurious trailing bytes in the client list */ + } else { + /* This should never happen */ + return OPENSSL_NPN_NO_OVERLAP; } - j += client[j]; - j++; } - i += server[i]; - i++; + /* Ignore spurious trailing bytes in the server list */ } - /* There's no overlap between our protocols and the server's list. */ - result = client; - status = OPENSSL_NPN_NO_OVERLAP; - - found: - *out = (unsigned char *)result + 1; - *outlen = result[0]; - return status; + /* + * There's no overlap between our protocols and the server's list. We use + * the default opportunistic protocol selected earlier + */ + return OPENSSL_NPN_NO_OVERLAP; } #ifndef OPENSSL_NO_NEXTPROTONEG From c6e1ea223510bb7104bf0c41c0c45eda5a16b718 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 31 May 2024 11:18:27 +0100 Subject: [PATCH 056/138] More correctly handle a selected_len of 0 when processing NPN In the case where the NPN callback returns with SSL_TLEXT_ERR_OK, but the selected_len is 0 we should fail. Previously this would fail with an internal_error alert because calling OPENSSL_malloc(selected_len) will return NULL when selected_len is 0. We make this error detection more explicit and return a handshake failure alert. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- ssl/statem/extensions_clnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index ef51c61ef3c99..f24db5f570d2c 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1598,8 +1598,8 @@ int tls_parse_stoc_npn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, if (sctx->ext.npn_select_cb(SSL_CONNECTION_GET_SSL(s), &selected, &selected_len, PACKET_data(pkt), PACKET_remaining(pkt), - sctx->ext.npn_select_cb_arg) != - SSL_TLSEXT_ERR_OK) { + sctx->ext.npn_select_cb_arg) != SSL_TLSEXT_ERR_OK + || selected_len == 0) { SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION); return 0; } From fc8ff75814767d6c55ea78d05adc72cd346d0f0a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 31 May 2024 11:22:13 +0100 Subject: [PATCH 057/138] Use correctly formatted ALPN data in tserver The QUIC test server was using incorrectly formatted ALPN data. With the previous implementation of SSL_select_next_proto this went unnoticed. With the new stricter implemenation it was failing. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- ssl/quic/quic_tserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index b9de60aea15fc..4f30eb14cec8d 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -63,7 +63,7 @@ static int alpn_select_cb(SSL *ssl, const unsigned char **out, if (srv->args.alpn == NULL) { alpn = alpndeflt; - alpnlen = sizeof(alpn); + alpnlen = sizeof(alpndeflt); } else { alpn = srv->args.alpn; alpnlen = srv->args.alpnlen; From a210f580f450bbd08fac85f06e27107b8c580f9b Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 31 May 2024 11:46:38 +0100 Subject: [PATCH 058/138] Clarify the SSL_select_next_proto() documentation We clarify the input preconditions and the expected behaviour in the event of no overlap. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- doc/man3/SSL_CTX_set_alpn_select_cb.pod | 26 +++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/doc/man3/SSL_CTX_set_alpn_select_cb.pod b/doc/man3/SSL_CTX_set_alpn_select_cb.pod index 05fee2fbecbce..79e1a252f6bf3 100644 --- a/doc/man3/SSL_CTX_set_alpn_select_cb.pod +++ b/doc/man3/SSL_CTX_set_alpn_select_cb.pod @@ -52,7 +52,8 @@ SSL_select_next_proto, SSL_get0_alpn_selected, SSL_get0_next_proto_negotiated SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() are used by the client to set the list of protocols available to be negotiated. The B must be in protocol-list format, described below. The length of B is specified in -B. +B. Setting B to 0 clears any existing list of ALPN +protocols and no ALPN extension will be sent to the server. SSL_CTX_set_alpn_select_cb() sets the application callback B used by a server to select which protocol to use for the incoming connection. When B @@ -73,9 +74,16 @@ B and B, B must be in the protocol-list format described below. The first item in the B, B list that matches an item in the B, B list is selected, and returned in B, B. The B value will point into either B or -B, so it should be copied immediately. If no match is found, the first -item in B, B is returned in B, B. This -function can also be used in the NPN callback. +B, so it should be copied immediately. The client list must include at +least one valid (nonempty) protocol entry in the list. + +The SSL_select_next_proto() helper function can be useful from either the ALPN +callback or the NPN callback (described below). If no match is found, the first +item in B, B is returned in B, B and +B is returned. This can be useful when implementating +the NPN callback. In the ALPN case, the value returned in B and B +must be ignored if B has been returned from +SSL_select_next_proto(). SSL_CTX_set_next_proto_select_cb() sets a callback B that is called when a client needs to select a protocol from the server's provided list, and a @@ -85,9 +93,10 @@ must be set to point to the selected protocol (which may be within B). The length of the protocol name must be written into B. The server's advertised protocols are provided in B and B. The callback can assume that B is syntactically valid. The client must -select a protocol. It is fatal to the connection if this callback returns -a value other than B. The B parameter is the pointer -set via SSL_CTX_set_next_proto_select_cb(). +select a protocol (although it may be an empty, zero length protocol). It is +fatal to the connection if this callback returns a value other than +B or if the zero length protocol is selected. The B +parameter is the pointer set via SSL_CTX_set_next_proto_select_cb(). SSL_CTX_set_next_protos_advertised_cb() sets a callback B that is called when a TLS server needs a list of supported protocols for Next Protocol @@ -154,7 +163,8 @@ A match was found and is returned in B, B. =item OPENSSL_NPN_NO_OVERLAP No match was found. The first item in B, B is returned in -B, B. +B, B (or B and 0 in the case where the first entry in +B is invalid). =back From 0d883f6309b6905d29ffded6d703ded39385579c Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 31 May 2024 16:35:16 +0100 Subject: [PATCH 059/138] Add a test for SSL_select_next_proto Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- test/sslapitest.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/test/sslapitest.c b/test/sslapitest.c index e013838bd1df4..0db82c159b521 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -11973,6 +11973,142 @@ static int test_multi_resume(int idx) return testresult; } +static struct next_proto_st { + int serverlen; + unsigned char server[40]; + int clientlen; + unsigned char client[40]; + int expected_ret; + size_t selectedlen; + unsigned char selected[40]; +} next_proto_tests[] = { + { + 4, { 3, 'a', 'b', 'c' }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 7, { 3, 'a', 'b', 'c', 2, 'a', 'b' }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 7, { 2, 'a', 'b', 3, 'a', 'b', 'c', }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 4, { 3, 'a', 'b', 'c' }, + 7, { 3, 'a', 'b', 'c', 2, 'a', 'b', }, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 4, { 3, 'a', 'b', 'c' }, + 7, { 2, 'a', 'b', 3, 'a', 'b', 'c'}, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 7, { 2, 'b', 'c', 3, 'a', 'b', 'c' }, + 7, { 2, 'a', 'b', 3, 'a', 'b', 'c'}, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 10, { 2, 'b', 'c', 3, 'a', 'b', 'c', 2, 'a', 'b' }, + 7, { 2, 'a', 'b', 3, 'a', 'b', 'c'}, + OPENSSL_NPN_NEGOTIATED, + 3, { 'a', 'b', 'c' } + }, + { + 4, { 3, 'b', 'c', 'd' }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NO_OVERLAP, + 3, { 'a', 'b', 'c' } + }, + { + 0, { 0 }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NO_OVERLAP, + 3, { 'a', 'b', 'c' } + }, + { + -1, { 0 }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NO_OVERLAP, + 3, { 'a', 'b', 'c' } + }, + { + 4, { 3, 'a', 'b', 'c' }, + 0, { 0 }, + OPENSSL_NPN_NO_OVERLAP, + 0, { 0 } + }, + { + 4, { 3, 'a', 'b', 'c' }, + -1, { 0 }, + OPENSSL_NPN_NO_OVERLAP, + 0, { 0 } + }, + { + 3, { 3, 'a', 'b', 'c' }, + 4, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NO_OVERLAP, + 3, { 'a', 'b', 'c' } + }, + { + 4, { 3, 'a', 'b', 'c' }, + 3, { 3, 'a', 'b', 'c' }, + OPENSSL_NPN_NO_OVERLAP, + 0, { 0 } + } +}; + +static int test_select_next_proto(int idx) +{ + struct next_proto_st *np = &next_proto_tests[idx]; + int ret = 0; + unsigned char *out, *client, *server; + unsigned char outlen; + unsigned int clientlen, serverlen; + + if (np->clientlen == -1) { + client = NULL; + clientlen = 0; + } else { + client = np->client; + clientlen = (unsigned int)np->clientlen; + } + if (np->serverlen == -1) { + server = NULL; + serverlen = 0; + } else { + server = np->server; + serverlen = (unsigned int)np->serverlen; + } + + if (!TEST_int_eq(SSL_select_next_proto(&out, &outlen, server, serverlen, + client, clientlen), + np->expected_ret)) + goto err; + + if (np->selectedlen == 0) { + if (!TEST_ptr_null(out) || !TEST_uchar_eq(outlen, 0)) + goto err; + } else { + if (!TEST_mem_eq(out, outlen, np->selected, np->selectedlen)) + goto err; + } + + ret = 1; + err: + return ret; +} + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -12289,6 +12425,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_handshake_retry, 16); ADD_TEST(test_data_retry); ADD_ALL_TESTS(test_multi_resume, 5); + ADD_ALL_TESTS(test_select_next_proto, OSSL_NELEM(next_proto_tests)); return 1; err: From 9925c97a8e8c9887765a0979c35b516bc8c3af85 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 4 Jun 2024 15:47:32 +0100 Subject: [PATCH 060/138] Allow an empty NPN/ALPN protocol list in the tests Allow ourselves to configure an empty NPN/ALPN protocol list and test what happens if we do. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- test/helpers/handshake.c | 6 + test/ssl-tests/08-npn.cnf | 553 +++++++++++++++++++--------------- test/ssl-tests/08-npn.cnf.in | 35 +++ test/ssl-tests/09-alpn.cnf | 66 +++- test/ssl-tests/09-alpn.cnf.in | 33 ++ 5 files changed, 449 insertions(+), 244 deletions(-) diff --git a/test/helpers/handshake.c b/test/helpers/handshake.c index e0422469e4c22..6b1629b942b20 100644 --- a/test/helpers/handshake.c +++ b/test/helpers/handshake.c @@ -348,6 +348,12 @@ static int parse_protos(const char *protos, unsigned char **out, size_t *outlen) len = strlen(protos); + if (len == 0) { + *out = NULL; + *outlen = 0; + return 1; + } + /* Should never have reuse. */ if (!TEST_ptr_null(*out) /* Test values are small, so we omit length limit checks. */ diff --git a/test/ssl-tests/08-npn.cnf b/test/ssl-tests/08-npn.cnf index f38b3f6975ce0..1931d02de4bac 100644 --- a/test/ssl-tests/08-npn.cnf +++ b/test/ssl-tests/08-npn.cnf @@ -1,6 +1,6 @@ # Generated with generate_ssl_tests.pl -num_tests = 20 +num_tests = 22 test-0 = 0-npn-simple test-1 = 1-npn-client-finds-match @@ -8,20 +8,22 @@ test-2 = 2-npn-client-honours-server-pref test-3 = 3-npn-client-first-pref-on-mismatch test-4 = 4-npn-no-server-support test-5 = 5-npn-no-client-support -test-6 = 6-npn-with-sni-no-context-switch -test-7 = 7-npn-with-sni-context-switch -test-8 = 8-npn-selected-sni-server-supports-npn -test-9 = 9-npn-selected-sni-server-does-not-support-npn -test-10 = 10-alpn-preferred-over-npn -test-11 = 11-sni-npn-preferred-over-alpn -test-12 = 12-npn-simple-resumption -test-13 = 13-npn-server-switch-resumption -test-14 = 14-npn-client-switch-resumption -test-15 = 15-npn-client-first-pref-on-mismatch-resumption -test-16 = 16-npn-no-server-support-resumption -test-17 = 17-npn-no-client-support-resumption -test-18 = 18-alpn-preferred-over-npn-resumption -test-19 = 19-npn-used-if-alpn-not-supported-resumption +test-6 = 6-npn-empty-client-list +test-7 = 7-npn-empty-server-list +test-8 = 8-npn-with-sni-no-context-switch +test-9 = 9-npn-with-sni-context-switch +test-10 = 10-npn-selected-sni-server-supports-npn +test-11 = 11-npn-selected-sni-server-does-not-support-npn +test-12 = 12-alpn-preferred-over-npn +test-13 = 13-sni-npn-preferred-over-alpn +test-14 = 14-npn-simple-resumption +test-15 = 15-npn-server-switch-resumption +test-16 = 16-npn-client-switch-resumption +test-17 = 17-npn-client-first-pref-on-mismatch-resumption +test-18 = 18-npn-no-server-support-resumption +test-19 = 19-npn-no-client-support-resumption +test-20 = 20-alpn-preferred-over-npn-resumption +test-21 = 21-npn-used-if-alpn-not-supported-resumption # =========================================================== [0-npn-simple] @@ -206,253 +208,318 @@ NPNProtocols = foo # =========================================================== -[6-npn-with-sni-no-context-switch] -ssl_conf = 6-npn-with-sni-no-context-switch-ssl +[6-npn-empty-client-list] +ssl_conf = 6-npn-empty-client-list-ssl -[6-npn-with-sni-no-context-switch-ssl] -server = 6-npn-with-sni-no-context-switch-server -client = 6-npn-with-sni-no-context-switch-client -server2 = 6-npn-with-sni-no-context-switch-server2 +[6-npn-empty-client-list-ssl] +server = 6-npn-empty-client-list-server +client = 6-npn-empty-client-list-client -[6-npn-with-sni-no-context-switch-server] +[6-npn-empty-client-list-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[6-npn-with-sni-no-context-switch-server2] +[6-npn-empty-client-list-client] +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-6] +ExpectedClientAlert = HandshakeFailure +ExpectedResult = ClientFail +server = 6-npn-empty-client-list-server-extra +client = 6-npn-empty-client-list-client-extra + +[6-npn-empty-client-list-server-extra] +NPNProtocols = foo + +[6-npn-empty-client-list-client-extra] +NPNProtocols = + + +# =========================================================== + +[7-npn-empty-server-list] +ssl_conf = 7-npn-empty-server-list-ssl + +[7-npn-empty-server-list-ssl] +server = 7-npn-empty-server-list-server +client = 7-npn-empty-server-list-client + +[7-npn-empty-server-list-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[6-npn-with-sni-no-context-switch-client] +[7-npn-empty-server-list-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-6] +[test-7] +ExpectedNPNProtocol = foo +server = 7-npn-empty-server-list-server-extra +client = 7-npn-empty-server-list-client-extra + +[7-npn-empty-server-list-server-extra] +NPNProtocols = + +[7-npn-empty-server-list-client-extra] +NPNProtocols = foo + + +# =========================================================== + +[8-npn-with-sni-no-context-switch] +ssl_conf = 8-npn-with-sni-no-context-switch-ssl + +[8-npn-with-sni-no-context-switch-ssl] +server = 8-npn-with-sni-no-context-switch-server +client = 8-npn-with-sni-no-context-switch-client +server2 = 8-npn-with-sni-no-context-switch-server2 + +[8-npn-with-sni-no-context-switch-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-npn-with-sni-no-context-switch-server2] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-npn-with-sni-no-context-switch-client] +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-8] ExpectedNPNProtocol = foo ExpectedServerName = server1 -server = 6-npn-with-sni-no-context-switch-server-extra -server2 = 6-npn-with-sni-no-context-switch-server2-extra -client = 6-npn-with-sni-no-context-switch-client-extra +server = 8-npn-with-sni-no-context-switch-server-extra +server2 = 8-npn-with-sni-no-context-switch-server2-extra +client = 8-npn-with-sni-no-context-switch-client-extra -[6-npn-with-sni-no-context-switch-server-extra] +[8-npn-with-sni-no-context-switch-server-extra] NPNProtocols = foo ServerNameCallback = IgnoreMismatch -[6-npn-with-sni-no-context-switch-server2-extra] +[8-npn-with-sni-no-context-switch-server2-extra] NPNProtocols = bar -[6-npn-with-sni-no-context-switch-client-extra] +[8-npn-with-sni-no-context-switch-client-extra] NPNProtocols = foo,bar ServerName = server1 # =========================================================== -[7-npn-with-sni-context-switch] -ssl_conf = 7-npn-with-sni-context-switch-ssl +[9-npn-with-sni-context-switch] +ssl_conf = 9-npn-with-sni-context-switch-ssl -[7-npn-with-sni-context-switch-ssl] -server = 7-npn-with-sni-context-switch-server -client = 7-npn-with-sni-context-switch-client -server2 = 7-npn-with-sni-context-switch-server2 +[9-npn-with-sni-context-switch-ssl] +server = 9-npn-with-sni-context-switch-server +client = 9-npn-with-sni-context-switch-client +server2 = 9-npn-with-sni-context-switch-server2 -[7-npn-with-sni-context-switch-server] +[9-npn-with-sni-context-switch-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[7-npn-with-sni-context-switch-server2] +[9-npn-with-sni-context-switch-server2] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[7-npn-with-sni-context-switch-client] +[9-npn-with-sni-context-switch-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-7] +[test-9] ExpectedNPNProtocol = bar ExpectedServerName = server2 -server = 7-npn-with-sni-context-switch-server-extra -server2 = 7-npn-with-sni-context-switch-server2-extra -client = 7-npn-with-sni-context-switch-client-extra +server = 9-npn-with-sni-context-switch-server-extra +server2 = 9-npn-with-sni-context-switch-server2-extra +client = 9-npn-with-sni-context-switch-client-extra -[7-npn-with-sni-context-switch-server-extra] +[9-npn-with-sni-context-switch-server-extra] NPNProtocols = foo ServerNameCallback = IgnoreMismatch -[7-npn-with-sni-context-switch-server2-extra] +[9-npn-with-sni-context-switch-server2-extra] NPNProtocols = bar -[7-npn-with-sni-context-switch-client-extra] +[9-npn-with-sni-context-switch-client-extra] NPNProtocols = foo,bar ServerName = server2 # =========================================================== -[8-npn-selected-sni-server-supports-npn] -ssl_conf = 8-npn-selected-sni-server-supports-npn-ssl +[10-npn-selected-sni-server-supports-npn] +ssl_conf = 10-npn-selected-sni-server-supports-npn-ssl -[8-npn-selected-sni-server-supports-npn-ssl] -server = 8-npn-selected-sni-server-supports-npn-server -client = 8-npn-selected-sni-server-supports-npn-client -server2 = 8-npn-selected-sni-server-supports-npn-server2 +[10-npn-selected-sni-server-supports-npn-ssl] +server = 10-npn-selected-sni-server-supports-npn-server +client = 10-npn-selected-sni-server-supports-npn-client +server2 = 10-npn-selected-sni-server-supports-npn-server2 -[8-npn-selected-sni-server-supports-npn-server] +[10-npn-selected-sni-server-supports-npn-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[8-npn-selected-sni-server-supports-npn-server2] +[10-npn-selected-sni-server-supports-npn-server2] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[8-npn-selected-sni-server-supports-npn-client] +[10-npn-selected-sni-server-supports-npn-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-8] +[test-10] ExpectedNPNProtocol = bar ExpectedServerName = server2 -server = 8-npn-selected-sni-server-supports-npn-server-extra -server2 = 8-npn-selected-sni-server-supports-npn-server2-extra -client = 8-npn-selected-sni-server-supports-npn-client-extra +server = 10-npn-selected-sni-server-supports-npn-server-extra +server2 = 10-npn-selected-sni-server-supports-npn-server2-extra +client = 10-npn-selected-sni-server-supports-npn-client-extra -[8-npn-selected-sni-server-supports-npn-server-extra] +[10-npn-selected-sni-server-supports-npn-server-extra] ServerNameCallback = IgnoreMismatch -[8-npn-selected-sni-server-supports-npn-server2-extra] +[10-npn-selected-sni-server-supports-npn-server2-extra] NPNProtocols = bar -[8-npn-selected-sni-server-supports-npn-client-extra] +[10-npn-selected-sni-server-supports-npn-client-extra] NPNProtocols = foo,bar ServerName = server2 # =========================================================== -[9-npn-selected-sni-server-does-not-support-npn] -ssl_conf = 9-npn-selected-sni-server-does-not-support-npn-ssl +[11-npn-selected-sni-server-does-not-support-npn] +ssl_conf = 11-npn-selected-sni-server-does-not-support-npn-ssl -[9-npn-selected-sni-server-does-not-support-npn-ssl] -server = 9-npn-selected-sni-server-does-not-support-npn-server -client = 9-npn-selected-sni-server-does-not-support-npn-client -server2 = 9-npn-selected-sni-server-does-not-support-npn-server2 +[11-npn-selected-sni-server-does-not-support-npn-ssl] +server = 11-npn-selected-sni-server-does-not-support-npn-server +client = 11-npn-selected-sni-server-does-not-support-npn-client +server2 = 11-npn-selected-sni-server-does-not-support-npn-server2 -[9-npn-selected-sni-server-does-not-support-npn-server] +[11-npn-selected-sni-server-does-not-support-npn-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[9-npn-selected-sni-server-does-not-support-npn-server2] +[11-npn-selected-sni-server-does-not-support-npn-server2] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[9-npn-selected-sni-server-does-not-support-npn-client] +[11-npn-selected-sni-server-does-not-support-npn-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-9] +[test-11] ExpectedServerName = server2 -server = 9-npn-selected-sni-server-does-not-support-npn-server-extra -client = 9-npn-selected-sni-server-does-not-support-npn-client-extra +server = 11-npn-selected-sni-server-does-not-support-npn-server-extra +client = 11-npn-selected-sni-server-does-not-support-npn-client-extra -[9-npn-selected-sni-server-does-not-support-npn-server-extra] +[11-npn-selected-sni-server-does-not-support-npn-server-extra] NPNProtocols = bar ServerNameCallback = IgnoreMismatch -[9-npn-selected-sni-server-does-not-support-npn-client-extra] +[11-npn-selected-sni-server-does-not-support-npn-client-extra] NPNProtocols = foo,bar ServerName = server2 # =========================================================== -[10-alpn-preferred-over-npn] -ssl_conf = 10-alpn-preferred-over-npn-ssl +[12-alpn-preferred-over-npn] +ssl_conf = 12-alpn-preferred-over-npn-ssl -[10-alpn-preferred-over-npn-ssl] -server = 10-alpn-preferred-over-npn-server -client = 10-alpn-preferred-over-npn-client +[12-alpn-preferred-over-npn-ssl] +server = 12-alpn-preferred-over-npn-server +client = 12-alpn-preferred-over-npn-client -[10-alpn-preferred-over-npn-server] +[12-alpn-preferred-over-npn-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[10-alpn-preferred-over-npn-client] +[12-alpn-preferred-over-npn-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-10] +[test-12] ExpectedALPNProtocol = foo -server = 10-alpn-preferred-over-npn-server-extra -client = 10-alpn-preferred-over-npn-client-extra +server = 12-alpn-preferred-over-npn-server-extra +client = 12-alpn-preferred-over-npn-client-extra -[10-alpn-preferred-over-npn-server-extra] +[12-alpn-preferred-over-npn-server-extra] ALPNProtocols = foo NPNProtocols = bar -[10-alpn-preferred-over-npn-client-extra] +[12-alpn-preferred-over-npn-client-extra] ALPNProtocols = foo NPNProtocols = bar # =========================================================== -[11-sni-npn-preferred-over-alpn] -ssl_conf = 11-sni-npn-preferred-over-alpn-ssl +[13-sni-npn-preferred-over-alpn] +ssl_conf = 13-sni-npn-preferred-over-alpn-ssl -[11-sni-npn-preferred-over-alpn-ssl] -server = 11-sni-npn-preferred-over-alpn-server -client = 11-sni-npn-preferred-over-alpn-client -server2 = 11-sni-npn-preferred-over-alpn-server2 +[13-sni-npn-preferred-over-alpn-ssl] +server = 13-sni-npn-preferred-over-alpn-server +client = 13-sni-npn-preferred-over-alpn-client +server2 = 13-sni-npn-preferred-over-alpn-server2 -[11-sni-npn-preferred-over-alpn-server] +[13-sni-npn-preferred-over-alpn-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[11-sni-npn-preferred-over-alpn-server2] +[13-sni-npn-preferred-over-alpn-server2] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[11-sni-npn-preferred-over-alpn-client] +[13-sni-npn-preferred-over-alpn-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-11] +[test-13] ExpectedNPNProtocol = bar ExpectedServerName = server2 -server = 11-sni-npn-preferred-over-alpn-server-extra -server2 = 11-sni-npn-preferred-over-alpn-server2-extra -client = 11-sni-npn-preferred-over-alpn-client-extra +server = 13-sni-npn-preferred-over-alpn-server-extra +server2 = 13-sni-npn-preferred-over-alpn-server2-extra +client = 13-sni-npn-preferred-over-alpn-client-extra -[11-sni-npn-preferred-over-alpn-server-extra] +[13-sni-npn-preferred-over-alpn-server-extra] ALPNProtocols = foo ServerNameCallback = IgnoreMismatch -[11-sni-npn-preferred-over-alpn-server2-extra] +[13-sni-npn-preferred-over-alpn-server2-extra] NPNProtocols = bar -[11-sni-npn-preferred-over-alpn-client-extra] +[13-sni-npn-preferred-over-alpn-client-extra] ALPNProtocols = foo NPNProtocols = bar ServerName = server2 @@ -460,356 +527,356 @@ ServerName = server2 # =========================================================== -[12-npn-simple-resumption] -ssl_conf = 12-npn-simple-resumption-ssl +[14-npn-simple-resumption] +ssl_conf = 14-npn-simple-resumption-ssl -[12-npn-simple-resumption-ssl] -server = 12-npn-simple-resumption-server -client = 12-npn-simple-resumption-client -resume-server = 12-npn-simple-resumption-server -resume-client = 12-npn-simple-resumption-client +[14-npn-simple-resumption-ssl] +server = 14-npn-simple-resumption-server +client = 14-npn-simple-resumption-client +resume-server = 14-npn-simple-resumption-server +resume-client = 14-npn-simple-resumption-client -[12-npn-simple-resumption-server] +[14-npn-simple-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[12-npn-simple-resumption-client] +[14-npn-simple-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-12] +[test-14] ExpectedNPNProtocol = foo HandshakeMode = Resume ResumptionExpected = Yes -server = 12-npn-simple-resumption-server-extra -resume-server = 12-npn-simple-resumption-server-extra -client = 12-npn-simple-resumption-client-extra -resume-client = 12-npn-simple-resumption-client-extra +server = 14-npn-simple-resumption-server-extra +resume-server = 14-npn-simple-resumption-server-extra +client = 14-npn-simple-resumption-client-extra +resume-client = 14-npn-simple-resumption-client-extra -[12-npn-simple-resumption-server-extra] +[14-npn-simple-resumption-server-extra] NPNProtocols = foo -[12-npn-simple-resumption-client-extra] +[14-npn-simple-resumption-client-extra] NPNProtocols = foo # =========================================================== -[13-npn-server-switch-resumption] -ssl_conf = 13-npn-server-switch-resumption-ssl +[15-npn-server-switch-resumption] +ssl_conf = 15-npn-server-switch-resumption-ssl -[13-npn-server-switch-resumption-ssl] -server = 13-npn-server-switch-resumption-server -client = 13-npn-server-switch-resumption-client -resume-server = 13-npn-server-switch-resumption-resume-server -resume-client = 13-npn-server-switch-resumption-client +[15-npn-server-switch-resumption-ssl] +server = 15-npn-server-switch-resumption-server +client = 15-npn-server-switch-resumption-client +resume-server = 15-npn-server-switch-resumption-resume-server +resume-client = 15-npn-server-switch-resumption-client -[13-npn-server-switch-resumption-server] +[15-npn-server-switch-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[13-npn-server-switch-resumption-resume-server] +[15-npn-server-switch-resumption-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[13-npn-server-switch-resumption-client] +[15-npn-server-switch-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-13] +[test-15] ExpectedNPNProtocol = baz HandshakeMode = Resume ResumptionExpected = Yes -server = 13-npn-server-switch-resumption-server-extra -resume-server = 13-npn-server-switch-resumption-resume-server-extra -client = 13-npn-server-switch-resumption-client-extra -resume-client = 13-npn-server-switch-resumption-client-extra +server = 15-npn-server-switch-resumption-server-extra +resume-server = 15-npn-server-switch-resumption-resume-server-extra +client = 15-npn-server-switch-resumption-client-extra +resume-client = 15-npn-server-switch-resumption-client-extra -[13-npn-server-switch-resumption-server-extra] +[15-npn-server-switch-resumption-server-extra] NPNProtocols = bar,foo -[13-npn-server-switch-resumption-resume-server-extra] +[15-npn-server-switch-resumption-resume-server-extra] NPNProtocols = baz,foo -[13-npn-server-switch-resumption-client-extra] +[15-npn-server-switch-resumption-client-extra] NPNProtocols = foo,bar,baz # =========================================================== -[14-npn-client-switch-resumption] -ssl_conf = 14-npn-client-switch-resumption-ssl +[16-npn-client-switch-resumption] +ssl_conf = 16-npn-client-switch-resumption-ssl -[14-npn-client-switch-resumption-ssl] -server = 14-npn-client-switch-resumption-server -client = 14-npn-client-switch-resumption-client -resume-server = 14-npn-client-switch-resumption-server -resume-client = 14-npn-client-switch-resumption-resume-client +[16-npn-client-switch-resumption-ssl] +server = 16-npn-client-switch-resumption-server +client = 16-npn-client-switch-resumption-client +resume-server = 16-npn-client-switch-resumption-server +resume-client = 16-npn-client-switch-resumption-resume-client -[14-npn-client-switch-resumption-server] +[16-npn-client-switch-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[14-npn-client-switch-resumption-client] +[16-npn-client-switch-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[14-npn-client-switch-resumption-resume-client] +[16-npn-client-switch-resumption-resume-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-14] +[test-16] ExpectedNPNProtocol = bar HandshakeMode = Resume ResumptionExpected = Yes -server = 14-npn-client-switch-resumption-server-extra -resume-server = 14-npn-client-switch-resumption-server-extra -client = 14-npn-client-switch-resumption-client-extra -resume-client = 14-npn-client-switch-resumption-resume-client-extra +server = 16-npn-client-switch-resumption-server-extra +resume-server = 16-npn-client-switch-resumption-server-extra +client = 16-npn-client-switch-resumption-client-extra +resume-client = 16-npn-client-switch-resumption-resume-client-extra -[14-npn-client-switch-resumption-server-extra] +[16-npn-client-switch-resumption-server-extra] NPNProtocols = foo,bar,baz -[14-npn-client-switch-resumption-client-extra] +[16-npn-client-switch-resumption-client-extra] NPNProtocols = foo,baz -[14-npn-client-switch-resumption-resume-client-extra] +[16-npn-client-switch-resumption-resume-client-extra] NPNProtocols = bar,baz # =========================================================== -[15-npn-client-first-pref-on-mismatch-resumption] -ssl_conf = 15-npn-client-first-pref-on-mismatch-resumption-ssl +[17-npn-client-first-pref-on-mismatch-resumption] +ssl_conf = 17-npn-client-first-pref-on-mismatch-resumption-ssl -[15-npn-client-first-pref-on-mismatch-resumption-ssl] -server = 15-npn-client-first-pref-on-mismatch-resumption-server -client = 15-npn-client-first-pref-on-mismatch-resumption-client -resume-server = 15-npn-client-first-pref-on-mismatch-resumption-resume-server -resume-client = 15-npn-client-first-pref-on-mismatch-resumption-client +[17-npn-client-first-pref-on-mismatch-resumption-ssl] +server = 17-npn-client-first-pref-on-mismatch-resumption-server +client = 17-npn-client-first-pref-on-mismatch-resumption-client +resume-server = 17-npn-client-first-pref-on-mismatch-resumption-resume-server +resume-client = 17-npn-client-first-pref-on-mismatch-resumption-client -[15-npn-client-first-pref-on-mismatch-resumption-server] +[17-npn-client-first-pref-on-mismatch-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[15-npn-client-first-pref-on-mismatch-resumption-resume-server] +[17-npn-client-first-pref-on-mismatch-resumption-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[15-npn-client-first-pref-on-mismatch-resumption-client] +[17-npn-client-first-pref-on-mismatch-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-15] +[test-17] ExpectedNPNProtocol = foo HandshakeMode = Resume ResumptionExpected = Yes -server = 15-npn-client-first-pref-on-mismatch-resumption-server-extra -resume-server = 15-npn-client-first-pref-on-mismatch-resumption-resume-server-extra -client = 15-npn-client-first-pref-on-mismatch-resumption-client-extra -resume-client = 15-npn-client-first-pref-on-mismatch-resumption-client-extra +server = 17-npn-client-first-pref-on-mismatch-resumption-server-extra +resume-server = 17-npn-client-first-pref-on-mismatch-resumption-resume-server-extra +client = 17-npn-client-first-pref-on-mismatch-resumption-client-extra +resume-client = 17-npn-client-first-pref-on-mismatch-resumption-client-extra -[15-npn-client-first-pref-on-mismatch-resumption-server-extra] +[17-npn-client-first-pref-on-mismatch-resumption-server-extra] NPNProtocols = bar -[15-npn-client-first-pref-on-mismatch-resumption-resume-server-extra] +[17-npn-client-first-pref-on-mismatch-resumption-resume-server-extra] NPNProtocols = baz -[15-npn-client-first-pref-on-mismatch-resumption-client-extra] +[17-npn-client-first-pref-on-mismatch-resumption-client-extra] NPNProtocols = foo,bar # =========================================================== -[16-npn-no-server-support-resumption] -ssl_conf = 16-npn-no-server-support-resumption-ssl +[18-npn-no-server-support-resumption] +ssl_conf = 18-npn-no-server-support-resumption-ssl -[16-npn-no-server-support-resumption-ssl] -server = 16-npn-no-server-support-resumption-server -client = 16-npn-no-server-support-resumption-client -resume-server = 16-npn-no-server-support-resumption-resume-server -resume-client = 16-npn-no-server-support-resumption-client +[18-npn-no-server-support-resumption-ssl] +server = 18-npn-no-server-support-resumption-server +client = 18-npn-no-server-support-resumption-client +resume-server = 18-npn-no-server-support-resumption-resume-server +resume-client = 18-npn-no-server-support-resumption-client -[16-npn-no-server-support-resumption-server] +[18-npn-no-server-support-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[16-npn-no-server-support-resumption-resume-server] +[18-npn-no-server-support-resumption-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[16-npn-no-server-support-resumption-client] +[18-npn-no-server-support-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-16] +[test-18] HandshakeMode = Resume ResumptionExpected = Yes -server = 16-npn-no-server-support-resumption-server-extra -client = 16-npn-no-server-support-resumption-client-extra -resume-client = 16-npn-no-server-support-resumption-client-extra +server = 18-npn-no-server-support-resumption-server-extra +client = 18-npn-no-server-support-resumption-client-extra +resume-client = 18-npn-no-server-support-resumption-client-extra -[16-npn-no-server-support-resumption-server-extra] +[18-npn-no-server-support-resumption-server-extra] NPNProtocols = foo -[16-npn-no-server-support-resumption-client-extra] +[18-npn-no-server-support-resumption-client-extra] NPNProtocols = foo # =========================================================== -[17-npn-no-client-support-resumption] -ssl_conf = 17-npn-no-client-support-resumption-ssl +[19-npn-no-client-support-resumption] +ssl_conf = 19-npn-no-client-support-resumption-ssl -[17-npn-no-client-support-resumption-ssl] -server = 17-npn-no-client-support-resumption-server -client = 17-npn-no-client-support-resumption-client -resume-server = 17-npn-no-client-support-resumption-server -resume-client = 17-npn-no-client-support-resumption-resume-client +[19-npn-no-client-support-resumption-ssl] +server = 19-npn-no-client-support-resumption-server +client = 19-npn-no-client-support-resumption-client +resume-server = 19-npn-no-client-support-resumption-server +resume-client = 19-npn-no-client-support-resumption-resume-client -[17-npn-no-client-support-resumption-server] +[19-npn-no-client-support-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[17-npn-no-client-support-resumption-client] +[19-npn-no-client-support-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[17-npn-no-client-support-resumption-resume-client] +[19-npn-no-client-support-resumption-resume-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-17] +[test-19] HandshakeMode = Resume ResumptionExpected = Yes -server = 17-npn-no-client-support-resumption-server-extra -resume-server = 17-npn-no-client-support-resumption-server-extra -client = 17-npn-no-client-support-resumption-client-extra +server = 19-npn-no-client-support-resumption-server-extra +resume-server = 19-npn-no-client-support-resumption-server-extra +client = 19-npn-no-client-support-resumption-client-extra -[17-npn-no-client-support-resumption-server-extra] +[19-npn-no-client-support-resumption-server-extra] NPNProtocols = foo -[17-npn-no-client-support-resumption-client-extra] +[19-npn-no-client-support-resumption-client-extra] NPNProtocols = foo # =========================================================== -[18-alpn-preferred-over-npn-resumption] -ssl_conf = 18-alpn-preferred-over-npn-resumption-ssl +[20-alpn-preferred-over-npn-resumption] +ssl_conf = 20-alpn-preferred-over-npn-resumption-ssl -[18-alpn-preferred-over-npn-resumption-ssl] -server = 18-alpn-preferred-over-npn-resumption-server -client = 18-alpn-preferred-over-npn-resumption-client -resume-server = 18-alpn-preferred-over-npn-resumption-resume-server -resume-client = 18-alpn-preferred-over-npn-resumption-client +[20-alpn-preferred-over-npn-resumption-ssl] +server = 20-alpn-preferred-over-npn-resumption-server +client = 20-alpn-preferred-over-npn-resumption-client +resume-server = 20-alpn-preferred-over-npn-resumption-resume-server +resume-client = 20-alpn-preferred-over-npn-resumption-client -[18-alpn-preferred-over-npn-resumption-server] +[20-alpn-preferred-over-npn-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[18-alpn-preferred-over-npn-resumption-resume-server] +[20-alpn-preferred-over-npn-resumption-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[18-alpn-preferred-over-npn-resumption-client] +[20-alpn-preferred-over-npn-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-18] +[test-20] ExpectedALPNProtocol = foo HandshakeMode = Resume ResumptionExpected = Yes -server = 18-alpn-preferred-over-npn-resumption-server-extra -resume-server = 18-alpn-preferred-over-npn-resumption-resume-server-extra -client = 18-alpn-preferred-over-npn-resumption-client-extra -resume-client = 18-alpn-preferred-over-npn-resumption-client-extra +server = 20-alpn-preferred-over-npn-resumption-server-extra +resume-server = 20-alpn-preferred-over-npn-resumption-resume-server-extra +client = 20-alpn-preferred-over-npn-resumption-client-extra +resume-client = 20-alpn-preferred-over-npn-resumption-client-extra -[18-alpn-preferred-over-npn-resumption-server-extra] +[20-alpn-preferred-over-npn-resumption-server-extra] NPNProtocols = bar -[18-alpn-preferred-over-npn-resumption-resume-server-extra] +[20-alpn-preferred-over-npn-resumption-resume-server-extra] ALPNProtocols = foo NPNProtocols = baz -[18-alpn-preferred-over-npn-resumption-client-extra] +[20-alpn-preferred-over-npn-resumption-client-extra] ALPNProtocols = foo NPNProtocols = bar,baz # =========================================================== -[19-npn-used-if-alpn-not-supported-resumption] -ssl_conf = 19-npn-used-if-alpn-not-supported-resumption-ssl +[21-npn-used-if-alpn-not-supported-resumption] +ssl_conf = 21-npn-used-if-alpn-not-supported-resumption-ssl -[19-npn-used-if-alpn-not-supported-resumption-ssl] -server = 19-npn-used-if-alpn-not-supported-resumption-server -client = 19-npn-used-if-alpn-not-supported-resumption-client -resume-server = 19-npn-used-if-alpn-not-supported-resumption-resume-server -resume-client = 19-npn-used-if-alpn-not-supported-resumption-client +[21-npn-used-if-alpn-not-supported-resumption-ssl] +server = 21-npn-used-if-alpn-not-supported-resumption-server +client = 21-npn-used-if-alpn-not-supported-resumption-client +resume-server = 21-npn-used-if-alpn-not-supported-resumption-resume-server +resume-client = 21-npn-used-if-alpn-not-supported-resumption-client -[19-npn-used-if-alpn-not-supported-resumption-server] +[21-npn-used-if-alpn-not-supported-resumption-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[19-npn-used-if-alpn-not-supported-resumption-resume-server] +[21-npn-used-if-alpn-not-supported-resumption-resume-server] Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem CipherString = DEFAULT PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem -[19-npn-used-if-alpn-not-supported-resumption-client] +[21-npn-used-if-alpn-not-supported-resumption-client] CipherString = DEFAULT MaxProtocol = TLSv1.2 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem VerifyMode = Peer -[test-19] +[test-21] ExpectedNPNProtocol = baz HandshakeMode = Resume ResumptionExpected = Yes -server = 19-npn-used-if-alpn-not-supported-resumption-server-extra -resume-server = 19-npn-used-if-alpn-not-supported-resumption-resume-server-extra -client = 19-npn-used-if-alpn-not-supported-resumption-client-extra -resume-client = 19-npn-used-if-alpn-not-supported-resumption-client-extra +server = 21-npn-used-if-alpn-not-supported-resumption-server-extra +resume-server = 21-npn-used-if-alpn-not-supported-resumption-resume-server-extra +client = 21-npn-used-if-alpn-not-supported-resumption-client-extra +resume-client = 21-npn-used-if-alpn-not-supported-resumption-client-extra -[19-npn-used-if-alpn-not-supported-resumption-server-extra] +[21-npn-used-if-alpn-not-supported-resumption-server-extra] ALPNProtocols = foo NPNProtocols = bar -[19-npn-used-if-alpn-not-supported-resumption-resume-server-extra] +[21-npn-used-if-alpn-not-supported-resumption-resume-server-extra] NPNProtocols = baz -[19-npn-used-if-alpn-not-supported-resumption-client-extra] +[21-npn-used-if-alpn-not-supported-resumption-client-extra] ALPNProtocols = foo NPNProtocols = bar,baz diff --git a/test/ssl-tests/08-npn.cnf.in b/test/ssl-tests/08-npn.cnf.in index 30783e45eb593..1dc2704bdba87 100644 --- a/test/ssl-tests/08-npn.cnf.in +++ b/test/ssl-tests/08-npn.cnf.in @@ -110,6 +110,41 @@ our @tests = ( "ExpectedNPNProtocol" => undef, }, }, + { + name => "npn-empty-client-list", + server => { + extra => { + "NPNProtocols" => "foo", + }, + }, + client => { + extra => { + "NPNProtocols" => "", + }, + "MaxProtocol" => "TLSv1.2" + }, + test => { + "ExpectedResult" => "ClientFail", + "ExpectedClientAlert" => "HandshakeFailure" + }, + }, + { + name => "npn-empty-server-list", + server => { + extra => { + "NPNProtocols" => "", + }, + }, + client => { + extra => { + "NPNProtocols" => "foo", + }, + "MaxProtocol" => "TLSv1.2" + }, + test => { + "ExpectedNPNProtocol" => "foo" + }, + }, { name => "npn-with-sni-no-context-switch", server => { diff --git a/test/ssl-tests/09-alpn.cnf b/test/ssl-tests/09-alpn.cnf index e7e6cb95348b7..dd668739ab9a0 100644 --- a/test/ssl-tests/09-alpn.cnf +++ b/test/ssl-tests/09-alpn.cnf @@ -1,6 +1,6 @@ # Generated with generate_ssl_tests.pl -num_tests = 16 +num_tests = 18 test-0 = 0-alpn-simple test-1 = 1-alpn-server-finds-match @@ -18,6 +18,8 @@ test-12 = 12-alpn-client-switch-resumption test-13 = 13-alpn-alert-on-mismatch-resumption test-14 = 14-alpn-no-server-support-resumption test-15 = 15-alpn-no-client-support-resumption +test-16 = 16-alpn-empty-client-list +test-17 = 17-alpn-empty-server-list # =========================================================== [0-alpn-simple] @@ -617,3 +619,65 @@ ALPNProtocols = foo ALPNProtocols = foo +# =========================================================== + +[16-alpn-empty-client-list] +ssl_conf = 16-alpn-empty-client-list-ssl + +[16-alpn-empty-client-list-ssl] +server = 16-alpn-empty-client-list-server +client = 16-alpn-empty-client-list-client + +[16-alpn-empty-client-list-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[16-alpn-empty-client-list-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-16] +server = 16-alpn-empty-client-list-server-extra +client = 16-alpn-empty-client-list-client-extra + +[16-alpn-empty-client-list-server-extra] +ALPNProtocols = foo + +[16-alpn-empty-client-list-client-extra] +ALPNProtocols = + + +# =========================================================== + +[17-alpn-empty-server-list] +ssl_conf = 17-alpn-empty-server-list-ssl + +[17-alpn-empty-server-list-ssl] +server = 17-alpn-empty-server-list-server +client = 17-alpn-empty-server-list-client + +[17-alpn-empty-server-list-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[17-alpn-empty-server-list-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-17] +ExpectedResult = ServerFail +ExpectedServerAlert = NoApplicationProtocol +server = 17-alpn-empty-server-list-server-extra +client = 17-alpn-empty-server-list-client-extra + +[17-alpn-empty-server-list-server-extra] +ALPNProtocols = + +[17-alpn-empty-server-list-client-extra] +ALPNProtocols = foo + + diff --git a/test/ssl-tests/09-alpn.cnf.in b/test/ssl-tests/09-alpn.cnf.in index 81330756c62ce..322b7096a6e46 100644 --- a/test/ssl-tests/09-alpn.cnf.in +++ b/test/ssl-tests/09-alpn.cnf.in @@ -322,4 +322,37 @@ our @tests = ( "ExpectedALPNProtocol" => undef, }, }, + { + name => "alpn-empty-client-list", + server => { + extra => { + "ALPNProtocols" => "foo", + }, + }, + client => { + extra => { + "ALPNProtocols" => "", + }, + }, + test => { + "ExpectedALPNProtocol" => undef, + }, + }, + { + name => "alpn-empty-server-list", + server => { + extra => { + "ALPNProtocols" => "", + }, + }, + client => { + extra => { + "ALPNProtocols" => "foo", + }, + }, + test => { + "ExpectedResult" => "ServerFail", + "ExpectedServerAlert" => "NoApplicationProtocol", + }, + }, ); From e10a3a84bf73a3e6024c338b51f2fb4e78a3dee9 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 21 Jun 2024 10:41:55 +0100 Subject: [PATCH 061/138] Correct return values for tls_construct_stoc_next_proto_neg Return EXT_RETURN_NOT_SENT in the event that we don't send the extension, rather than EXT_RETURN_SENT. This actually makes no difference at all to the current control flow since this return value is ignored in this case anyway. But lets make it correct anyway. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- ssl/statem/extensions_srvr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 699cc202c344e..38d34f3c17bb8 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1519,9 +1519,10 @@ EXT_RETURN tls_construct_stoc_next_proto_neg(SSL_CONNECTION *s, WPACKET *pkt, return EXT_RETURN_FAIL; } s->s3.npn_seen = 1; + return EXT_RETURN_SENT; } - return EXT_RETURN_SENT; + return EXT_RETURN_NOT_SENT; } #endif From 238fa464d6e38aa2c92af70ef9580c74cff512e4 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 21 Jun 2024 11:51:54 +0100 Subject: [PATCH 062/138] Add ALPN validation in the client The ALPN protocol selected by the server must be one that we originally advertised. We should verify that it is. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- ssl/statem/extensions_clnt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index f24db5f570d2c..1c955f414eb25 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1628,6 +1628,8 @@ int tls_parse_stoc_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { size_t len; + PACKET confpkt, protpkt; + int valid = 0; /* We must have requested it. */ if (!s->s3.alpn_sent) { @@ -1646,6 +1648,28 @@ int tls_parse_stoc_alpn(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); return 0; } + + /* It must be a protocol that we sent */ + if (!PACKET_buf_init(&confpkt, s->ext.alpn, s->ext.alpn_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + while (PACKET_get_length_prefixed_1(&confpkt, &protpkt)) { + if (PACKET_remaining(&protpkt) != len) + continue; + if (memcmp(PACKET_data(pkt), PACKET_data(&protpkt), len) == 0) { + /* Valid protocol found */ + valid = 1; + break; + } + } + + if (!valid) { + /* The protocol sent from the server does not match one we advertised */ + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + OPENSSL_free(s->s3.alpn_selected); s->s3.alpn_selected = OPENSSL_malloc(len); if (s->s3.alpn_selected == NULL) { From de71058567b84c6e14b758a383e1862eb3efb921 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 21 Jun 2024 10:09:41 +0100 Subject: [PATCH 063/138] Add explicit testing of ALN and NPN in sslapitest We already had some tests elsewhere - but this extends that testing with additional tests. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- test/sslapitest.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/test/sslapitest.c b/test/sslapitest.c index 0db82c159b521..7ad12f29713f7 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -12109,6 +12109,231 @@ static int test_select_next_proto(int idx) return ret; } +static const unsigned char fooprot[] = {3, 'f', 'o', 'o' }; +static const unsigned char barprot[] = {3, 'b', 'a', 'r' }; + +#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG) +static int npn_advert_cb(SSL *ssl, const unsigned char **out, + unsigned int *outlen, void *arg) +{ + int *idx = (int *)arg; + + switch (*idx) { + default: + case 0: + *out = fooprot; + *outlen = sizeof(fooprot); + return SSL_TLSEXT_ERR_OK; + + case 1: + *outlen = 0; + return SSL_TLSEXT_ERR_OK; + + case 2: + return SSL_TLSEXT_ERR_NOACK; + } +} + +static int npn_select_cb(SSL *s, unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) +{ + int *idx = (int *)arg; + + switch (*idx) { + case 0: + case 1: + *out = (unsigned char *)(fooprot + 1); + *outlen = *fooprot; + return SSL_TLSEXT_ERR_OK; + + case 3: + *out = (unsigned char *)(barprot + 1); + *outlen = *barprot; + return SSL_TLSEXT_ERR_OK; + + case 4: + *outlen = 0; + return SSL_TLSEXT_ERR_OK; + + default: + case 2: + return SSL_TLSEXT_ERR_ALERT_FATAL; + } +} + +/* + * Test the NPN callbacks + * Test 0: advert = foo, select = foo + * Test 1: advert = , select = foo + * Test 2: no advert + * Test 3: advert = foo, select = bar + * Test 4: advert = foo, select = (should fail) + */ +static int test_npn(int idx) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), 0, TLS1_2_VERSION, + &sctx, &cctx, cert, privkey))) + goto end; + + SSL_CTX_set_next_protos_advertised_cb(sctx, npn_advert_cb, &idx); + SSL_CTX_set_next_proto_select_cb(cctx, npn_select_cb, &idx); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, + NULL))) + goto end; + + if (idx == 4) { + /* We don't allow empty selection of NPN, so this should fail */ + if (!TEST_false(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + } else { + const unsigned char *prot; + unsigned int protlen; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + SSL_get0_next_proto_negotiated(serverssl, &prot, &protlen); + switch (idx) { + case 0: + case 1: + if (!TEST_mem_eq(prot, protlen, fooprot + 1, *fooprot)) + goto end; + break; + case 2: + if (!TEST_uint_eq(protlen, 0)) + goto end; + break; + case 3: + if (!TEST_mem_eq(prot, protlen, barprot + 1, *barprot)) + goto end; + break; + default: + TEST_error("Should not get here"); + goto end; + } + } + + testresult = 1; + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} +#endif /* !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG) */ + +static int alpn_select_cb2(SSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) +{ + int *idx = (int *)arg; + + switch (*idx) { + case 0: + *out = (unsigned char *)(fooprot + 1); + *outlen = *fooprot; + return SSL_TLSEXT_ERR_OK; + + case 2: + *out = (unsigned char *)(barprot + 1); + *outlen = *barprot; + return SSL_TLSEXT_ERR_OK; + + case 3: + *outlen = 0; + return SSL_TLSEXT_ERR_OK; + + default: + case 1: + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + return 0; +} + +/* + * Test the ALPN callbacks + * Test 0: client = foo, select = foo + * Test 1: client = , select = none + * Test 2: client = foo, select = bar (should fail) + * Test 3: client = foo, select = (should fail) + */ +static int test_alpn(int idx) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + const unsigned char *prots = fooprot; + unsigned int protslen = sizeof(fooprot); + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), 0, 0, + &sctx, &cctx, cert, privkey))) + goto end; + + SSL_CTX_set_alpn_select_cb(sctx, alpn_select_cb2, &idx); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, + NULL))) + goto end; + + if (idx == 1) { + prots = NULL; + protslen = 0; + } + + /* SSL_set_alpn_protos returns 0 for success! */ + if (!TEST_false(SSL_set_alpn_protos(clientssl, prots, protslen))) + goto end; + + if (idx == 2 || idx == 3) { + /* We don't allow empty selection of NPN, so this should fail */ + if (!TEST_false(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + } else { + const unsigned char *prot; + unsigned int protlen; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + SSL_get0_alpn_selected(clientssl, &prot, &protlen); + switch (idx) { + case 0: + if (!TEST_mem_eq(prot, protlen, fooprot + 1, *fooprot)) + goto end; + break; + case 1: + if (!TEST_uint_eq(protlen, 0)) + goto end; + break; + default: + TEST_error("Should not get here"); + goto end; + } + } + + testresult = 1; + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -12426,6 +12651,10 @@ int setup_tests(void) ADD_TEST(test_data_retry); ADD_ALL_TESTS(test_multi_resume, 5); ADD_ALL_TESTS(test_select_next_proto, OSSL_NELEM(next_proto_tests)); +#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_NEXTPROTONEG) + ADD_ALL_TESTS(test_npn, 5); +#endif + ADD_ALL_TESTS(test_alpn, 4); return 1; err: From 214c724e00d594c3eecf4b740ee7af772f0ee04a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 21 Jun 2024 14:29:26 +0100 Subject: [PATCH 064/138] Add a test for an empty NextProto message It is valid according to the spec for a NextProto message to have no protocols listed in it. The OpenSSL implementation however does not allow us to create such a message. In order to check that we work as expected when communicating with a client that does generate such messages we have to use a TLSProxy test. Follow on from CVE-2024-5535 Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24716) --- test/recipes/70-test_npn.t | 73 +++++++++++++++++++++++++++++++++ util/perl/TLSProxy/Message.pm | 13 ++++++ util/perl/TLSProxy/NextProto.pm | 62 ++++++++++++++++++++++++++++ util/perl/TLSProxy/Proxy.pm | 1 + 4 files changed, 149 insertions(+) create mode 100644 test/recipes/70-test_npn.t create mode 100644 util/perl/TLSProxy/NextProto.pm diff --git a/test/recipes/70-test_npn.t b/test/recipes/70-test_npn.t new file mode 100644 index 0000000000000..f82e71af6aca1 --- /dev/null +++ b/test/recipes/70-test_npn.t @@ -0,0 +1,73 @@ +#! /usr/bin/env perl +# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file/; +use OpenSSL::Test::Utils; + +use TLSProxy::Proxy; + +my $test_name = "test_npn"; +setup($test_name); + +plan skip_all => "TLSProxy isn't usable on $^O" + if $^O =~ /^(VMS)$/; + +plan skip_all => "$test_name needs the dynamic engine feature enabled" + if disabled("engine") || disabled("dynamic-engine"); + +plan skip_all => "$test_name needs the sock feature enabled" + if disabled("sock"); + +plan skip_all => "$test_name needs NPN enabled" + if disabled("nextprotoneg"); + +plan skip_all => "$test_name needs TLSv1.2 enabled" + if disabled("tls1_2"); + +my $proxy = TLSProxy::Proxy->new( + undef, + cmdstr(app(["openssl"]), display => 1), + srctop_file("apps", "server.pem"), + (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) +); + +$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; +plan tests => 1; + +my $npnseen = 0; + +# Test 1: Check sending an empty NextProto message from the client works. This is +# valid as per the spec, but OpenSSL does not allow you to send it. +# Therefore we must be prepared to receive such a message but we cannot +# generate it except via TLSProxy +$proxy->clear(); +$proxy->filter(\&npn_filter); +$proxy->clientflags("-nextprotoneg foo -no_tls1_3"); +$proxy->serverflags("-nextprotoneg foo"); +$proxy->start(); +ok($npnseen && TLSProxy::Message->success(), "Empty NPN message"); + +sub npn_filter +{ + my $proxy = shift; + my $message; + + # The NextProto message always appears in flight 2 + return if $proxy->flight != 2; + + foreach my $message (@{$proxy->message_list}) { + if ($message->mt == TLSProxy::Message::MT_NEXT_PROTO) { + # Our TLSproxy NextProto message support doesn't support parsing of + # the message. If we repack it just creates an empty NextProto + # message - which is exactly the scenario we want to test here. + $message->repack(); + $npnseen = 1; + } + } +} diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index 5f304a2cfd52b..d1b108f5d68f1 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -464,6 +464,19 @@ sub create_message ); } $message->parse(); + } elsif ($mt == MT_NEXT_PROTO) { + $message = TLSProxy::NextProto->new( + $isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + $message->parse(); } else { #Unknown message type $message = TLSProxy::Message->new( diff --git a/util/perl/TLSProxy/NextProto.pm b/util/perl/TLSProxy/NextProto.pm new file mode 100644 index 0000000000000..0825ea744f47a --- /dev/null +++ b/util/perl/TLSProxy/NextProto.pm @@ -0,0 +1,62 @@ +# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; + +package TLSProxy::NextProto; + +use vars '@ISA'; +push @ISA, 'TLSProxy::Message'; + +sub new +{ + my $class = shift; + my ($isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens) = @_; + + my $self = $class->SUPER::new( + $isdtls, + $server, + TLSProxy::Message::MT_NEXT_PROTO, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + $records, + $startoffset, + $message_frag_lens); + + return $self; +} + +sub parse +{ + # We don't support parsing at the moment +} + +# This is supposed to reconstruct the on-the-wire message data following changes. +# For now though since we don't support parsing we just create an empty NextProto +# message - this capability is used in test_npn +sub set_message_contents +{ + my $self = shift; + my $data; + + $data = pack("C32", 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00); + $self->data($data); +} +1; diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm index c4f3a0a5497da..48c55f48220b2 100644 --- a/util/perl/TLSProxy/Proxy.pm +++ b/util/perl/TLSProxy/Proxy.pm @@ -25,6 +25,7 @@ use TLSProxy::CertificateRequest; use TLSProxy::CertificateVerify; use TLSProxy::ServerKeyExchange; use TLSProxy::NewSessionTicket; +use TLSProxy::NextProto; my $have_IPv6; my $IP_factory; From 981d129a5609ee2e031367c34c67a9f61a5bfd66 Mon Sep 17 00:00:00 2001 From: Vita Batrla Date: Tue, 25 Jun 2024 11:58:49 +0200 Subject: [PATCH 065/138] docs: document that *_free(NULL) does nothing Explicitly documents that *_free(NULL) does nothing. Fixes two cases where that wasn't true. Fixes #24675. Reviewed-by: Richard Levitte Reviewed-by: Tim Hudson Reviewed-by: Sasa Nedvedicky (Merged from https://github.com/openssl/openssl/pull/24735) --- crypto/conf/conf_lib.c | 2 +- crypto/context.c | 4 ++-- doc/man3/ASN1_INTEGER_new.pod | 1 + doc/man3/ASYNC_WAIT_CTX_new.pod | 3 +++ doc/man3/BIO_ADDR.pod | 4 ++-- doc/man3/BIO_ADDRINFO.pod | 2 +- doc/man3/BIO_meth_new.pod | 2 +- doc/man3/BN_generate_prime.pod | 3 ++- doc/man3/BUF_MEM_new.pod | 1 + doc/man3/COMP_CTX_new.pod | 2 ++ doc/man3/CRYPTO_THREAD_run_once.pod | 1 + doc/man3/CTLOG_STORE_new.pod | 2 +- doc/man3/CTLOG_new.pod | 2 +- doc/man3/CT_POLICY_EVAL_CTX_new.pod | 3 ++- doc/man3/DH_meth_new.pod | 2 +- doc/man3/DSA_SIG_new.pod | 1 + doc/man3/DSA_meth_new.pod | 2 +- doc/man3/ECDSA_SIG_new.pod | 1 + doc/man3/ENGINE_add.pod | 3 ++- doc/man3/EVP_ASYM_CIPHER_free.pod | 2 +- doc/man3/EVP_CIPHER_meth_new.pod | 1 + doc/man3/EVP_DigestInit.pod | 2 ++ doc/man3/EVP_EncodeInit.pod | 2 +- doc/man3/EVP_EncryptInit.pod | 7 ++++--- doc/man3/EVP_KEM_free.pod | 1 + doc/man3/EVP_KEYEXCH_free.pod | 2 +- doc/man3/EVP_KEYMGMT.pod | 1 + doc/man3/EVP_MD_meth_new.pod | 1 + doc/man3/EVP_PKEY_ASN1_METHOD.pod | 2 +- doc/man3/EVP_PKEY_meth_new.pod | 2 +- doc/man3/EVP_SIGNATURE.pod | 2 +- doc/man3/HMAC.pod | 2 +- doc/man3/NCONF_new_ex.pod | 2 +- doc/man3/OCSP_REQUEST_new.pod | 1 + doc/man3/OCSP_cert_to_id.pod | 1 + doc/man3/OCSP_response_status.pod | 1 + doc/man3/OPENSSL_LH_COMPFUNC.pod | 2 +- doc/man3/OPENSSL_init_crypto.pod | 1 + doc/man3/OPENSSL_malloc.pod | 3 ++- doc/man3/OPENSSL_secure_malloc.pod | 6 ++++-- doc/man3/OSSL_CMP_CTX_new.pod | 1 + doc/man3/OSSL_CMP_SRV_CTX_new.pod | 1 + doc/man3/OSSL_DECODER.pod | 1 + doc/man3/OSSL_DECODER_CTX.pod | 1 + doc/man3/OSSL_ENCODER.pod | 1 + doc/man3/OSSL_ENCODER_CTX.pod | 1 + doc/man3/OSSL_ERR_STATE_save.pod | 1 + doc/man3/OSSL_HPKE_CTX_new.pod | 3 ++- doc/man3/OSSL_HTTP_REQ_CTX.pod | 1 + doc/man3/OSSL_LIB_CTX.pod | 2 +- doc/man3/OSSL_PARAM_BLD.pod | 1 + doc/man3/OSSL_PARAM_dup.pod | 1 + doc/man3/OSSL_SELF_TEST_new.pod | 1 + doc/man3/OSSL_STORE_INFO.pod | 1 + doc/man3/OSSL_STORE_LOADER.pod | 2 ++ doc/man3/OSSL_STORE_SEARCH.pod | 1 + doc/man3/RSA_meth_new.pod | 2 +- doc/man3/SCT_new.pod | 6 ++++++ doc/man3/TS_RESP_CTX_new.pod | 1 + doc/man3/X509_LOOKUP.pod | 1 + doc/man3/X509_LOOKUP_meth_new.pod | 1 + doc/man3/X509_STORE_new.pod | 1 + doc/man3/X509_dup.pod | 2 +- doc/man3/X509_new.pod | 6 ++++-- 64 files changed, 90 insertions(+), 35 deletions(-) diff --git a/crypto/conf/conf_lib.c b/crypto/conf/conf_lib.c index 24cf40449788c..2a1c992eb2154 100644 --- a/crypto/conf/conf_lib.c +++ b/crypto/conf/conf_lib.c @@ -1,5 +1,5 @@ /* - * Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/crypto/context.c b/crypto/context.c index 84707e7694362..1059a43b2c80a 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -492,7 +492,7 @@ int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file) void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx) { - if (ossl_lib_ctx_is_default(ctx)) + if (ctx == NULL || ossl_lib_ctx_is_default(ctx)) return; #ifndef FIPS_MODULE diff --git a/doc/man3/ASN1_INTEGER_new.pod b/doc/man3/ASN1_INTEGER_new.pod index 4722f880c0b28..fb9f3255d8186 100644 --- a/doc/man3/ASN1_INTEGER_new.pod +++ b/doc/man3/ASN1_INTEGER_new.pod @@ -18,6 +18,7 @@ ASN1_INTEGER_new, ASN1_INTEGER_free - ASN1_INTEGER allocation functions ASN1_INTEGER_new() returns an allocated B structure. ASN1_INTEGER_free() frees up a single B object. +If the argument is NULL, nothing is done. B structure representing the ASN.1 INTEGER type diff --git a/doc/man3/ASYNC_WAIT_CTX_new.pod b/doc/man3/ASYNC_WAIT_CTX_new.pod index 7621a8b3a166b..5293c0af5ed20 100644 --- a/doc/man3/ASYNC_WAIT_CTX_new.pod +++ b/doc/man3/ASYNC_WAIT_CTX_new.pod @@ -178,6 +178,9 @@ operation, normally it is detected by a polling function or an interrupt, as the user code set a callback by calling ASYNC_WAIT_CTX_set_callback() previously, then the registered callback will be called. +ASYNC_WAIT_CTX_free() frees up a single B object. +If the argument is NULL, nothing is done. + =head1 RETURN VALUES ASYNC_WAIT_CTX_new() returns a pointer to the newly allocated B diff --git a/doc/man3/BIO_ADDR.pod b/doc/man3/BIO_ADDR.pod index eb5a4a8fe7fbd..1313d02537954 100644 --- a/doc/man3/BIO_ADDR.pod +++ b/doc/man3/BIO_ADDR.pod @@ -18,7 +18,7 @@ BIO_ADDR_path_string - BIO_ADDR routines BIO_ADDR *BIO_ADDR_new(void); int BIO_ADDR_copy(BIO_ADDR *dst, const BIO_ADDR *src); BIO_ADDR *BIO_ADDR_dup(const BIO_ADDR *ap); - void BIO_ADDR_free(BIO_ADDR *); + void BIO_ADDR_free(BIO_ADDR *ap); void BIO_ADDR_clear(BIO_ADDR *ap); int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, const void *where, size_t wherelen, unsigned short port); @@ -47,7 +47,7 @@ BIO_ADDR_dup() creates a new B, with a copy of the address data in B. BIO_ADDR_free() frees a B created with BIO_ADDR_new() -or BIO_ADDR_dup(); +or BIO_ADDR_dup(). If the argument is NULL, nothing is done. BIO_ADDR_clear() clears any data held within the provided B and sets it back to an uninitialised state. diff --git a/doc/man3/BIO_ADDRINFO.pod b/doc/man3/BIO_ADDRINFO.pod index 626052e7f8b90..d42a8340bad82 100644 --- a/doc/man3/BIO_ADDRINFO.pod +++ b/doc/man3/BIO_ADDRINFO.pod @@ -78,7 +78,7 @@ BIO_ADDRINFO_next() returns the next B in the chain from the given one. BIO_ADDRINFO_free() frees the chain of B starting -with the given one. +with the given one. If the argument is NULL, nothing is done. =head1 RETURN VALUES diff --git a/doc/man3/BIO_meth_new.pod b/doc/man3/BIO_meth_new.pod index 41e36f7c79865..b532190e5a54e 100644 --- a/doc/man3/BIO_meth_new.pod +++ b/doc/man3/BIO_meth_new.pod @@ -100,7 +100,7 @@ additionally have the "descriptor" bit set (B). See the L page for more information. BIO_meth_free() destroys a B structure and frees up any memory -associated with it. +associated with it. If the argument is NULL, nothing is done. BIO_meth_get_write_ex() and BIO_meth_set_write_ex() get and set the function used for writing arbitrary length data to the BIO respectively. This function diff --git a/doc/man3/BN_generate_prime.pod b/doc/man3/BN_generate_prime.pod index b536bcb3b781c..51306410e6c10 100644 --- a/doc/man3/BN_generate_prime.pod +++ b/doc/man3/BN_generate_prime.pod @@ -167,7 +167,8 @@ programs should prefer the "new" style, whilst the "old" style is provided for backwards compatibility purposes. A B structure should be created through a call to BN_GENCB_new(), -and freed through a call to BN_GENCB_free(). +and freed through a call to BN_GENCB_free(). If the argument is NULL, +nothing is done. For "new" style callbacks a BN_GENCB structure should be initialised with a call to BN_GENCB_set(), where B is a B, B is of diff --git a/doc/man3/BUF_MEM_new.pod b/doc/man3/BUF_MEM_new.pod index 262e18f31bfe9..33ca4dfcc98d4 100644 --- a/doc/man3/BUF_MEM_new.pod +++ b/doc/man3/BUF_MEM_new.pod @@ -34,6 +34,7 @@ should be allocated on the secure heap; see L. BUF_MEM_free() frees up an already existing buffer. The data is zeroed before freeing up in case the buffer contains sensitive data. +If the argument is NULL, nothing is done. BUF_MEM_grow() changes the size of an already existing buffer to B. Any data already in the buffer is preserved if it increases in diff --git a/doc/man3/COMP_CTX_new.pod b/doc/man3/COMP_CTX_new.pod index 997f1187f46be..c2eecfb61a89e 100644 --- a/doc/man3/COMP_CTX_new.pod +++ b/doc/man3/COMP_CTX_new.pod @@ -54,7 +54,9 @@ These functions provide compression support for OpenSSL. Compression is used wit the OpenSSL library to support TLS record and certificate compression. COMP_CTX_new() is used to create a new B structure used to compress data. + COMP_CTX_free() is used to free the returned B. +If the argument is NULL, nothing is done. COMP_CTX_get_method() returns the B of the given I. diff --git a/doc/man3/CRYPTO_THREAD_run_once.pod b/doc/man3/CRYPTO_THREAD_run_once.pod index 4fb3774484c3b..2b0d0675ab090 100644 --- a/doc/man3/CRYPTO_THREAD_run_once.pod +++ b/doc/man3/CRYPTO_THREAD_run_once.pod @@ -82,6 +82,7 @@ CRYPTO_THREAD_unlock() unlocks the previously locked I. =item * CRYPTO_THREAD_lock_free() frees the provided I. +If the argument is NULL, nothing is done. =item * diff --git a/doc/man3/CTLOG_STORE_new.pod b/doc/man3/CTLOG_STORE_new.pod index 801b1447e1559..2f1596be425d5 100644 --- a/doc/man3/CTLOG_STORE_new.pod +++ b/doc/man3/CTLOG_STORE_new.pod @@ -52,7 +52,7 @@ The expected format of the file is: Once a CTLOG_STORE is no longer required, it should be passed to CTLOG_STORE_free(). This will delete all of the CTLOGs stored within, along -with the CTLOG_STORE itself. +with the CTLOG_STORE itself. If the argument is NULL, nothing is done. =head1 NOTES diff --git a/doc/man3/CTLOG_new.pod b/doc/man3/CTLOG_new.pod index 30b8068249667..b72c1a4249518 100644 --- a/doc/man3/CTLOG_new.pod +++ b/doc/man3/CTLOG_new.pod @@ -50,7 +50,7 @@ property query string are used. Regardless of whether CTLOG_new() or CTLOG_new_from_base64() is used, it is the caller's responsibility to pass the CTLOG to CTLOG_free() once it is no longer needed. This will delete it and, if created by CTLOG_new(), the EVP_PKEY that -was passed to it. +was passed to it. If the argument to CTLOG_free() is NULL, nothing is done. CTLOG_get0_name() returns the name of the log, as provided when the CTLOG was created. Ownership of the string remains with the CTLOG. diff --git a/doc/man3/CT_POLICY_EVAL_CTX_new.pod b/doc/man3/CT_POLICY_EVAL_CTX_new.pod index bba6778d2debc..45ba91bba070e 100644 --- a/doc/man3/CT_POLICY_EVAL_CTX_new.pod +++ b/doc/man3/CT_POLICY_EVAL_CTX_new.pod @@ -105,7 +105,8 @@ The time should be in milliseconds since the Unix Epoch. Each setter has a matching getter for accessing the current value. When no longer required, the B should be passed to -CT_POLICY_EVAL_CTX_free() to delete it. +CT_POLICY_EVAL_CTX_free() to delete it. If the argument to +CT_POLICY_EVAL_CTX_free() is NULL, nothing is done. =head1 NOTES diff --git a/doc/man3/DH_meth_new.pod b/doc/man3/DH_meth_new.pod index 779a6951678f0..2da003353a1c3 100644 --- a/doc/man3/DH_meth_new.pod +++ b/doc/man3/DH_meth_new.pod @@ -81,7 +81,7 @@ parameter. This might be useful for creating a new B based on an existing one, but with some differences. DH_meth_free() destroys a B structure and frees up any memory -associated with it. +associated with it. If the argument is NULL, nothing is done. DH_meth_get0_name() will return a pointer to the name of this DH_METHOD. This is a pointer to the internal name string and so should not be freed by the diff --git a/doc/man3/DSA_SIG_new.pod b/doc/man3/DSA_SIG_new.pod index 1f532d300065e..7e909f6d6769b 100644 --- a/doc/man3/DSA_SIG_new.pod +++ b/doc/man3/DSA_SIG_new.pod @@ -20,6 +20,7 @@ DSA_SIG_new() allocates an empty B structure. DSA_SIG_free() frees the B structure and its components. The values are erased before the memory is returned to the system. +If the argument is NULL, nothing is done. DSA_SIG_get0() returns internal pointers to the B and B values contained in B. diff --git a/doc/man3/DSA_meth_new.pod b/doc/man3/DSA_meth_new.pod index f8f5a1f022426..45d43632081af 100644 --- a/doc/man3/DSA_meth_new.pod +++ b/doc/man3/DSA_meth_new.pod @@ -110,7 +110,7 @@ parameter. This might be useful for creating a new B based on an existing one, but with some differences. DSA_meth_free() destroys a B structure and frees up any memory -associated with it. +associated with it. If the argument is NULL, nothing is done. DSA_meth_get0_name() will return a pointer to the name of this DSA_METHOD. This is a pointer to the internal name string and so should not be freed by the diff --git a/doc/man3/ECDSA_SIG_new.pod b/doc/man3/ECDSA_SIG_new.pod index 3266c43b550c4..2eecd4ed43c92 100644 --- a/doc/man3/ECDSA_SIG_new.pod +++ b/doc/man3/ECDSA_SIG_new.pod @@ -31,6 +31,7 @@ ECDSA_SIG_new() allocates an empty B structure. Note: before OpenSSL 1.1.0, the I and I components were initialised. ECDSA_SIG_free() frees the B structure I. +If the argument is NULL, nothing is done. ECDSA_SIG_get0() returns internal pointers the I and I values contained in I and stores them in I<*pr> and I<*ps>, respectively. diff --git a/doc/man3/ENGINE_add.pod b/doc/man3/ENGINE_add.pod index 55e5d76fcdb8c..c587f836425e1 100644 --- a/doc/man3/ENGINE_add.pod +++ b/doc/man3/ENGINE_add.pod @@ -227,7 +227,8 @@ references such as; ENGINE_by_id(), ENGINE_get_first(), ENGINE_get_last(), ENGINE_get_next(), ENGINE_get_prev(). All structural references should be released by a corresponding to call to the ENGINE_free() function - the ENGINE object itself will only actually be cleaned up and deallocated when -the last structural reference is released. +the last structural reference is released. If the argument to ENGINE_free() +is NULL, nothing is done. It should also be noted that many ENGINE API function calls that accept a structural reference will internally obtain another reference - typically diff --git a/doc/man3/EVP_ASYM_CIPHER_free.pod b/doc/man3/EVP_ASYM_CIPHER_free.pod index c158ec1ae74a7..ae7a4adc7b382 100644 --- a/doc/man3/EVP_ASYM_CIPHER_free.pod +++ b/doc/man3/EVP_ASYM_CIPHER_free.pod @@ -45,7 +45,7 @@ The returned value must eventually be freed with EVP_ASYM_CIPHER_free(). EVP_ASYM_CIPHER_free() decrements the reference count for the B structure. Typically this structure will have been obtained from an earlier call to EVP_ASYM_CIPHER_fetch(). If the reference count drops to 0 then the -structure is freed. +structure is freed. If the argument is NULL, nothing is done. EVP_ASYM_CIPHER_up_ref() increments the reference count for an B structure. diff --git a/doc/man3/EVP_CIPHER_meth_new.pod b/doc/man3/EVP_CIPHER_meth_new.pod index 35d4db2a6626f..9c7fedf0feb8c 100644 --- a/doc/man3/EVP_CIPHER_meth_new.pod +++ b/doc/man3/EVP_CIPHER_meth_new.pod @@ -80,6 +80,7 @@ EVP_CIPHER_meth_new() creates a new B structure. EVP_CIPHER_meth_dup() creates a copy of B. EVP_CIPHER_meth_free() destroys a B structure. +If the argument is NULL, nothing is done. EVP_CIPHER_meth_set_iv_length() sets the length of the IV. This is only needed when the implemented cipher mode requires it. diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod index d31f845575735..aeae8e81e6d2f 100644 --- a/doc/man3/EVP_DigestInit.pod +++ b/doc/man3/EVP_DigestInit.pod @@ -160,6 +160,7 @@ Increments the reference count for an B structure. Decrements the reference count for the fetched B structure. If the reference count drops to 0 then the structure is freed. +If the argument is NULL, nothing is done. =item EVP_MD_CTX_new() @@ -173,6 +174,7 @@ existing context. =item EVP_MD_CTX_free() Cleans up digest context I and frees up the space allocated to it. +If the argument is NULL, nothing is done. =item EVP_MD_CTX_ctrl() diff --git a/doc/man3/EVP_EncodeInit.pod b/doc/man3/EVP_EncodeInit.pod index 2b9e02e02d79f..2d6e4e8cbfae0 100644 --- a/doc/man3/EVP_EncodeInit.pod +++ b/doc/man3/EVP_EncodeInit.pod @@ -41,7 +41,7 @@ EVP_ENCODE_CTX_new() allocates, initializes and returns a context to be used for the encode/decode functions. EVP_ENCODE_CTX_free() cleans up an encode/decode context B and frees up the -space allocated to it. +space allocated to it. If the argument is NULL, nothing is done. Encoding of binary data is performed in blocks of 48 input bytes (or less for the final block). For each 48 byte input block encoded 64 bytes of base 64 data diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index 357650ac97fd4..b759f9020d936 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -272,6 +272,7 @@ Increments the reference count for an B structure. Decrements the reference count for the fetched B structure. If the reference count drops to 0 then the structure is freed. +If the argument is NULL, nothing is done. =item EVP_CIPHER_CTX_new() @@ -280,9 +281,9 @@ Allocates and returns a cipher context. =item EVP_CIPHER_CTX_free() Clears all information from a cipher context and frees any allocated memory -associated with it, including I itself. This function should be called after -all operations using a cipher are complete so sensitive information does not -remain in memory. +associated with it, including I itself. This function should be called +after all operations using a cipher are complete so sensitive information does +not remain in memory. If the argument is NULL, nothing is done. =item EVP_CIPHER_CTX_dup() diff --git a/doc/man3/EVP_KEM_free.pod b/doc/man3/EVP_KEM_free.pod index 575abc5f5798c..8ddd6dcf64586 100644 --- a/doc/man3/EVP_KEM_free.pod +++ b/doc/man3/EVP_KEM_free.pod @@ -41,6 +41,7 @@ The returned value must eventually be freed with EVP_KEM_free(). EVP_KEM_free() decrements the reference count for the B structure. Typically this structure will have been obtained from an earlier call to EVP_KEM_fetch(). If the reference count drops to 0 then the structure is freed. +If the argument is NULL, nothing is done. EVP_KEM_up_ref() increments the reference count for an B structure. diff --git a/doc/man3/EVP_KEYEXCH_free.pod b/doc/man3/EVP_KEYEXCH_free.pod index 272855ccb3dd8..21e097d079bdf 100644 --- a/doc/man3/EVP_KEYEXCH_free.pod +++ b/doc/man3/EVP_KEYEXCH_free.pod @@ -41,7 +41,7 @@ The returned value must eventually be freed with EVP_KEYEXCH_free(). EVP_KEYEXCH_free() decrements the reference count for the B structure. Typically this structure will have been obtained from an earlier call to EVP_KEYEXCH_fetch(). If the reference count drops to 0 then the -structure is freed. +structure is freed. If the argument is NULL, nothing is done. EVP_KEYEXCH_up_ref() increments the reference count for an B structure. diff --git a/doc/man3/EVP_KEYMGMT.pod b/doc/man3/EVP_KEYMGMT.pod index da03286a996e4..a801ae28e9e5a 100644 --- a/doc/man3/EVP_KEYMGMT.pod +++ b/doc/man3/EVP_KEYMGMT.pod @@ -62,6 +62,7 @@ B I. EVP_KEYMGMT_free() decrements the reference count for the given B I, and when the count reaches zero, frees it. +If the argument is NULL, nothing is done. EVP_KEYMGMT_get0_provider() returns the provider that has this particular implementation. diff --git a/doc/man3/EVP_MD_meth_new.pod b/doc/man3/EVP_MD_meth_new.pod index a553c378f3d7d..9ddc0001ab550 100644 --- a/doc/man3/EVP_MD_meth_new.pod +++ b/doc/man3/EVP_MD_meth_new.pod @@ -74,6 +74,7 @@ EVP_MD_meth_dup() creates a copy of B. EVP_MD_meth_free() decrements the reference count for the B structure. If the reference count drops to 0 then the structure is freed. +If the argument is NULL, nothing is done. EVP_MD_meth_set_input_blocksize() sets the internal input block size for the method B to B bytes. diff --git a/doc/man3/EVP_PKEY_ASN1_METHOD.pod b/doc/man3/EVP_PKEY_ASN1_METHOD.pod index cc50d363daf1e..637fd48010175 100644 --- a/doc/man3/EVP_PKEY_ASN1_METHOD.pod +++ b/doc/man3/EVP_PKEY_ASN1_METHOD.pod @@ -393,7 +393,7 @@ This function is not thread safe, it's recommended to only use this when initializing the application. EVP_PKEY_asn1_free() frees an existing B pointed -by B. +by B. If the argument is NULL, nothing is done. EVP_PKEY_asn1_add0() adds B to the user defined stack of methods unless another B with the same NID is diff --git a/doc/man3/EVP_PKEY_meth_new.pod b/doc/man3/EVP_PKEY_meth_new.pod index db0b09f855fc4..45f868d04d868 100644 --- a/doc/man3/EVP_PKEY_meth_new.pod +++ b/doc/man3/EVP_PKEY_meth_new.pod @@ -407,7 +407,7 @@ of an B is always called by the EVP framework while doing a digest signing operation by calling L. EVP_PKEY_meth_free() frees an existing B pointed by -B. +B. If the argument is NULL, nothing is done. EVP_PKEY_meth_copy() copies an B object from B to B. diff --git a/doc/man3/EVP_SIGNATURE.pod b/doc/man3/EVP_SIGNATURE.pod index 1f534ef33810e..9a1bc31a4037c 100644 --- a/doc/man3/EVP_SIGNATURE.pod +++ b/doc/man3/EVP_SIGNATURE.pod @@ -49,7 +49,7 @@ The returned value must eventually be freed with EVP_SIGNATURE_free(). EVP_SIGNATURE_free() decrements the reference count for the B structure. Typically this structure will have been obtained from an earlier call to EVP_SIGNATURE_fetch(). If the reference count drops to 0 then the -structure is freed. +structure is freed. If the argument is NULL, nothing is done. EVP_SIGNATURE_up_ref() increments the reference count for an B structure. diff --git a/doc/man3/HMAC.pod b/doc/man3/HMAC.pod index 87a567242f60f..b0c640d32e08f 100644 --- a/doc/man3/HMAC.pod +++ b/doc/man3/HMAC.pod @@ -87,7 +87,7 @@ created with HMAC_CTX_new(). HMAC_CTX_free() erases the key and other data from the B, releases any associated resources and finally frees the B -itself. +itself. If the argument is NULL, nothing is done. The following functions may be used if the message is not completely stored in memory: diff --git a/doc/man3/NCONF_new_ex.pod b/doc/man3/NCONF_new_ex.pod index 6861fb198c103..394dbd82d4625 100644 --- a/doc/man3/NCONF_new_ex.pod +++ b/doc/man3/NCONF_new_ex.pod @@ -35,7 +35,7 @@ I is set to NULL then the default value of NCONF_default() is used. NCONF_new() is similar to NCONF_new_ex() but sets the I to NULL. NCONF_free() frees the data associated with I and then frees the I -object. +object. If the argument is NULL, nothing is done. NCONF_load() parses the file named I and adds the values found to I. If an error occurs I and I list the file and line that diff --git a/doc/man3/OCSP_REQUEST_new.pod b/doc/man3/OCSP_REQUEST_new.pod index e34e591fe01be..28779fb07d68b 100644 --- a/doc/man3/OCSP_REQUEST_new.pod +++ b/doc/man3/OCSP_REQUEST_new.pod @@ -29,6 +29,7 @@ OCSP_request_onereq_get0 - OCSP request functions OCSP_REQUEST_new() allocates and returns an empty B structure. OCSP_REQUEST_free() frees up the request structure B. +If the argument is NULL, nothing is done. OCSP_request_add0_id() adds certificate ID B to B. It returns the B structure added so an application can add additional diff --git a/doc/man3/OCSP_cert_to_id.pod b/doc/man3/OCSP_cert_to_id.pod index 298527f6bb25b..abf07db109e00 100644 --- a/doc/man3/OCSP_cert_to_id.pod +++ b/doc/man3/OCSP_cert_to_id.pod @@ -38,6 +38,7 @@ issuer name B, issuer key hash B and serial number B. OCSP_CERTID_free() frees up B. +If the argument is NULL, nothing is done. OCSP_id_cmp() compares B B and B. diff --git a/doc/man3/OCSP_response_status.pod b/doc/man3/OCSP_response_status.pod index 7ff74923a53f3..a7402540b28ec 100644 --- a/doc/man3/OCSP_response_status.pod +++ b/doc/man3/OCSP_response_status.pod @@ -46,6 +46,7 @@ OCSP_response_create() creates and returns an I structure for I and optionally including basic response I. OCSP_RESPONSE_free() frees up OCSP response I. +If the argument is NULL, nothing is done. OCSP_RESPID_set_by_name() sets the name of the OCSP_RESPID to be the same as the subject name in the supplied X509 certificate I for the OCSP responder. diff --git a/doc/man3/OPENSSL_LH_COMPFUNC.pod b/doc/man3/OPENSSL_LH_COMPFUNC.pod index bf3169ae0d599..772f421303a69 100644 --- a/doc/man3/OPENSSL_LH_COMPFUNC.pod +++ b/doc/man3/OPENSSL_LH_COMPFUNC.pod @@ -144,7 +144,7 @@ Then a hash table of B> objects can be created using this: B_free>() frees the B(B>) structure I. Allocated hash table entries will not be freed; consider using B_doall>() to deallocate any remaining entries in the -hash table (see below). +hash table (see below). If the argument is NULL, nothing is done. B_flush>() empties the B(B>) structure I
. New entries can be added to the flushed table. Allocated hash table entries diff --git a/doc/man3/OPENSSL_init_crypto.pod b/doc/man3/OPENSSL_init_crypto.pod index b2d48daeff330..bb0421d9eb2da 100644 --- a/doc/man3/OPENSSL_init_crypto.pod +++ b/doc/man3/OPENSSL_init_crypto.pod @@ -249,6 +249,7 @@ If the B flag is not included, any errors in the configuration file will cause an error return from B or indirectly L. The object can be released with OPENSSL_INIT_free() when done. +If the argument to OPENSSL_INIT_free() is NULL, nothing is done. =head1 NOTES diff --git a/doc/man3/OPENSSL_malloc.pod b/doc/man3/OPENSSL_malloc.pod index 9e8e0eebc0bb1..3c4099bc85962 100644 --- a/doc/man3/OPENSSL_malloc.pod +++ b/doc/man3/OPENSSL_malloc.pod @@ -116,7 +116,8 @@ the returned pointer. OPENSSL_clear_realloc() and OPENSSL_clear_free() should be used when the buffer at B holds sensitive information. The old buffer is filled with zero's by calling OPENSSL_cleanse() -before ultimately calling OPENSSL_free(). +before ultimately calling OPENSSL_free(). If the argument to OPENSSL_free() is +NULL, nothing is done. OPENSSL_cleanse() fills B of size B with a string of 0's. Use OPENSSL_cleanse() with care if the memory is a mapping of a file. diff --git a/doc/man3/OPENSSL_secure_malloc.pod b/doc/man3/OPENSSL_secure_malloc.pod index c5d4bb2dbbb8c..cd18753d6fca3 100644 --- a/doc/man3/OPENSSL_secure_malloc.pod +++ b/doc/man3/OPENSSL_secure_malloc.pod @@ -82,13 +82,15 @@ If CRYPTO_secure_malloc_init() is not called, this is equivalent to calling OPENSSL_free(). It exists for consistency with OPENSSL_secure_malloc() , and is a macro that expands to CRYPTO_secure_free() and adds the C<__FILE__> -and C<__LINE__> parameters.. +and C<__LINE__> parameters.. If the argument to OPENSSL_secure_free() +is NULL, nothing is done. OPENSSL_secure_clear_free() is similar to OPENSSL_secure_free() except that it has an additional C parameter which is used to clear the memory if it was not allocated from the secure heap. If CRYPTO_secure_malloc_init() is not called, this is equivalent to -calling OPENSSL_clear_free(). +calling OPENSSL_clear_free(). If the argument to OPENSSL_secure_clear_free() +is NULL, nothing is done. OPENSSL_secure_actual_size() tells the actual size allocated to the pointer; implementations may allocate more space than initially diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index b9d89dbc3d831..3af2c897154f9 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -190,6 +190,7 @@ the message timeout is set to 120 seconds, and the proof-of-possession method is set to OSSL_CRMF_POPO_SIGNATURE. OSSL_CMP_CTX_free() deallocates an OSSL_CMP_CTX structure. +If the argument is NULL, nothing is done. OSSL_CMP_CTX_reinit() prepares the given I for a further transaction by clearing the internal CMP transaction (aka session) status, PKIStatusInfo, diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod index d1fd7e83b1ab8..7222a898e8e7b 100644 --- a/doc/man3/OSSL_CMP_SRV_CTX_new.pod +++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod @@ -114,6 +114,7 @@ associated with the library context I and property query string I, both of which may be NULL to select the defaults. OSSL_CMP_SRV_CTX_free() deletes the given I. +If the argument is NULL, nothing is done. OSSL_CMP_SRV_CTX_init() sets in the given I a custom server context pointer as well as callback functions performing the specific processing of CMP diff --git a/doc/man3/OSSL_DECODER.pod b/doc/man3/OSSL_DECODER.pod index c58ebf462c71a..25f5e50dceb60 100644 --- a/doc/man3/OSSL_DECODER.pod +++ b/doc/man3/OSSL_DECODER.pod @@ -61,6 +61,7 @@ I. OSSL_DECODER_free() decrements the reference count for the given I, and when the count reaches zero, frees it. +If the argument is NULL, nothing is done. OSSL_DECODER_get0_provider() returns the provider of the given I. diff --git a/doc/man3/OSSL_DECODER_CTX.pod b/doc/man3/OSSL_DECODER_CTX.pod index 034cf12c73894..61ffc2e1f6ef4 100644 --- a/doc/man3/OSSL_DECODER_CTX.pod +++ b/doc/man3/OSSL_DECODER_CTX.pod @@ -126,6 +126,7 @@ decoders that have been added to the I so far. Parameters that an implementation doesn't recognise should be ignored by it. OSSL_DECODER_CTX_free() frees the given context I. +If the argument is NULL, nothing is done. OSSL_DECODER_CTX_add_decoder() populates the B I with a decoder, to be used to attempt to decode some encoded input. diff --git a/doc/man3/OSSL_ENCODER.pod b/doc/man3/OSSL_ENCODER.pod index d7271547287e1..e5e1598808cac 100644 --- a/doc/man3/OSSL_ENCODER.pod +++ b/doc/man3/OSSL_ENCODER.pod @@ -61,6 +61,7 @@ I. OSSL_ENCODER_free() decrements the reference count for the given I, and when the count reaches zero, frees it. +If the argument is NULL, nothing is done. OSSL_ENCODER_get0_provider() returns the provider of the given I. diff --git a/doc/man3/OSSL_ENCODER_CTX.pod b/doc/man3/OSSL_ENCODER_CTX.pod index b4b5f61e13040..75dcb83af7943 100644 --- a/doc/man3/OSSL_ENCODER_CTX.pod +++ b/doc/man3/OSSL_ENCODER_CTX.pod @@ -102,6 +102,7 @@ with an L array I. Parameters that the implementation doesn't recognise should be ignored. OSSL_ENCODER_CTX_free() frees the given context I. +If the argument is NULL, nothing is done. OSSL_ENCODER_CTX_add_encoder() populates the B I with a encoder, to be used to encode an input object. diff --git a/doc/man3/OSSL_ERR_STATE_save.pod b/doc/man3/OSSL_ERR_STATE_save.pod index 93c4b8f473604..379a93aa87aa6 100644 --- a/doc/man3/OSSL_ERR_STATE_save.pod +++ b/doc/man3/OSSL_ERR_STATE_save.pod @@ -46,6 +46,7 @@ for all the added entries. Any allocated data in the saved error entries is duplicated on adding to the thread state. OSSL_ERR_STATE_free() frees the saved error state I. +If the argument is NULL, nothing is done. =head1 RETURN VALUES diff --git a/doc/man3/OSSL_HPKE_CTX_new.pod b/doc/man3/OSSL_HPKE_CTX_new.pod index e291ec7e48383..b3ad66e05f527 100644 --- a/doc/man3/OSSL_HPKE_CTX_new.pod +++ b/doc/man3/OSSL_HPKE_CTX_new.pod @@ -240,7 +240,8 @@ I and I are used when fetching algorithms from providers and may be set to NULL. OSSL_HPKE_CTX_free() frees the I B that was created -previously by a call to OSSL_HPKE_CTX_new(). +previously by a call to OSSL_HPKE_CTX_new(). If the argument to +OSSL_HPKE_CTX_free() is NULL, nothing is done. =head2 Sender APIs diff --git a/doc/man3/OSSL_HTTP_REQ_CTX.pod b/doc/man3/OSSL_HTTP_REQ_CTX.pod index 105ed60e534f2..2a1485cbe9a26 100644 --- a/doc/man3/OSSL_HTTP_REQ_CTX.pod +++ b/doc/man3/OSSL_HTTP_REQ_CTX.pod @@ -75,6 +75,7 @@ which collects the HTTP request header lines. OSSL_HTTP_REQ_CTX_free() frees up the HTTP request context I. The I is not free'd, I will be free'd if I is set. +If the argument is NULL, nothing is done. OSSL_HTTP_REQ_CTX_set_request_line() adds the 1st HTTP request line to I. The HTTP method is determined by I, diff --git a/doc/man3/OSSL_LIB_CTX.pod b/doc/man3/OSSL_LIB_CTX.pod index a464475a14771..e594a95fd48cd 100644 --- a/doc/man3/OSSL_LIB_CTX.pod +++ b/doc/man3/OSSL_LIB_CTX.pod @@ -91,7 +91,7 @@ from a configuration. This function must not be called concurrently from multiple threads on a single I. OSSL_LIB_CTX_free() frees the given I, unless it happens to be the -default OpenSSL library context. +default OpenSSL library context. If the argument is NULL, nothing is done. OSSL_LIB_CTX_get0_global_default() returns a concrete (non NULL) reference to the global default library context. diff --git a/doc/man3/OSSL_PARAM_BLD.pod b/doc/man3/OSSL_PARAM_BLD.pod index 639f7bb59537e..d1ac7b49639c6 100644 --- a/doc/man3/OSSL_PARAM_BLD.pod +++ b/doc/man3/OSSL_PARAM_BLD.pod @@ -53,6 +53,7 @@ so that values can be added. Any existing values are cleared. OSSL_PARAM_BLD_free() deallocates the memory allocates by OSSL_PARAM_BLD_new(). +If the argument is NULL, nothing is done. OSSL_PARAM_BLD_to_param() converts a built up OSSL_PARAM_BLD structure I into an allocated OSSL_PARAM array. diff --git a/doc/man3/OSSL_PARAM_dup.pod b/doc/man3/OSSL_PARAM_dup.pod index 4ae33faf1e4e8..dbaeed9a533e2 100644 --- a/doc/man3/OSSL_PARAM_dup.pod +++ b/doc/man3/OSSL_PARAM_dup.pod @@ -32,6 +32,7 @@ array that have the same key. OSSL_PARAM_free() frees the parameter array I that was created using OSSL_PARAM_dup(), OSSL_PARAM_merge() or OSSL_PARAM_BLD_to_param(). +If the argument to OSSL_PARAM_free() is NULL, nothing is done. =head1 RETURN VALUES diff --git a/doc/man3/OSSL_SELF_TEST_new.pod b/doc/man3/OSSL_SELF_TEST_new.pod index 4c4b10fca96ad..dbacf9556a35f 100644 --- a/doc/man3/OSSL_SELF_TEST_new.pod +++ b/doc/man3/OSSL_SELF_TEST_new.pod @@ -32,6 +32,7 @@ The callback I may be triggered multiple times by a self test to indicate different phases. OSSL_SELF_TEST_free() frees the space allocated by OSSL_SELF_TEST_new(). +If the argument is NULL, nothing is done. OSSL_SELF_TEST_onbegin() may be inserted at the start of a block of self test code. It can be used for diagnostic purposes. diff --git a/doc/man3/OSSL_STORE_INFO.pod b/doc/man3/OSSL_STORE_INFO.pod index 39bb93fbf5f21..546ec54c70c20 100644 --- a/doc/man3/OSSL_STORE_INFO.pod +++ b/doc/man3/OSSL_STORE_INFO.pod @@ -101,6 +101,7 @@ holds if the B type (as returned by OSSL_STORE_INFO_get_type()) matches the function, otherwise NULL. OSSL_STORE_INFO_free() frees a B and its contained type. +If the argument is NULL, nothing is done. OSSL_STORE_INFO_new_NAME() , OSSL_STORE_INFO_new_PARAMS(), , OSSL_STORE_INFO_new_PUBKEY(), OSSL_STORE_INFO_new_PKEY(), diff --git a/doc/man3/OSSL_STORE_LOADER.pod b/doc/man3/OSSL_STORE_LOADER.pod index 176d39f6981cf..89c60f1ef19a2 100644 --- a/doc/man3/OSSL_STORE_LOADER.pod +++ b/doc/man3/OSSL_STORE_LOADER.pod @@ -125,6 +125,7 @@ I. OSSL_STORE_LOADER_free() decrements the reference count for the given I, and when the count reaches zero, frees it. +If the argument is NULL, nothing is done. OSSL_STORE_LOADER_get0_provider() returns the provider of the given I. @@ -296,6 +297,7 @@ OSSL_STORE_LOADER_set_close() sets the closing function for the I. OSSL_STORE_LOADER_free() frees the given I. +If the argument is NULL, nothing is done. OSSL_STORE_register_loader() register the given I and thereby makes it available for use with OSSL_STORE_open(), diff --git a/doc/man3/OSSL_STORE_SEARCH.pod b/doc/man3/OSSL_STORE_SEARCH.pod index 79186b08997e0..021ed0c8baa65 100644 --- a/doc/man3/OSSL_STORE_SEARCH.pod +++ b/doc/man3/OSSL_STORE_SEARCH.pod @@ -75,6 +75,7 @@ criterion, so they must have at least the same life time as the created B. OSSL_STORE_SEARCH_free() is used to free the B. +If the argument is NULL, nothing is done. =head2 Loader Functions diff --git a/doc/man3/RSA_meth_new.pod b/doc/man3/RSA_meth_new.pod index 6c8eda1615b02..7372358fa7194 100644 --- a/doc/man3/RSA_meth_new.pod +++ b/doc/man3/RSA_meth_new.pod @@ -147,7 +147,7 @@ passed as a parameter. This might be useful for creating a new B based on an existing one, but with some differences. RSA_meth_free() destroys an B structure and frees up any -memory associated with it. +memory associated with it. If the argument is NULL, nothing is done. RSA_meth_get0_name() will return a pointer to the name of this RSA_METHOD. This is a pointer to the internal name string and so diff --git a/doc/man3/SCT_new.pod b/doc/man3/SCT_new.pod index 235762721992b..ecaa25e1d221d 100644 --- a/doc/man3/SCT_new.pod +++ b/doc/man3/SCT_new.pod @@ -166,6 +166,12 @@ SCT_set_source() can be used to record where the SCT was found (TLS extension, X.509 certificate extension or OCSP response). This is not required for verifying the SCT. +SCT_free() frees the specified SCT. +If the argument is NULL, nothing is done. + +SCT_LIST_free() frees the specified stack of SCTs. +If the argument is NULL, nothing is done. + =head1 NOTES Some of the setters return int, instead of void. These will all return 1 on diff --git a/doc/man3/TS_RESP_CTX_new.pod b/doc/man3/TS_RESP_CTX_new.pod index 725a1921d133e..3b5bfc65ba780 100644 --- a/doc/man3/TS_RESP_CTX_new.pod +++ b/doc/man3/TS_RESP_CTX_new.pod @@ -27,6 +27,7 @@ and property query to NULL. This results in the default (NULL) library context being used for any operations requiring algorithm fetches. TS_RESP_CTX_free() frees the B object I. +If the argument is NULL, nothing is done. =head1 RETURN VALUES diff --git a/doc/man3/X509_LOOKUP.pod b/doc/man3/X509_LOOKUP.pod index f888d28467fba..5d3d12a4b83e8 100644 --- a/doc/man3/X509_LOOKUP.pod +++ b/doc/man3/X509_LOOKUP.pod @@ -85,6 +85,7 @@ X509_LOOKUP_shutdown() tears down the internal state and resources of the given B. X509_LOOKUP_free() destructs the given B. +If the argument is NULL, nothing is done. X509_LOOKUP_set_method_data() and X509_LOOKUP_get_method_data() associates and retrieves a pointer to application data to and from the diff --git a/doc/man3/X509_LOOKUP_meth_new.pod b/doc/man3/X509_LOOKUP_meth_new.pod index 49776e7126072..3d2a070c6c3d6 100644 --- a/doc/man3/X509_LOOKUP_meth_new.pod +++ b/doc/man3/X509_LOOKUP_meth_new.pod @@ -110,6 +110,7 @@ be given a human-readable string containing a brief description of the lookup method. X509_LOOKUP_meth_free() destroys a B structure. +If the argument is NULL, nothing is done. X509_LOOKUP_get_new_item() and X509_LOOKUP_set_new_item() get and set the function that is called when an B object is created with diff --git a/doc/man3/X509_STORE_new.pod b/doc/man3/X509_STORE_new.pod index 59b5160f39ba7..22ffad570341b 100644 --- a/doc/man3/X509_STORE_new.pod +++ b/doc/man3/X509_STORE_new.pod @@ -27,6 +27,7 @@ X509_STORE_lock() locks the store from modification by other threads, X509_STORE_unlock() unlocks it. X509_STORE_free() frees up a single X509_STORE object. +If the argument is NULL, nothing is done. =head1 RETURN VALUES diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index f350d74a7196f..6ffcca79db142 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -412,7 +412,7 @@ followed by I, which re-builds the cached data. B_free>() releases the object and all pointers and sub-objects -within it. +within it. If the argument is NULL, nothing is done. B_print_ctx>() prints the object I on the specified BIO I. Each line will be prefixed with I spaces. diff --git a/doc/man3/X509_new.pod b/doc/man3/X509_new.pod index dcebb55fe6ad4..7fbbfa9e8dbd9 100644 --- a/doc/man3/X509_new.pod +++ b/doc/man3/X509_new.pod @@ -21,7 +21,7 @@ OSSL_STACK_OF_X509_free =head1 DESCRIPTION -The X509 ASN1 allocation routines, allocate and free an +The X509 ASN1 allocation routines allocate and free an X509 structure, which represents an X509 certificate. X509_new_ex() allocates and initializes a X509 structure with a @@ -36,7 +36,8 @@ and property query to NULL. This results in the default (NULL) library context being used for any X509 operations requiring algorithm fetches. X509_free() decrements the reference count of B structure B and -frees it up if the reference count is zero. If B is NULL nothing is done. +frees it up if the reference count is zero. If the argument is NULL, +nothing is done. X509_up_ref() increments the reference count of B. @@ -45,6 +46,7 @@ chain B and returns a copy of the stack, or an empty stack if B is NULL. OSSL_STACK_OF_X509_free() deallocates the given list of pointers to certificates after calling X509_free() on all its elements. +If the argument is NULL, nothing is done. =head1 NOTES From fbd6609bb21b125c9454d07c484d166a33b4815b Mon Sep 17 00:00:00 2001 From: sgzmd Date: Tue, 25 Jun 2024 15:53:32 +0100 Subject: [PATCH 066/138] Free appname if it was set after initializing crypto. Fixes #24729 CLA: trivial Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Bernd Edlinger Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24730) --- crypto/conf/conf_sap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/conf/conf_sap.c b/crypto/conf/conf_sap.c index 3019bcf31af81..bfe3a5f6f4d5e 100644 --- a/crypto/conf/conf_sap.c +++ b/crypto/conf/conf_sap.c @@ -38,6 +38,8 @@ void OPENSSL_config(const char *appname) settings.appname = strdup(appname); settings.flags = DEFAULT_CONF_MFLAGS; OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, &settings); + + free(settings.appname); } #endif From 41c1b6f0a549f2a6401bf06c52badd482b6bd7bc Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Sat, 22 Jun 2024 19:48:42 +0000 Subject: [PATCH 067/138] ossl_print_attribute_value(): Multiple minor fixes for style and other errors - use correct return values - do not modify pointer in the atrtribute after decoding with d2i_X509_NAME() - make oid parameter const in print_oid - use OPENSSL_buf2hexstr_ex - simplify return code translation from BIO_printf() Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24725) --- crypto/x509/x_attrib.c | 120 ++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c index 4bae377905886..5446e0c2fe57f 100644 --- a/crypto/x509/x_attrib.c +++ b/crypto/x509/x_attrib.c @@ -60,38 +60,28 @@ X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value) static int print_hex(BIO *out, unsigned char *buf, int len) { - int i; + int result = -1; + char *hexbuf; + int hexlen = len * 2 + 1; - for (i = 0; i < len; i++) { - if (BIO_printf(out, "%02X ", buf[i]) <= 0) { - return 0; - } - } - return 1; -} + hexbuf = OPENSSL_malloc(hexlen); + if (hexbuf == NULL) + return 0; + result = OPENSSL_buf2hexstr_ex(hexbuf, hexlen, NULL, buf, len, ':'); + if (result != 1) + goto err; + if ((result = BIO_puts(out, hexbuf)) <= 0) + goto err; -static int asn1_integer_print_bio(BIO *bio, const ASN1_INTEGER *num) -{ - BIGNUM *num_bn; - int result = 0; - char *hex; - - num_bn = ASN1_INTEGER_to_BN(num, NULL); - if (num_bn == NULL) - return -1; - if ((hex = BN_bn2hex(num_bn)) != NULL) { - result = BIO_write(bio, "0x", 2) > 0; - result = result && BIO_write(bio, hex, strlen(hex)) > 0; - OPENSSL_free(hex); - } else { - return -1; - } - BN_free(num_bn); + OPENSSL_free(hexbuf); + return 1; - return result; + err: + OPENSSL_free(hexbuf); + return 0; } -static int print_oid (BIO *out, ASN1_OBJECT *oid) { +static int print_oid(BIO *out, const ASN1_OBJECT *oid) { const char *ln; char objbuf[80]; int rc; @@ -102,9 +92,7 @@ static int print_oid (BIO *out, ASN1_OBJECT *oid) { rc = (ln != NULL) ? BIO_printf(out, "%s (%s)", objbuf, ln) : BIO_printf(out, "%s", objbuf); - if (rc < 0) - return 0; - return 1; + return (rc >= 0); } int ossl_print_attribute_value(BIO *out, @@ -134,19 +122,19 @@ int ossl_print_attribute_value(BIO *out, case NID_associatedName: case NID_dITRedirect: case NID_owner: + /* + * d2i_ functions increment the ppin pointer. See doc/man3/d2i_X509.pod. + * This preserves the original pointer. We don't want to corrupt this + * value. + */ value = av->value.sequence->data; xn = d2i_X509_NAME(NULL, - (const unsigned char**)&(av->value.sequence->data), + (const unsigned char**)&value, av->value.sequence->length); if (xn == NULL) { BIO_puts(out, "(COULD NOT DECODE DISTINGUISHED NAME)\n"); return 0; } - /* - * d2i_ functions increment the ppin pointer. See doc/man3/d2i_X509.pod. - * This resets the pointer. We don't want to corrupt this value. - */ - av->value.sequence->data = value; if (X509_NAME_print_ex(out, xn, indent, XN_FLAG_SEP_CPLUS_SPC) <= 0) return 0; X509_NAME_free(xn); @@ -159,49 +147,39 @@ int ossl_print_attribute_value(BIO *out, switch (av->type) { case V_ASN1_BOOLEAN: if (av->value.boolean) { - return BIO_printf(out, "%*sTRUE", indent, ""); + return BIO_printf(out, "%*sTRUE", indent, "") >= 4; } else { - return BIO_printf(out, "%*sFALSE", indent, ""); + return BIO_printf(out, "%*sFALSE", indent, "") >= 5; } case V_ASN1_INTEGER: - if (BIO_printf(out, "%*s", indent, "") <= 0) - return 0; - if (ASN1_INTEGER_get_int64(&int_val, av->value.integer) > 0) { - return BIO_printf(out, "%lld", (long long int)int_val); - } else { - str = av->value.integer; - return asn1_integer_print_bio(out, str); - } - case V_ASN1_ENUMERATED: - if (BIO_printf(out, "%*s", indent, "") <= 0) + if (BIO_printf(out, "%*s", indent, "") < 0) return 0; - if (ASN1_ENUMERATED_get_int64(&int_val, av->value.enumerated) > 0) { - return BIO_printf(out, "%lld", (long long int)int_val); - } else { - str = av->value.enumerated; - return asn1_integer_print_bio(out, str); + if (ASN1_ENUMERATED_get_int64(&int_val, av->value.integer) > 0) { + return BIO_printf(out, "%lld", (long long int)int_val) > 0; } + str = av->value.integer; + return print_hex(out, str->data, str->length); case V_ASN1_BIT_STRING: - if (BIO_printf(out, "%*s", indent, "") <= 0) + if (BIO_printf(out, "%*s", indent, "") < 0) return 0; return print_hex(out, av->value.bit_string->data, - av->value.bit_string->length); + av->value.bit_string->length); case V_ASN1_OCTET_STRING: case V_ASN1_VIDEOTEXSTRING: - if (BIO_printf(out, "%*s", indent, "") <= 0) + if (BIO_printf(out, "%*s", indent, "") < 0) return 0; return print_hex(out, av->value.octet_string->data, - av->value.octet_string->length); + av->value.octet_string->length); case V_ASN1_NULL: - return BIO_printf(out, "%*sNULL", indent, ""); + return BIO_printf(out, "%*sNULL", indent, "") >= 4; case V_ASN1_OBJECT: - if (BIO_printf(out, "%*s", indent, "") <= 0) + if (BIO_printf(out, "%*s", indent, "") < 0) return 0; return print_oid(out, av->value.object); @@ -215,7 +193,7 @@ int ossl_print_attribute_value(BIO *out, case V_ASN1_OBJECT_DESCRIPTOR: return BIO_printf(out, "%*s%.*s", indent, "", av->value.generalstring->length, - av->value.generalstring->data); + av->value.generalstring->data) >= 0; /* EXTERNAL would go here. */ /* EMBEDDED PDV would go here. */ @@ -223,21 +201,21 @@ int ossl_print_attribute_value(BIO *out, case V_ASN1_UTF8STRING: return BIO_printf(out, "%*s%.*s", indent, "", av->value.utf8string->length, - av->value.utf8string->data); + av->value.utf8string->data) >= 0; case V_ASN1_REAL: - return BIO_printf(out, "%*sREAL", indent, ""); + return BIO_printf(out, "%*sREAL", indent, "") >= 4; /* RELATIVE-OID would go here. */ /* TIME would go here. */ case V_ASN1_SEQUENCE: return ASN1_parse_dump(out, av->value.sequence->data, - av->value.sequence->length, indent, 1); + av->value.sequence->length, indent, 1) > 0; case V_ASN1_SET: return ASN1_parse_dump(out, av->value.set->data, - av->value.set->length, indent, 1); + av->value.set->length, indent, 1) > 0; /* * UTCTime ::= [UNIVERSAL 23] IMPLICIT VisibleString @@ -250,22 +228,22 @@ int ossl_print_attribute_value(BIO *out, case V_ASN1_NUMERICSTRING: return BIO_printf(out, "%*s%.*s", indent, "", av->value.visiblestring->length, - av->value.visiblestring->data); + av->value.visiblestring->data) >= 0; case V_ASN1_PRINTABLESTRING: return BIO_printf(out, "%*s%.*s", indent, "", av->value.printablestring->length, - av->value.printablestring->data); + av->value.printablestring->data) >= 0; case V_ASN1_T61STRING: return BIO_printf(out, "%*s%.*s", indent, "", av->value.t61string->length, - av->value.t61string->data); + av->value.t61string->data) >= 0; case V_ASN1_IA5STRING: return BIO_printf(out, "%*s%.*s", indent, "", av->value.ia5string->length, - av->value.ia5string->data); + av->value.ia5string->data) >= 0; /* UniversalString would go here. */ /* CHARACTER STRING would go here. */ @@ -279,6 +257,10 @@ int ossl_print_attribute_value(BIO *out, /* Would it be approriate to just hexdump? */ default: - return BIO_printf(out, "%*s", indent, "", av->type); + return BIO_printf(out, + "%*s", + indent, + "", + av->type) >= 0; } } From 940059d545981017fffba9e8eeb9e52ee7f4cda0 Mon Sep 17 00:00:00 2001 From: Drokov Pavel Date: Fri, 12 Jan 2024 02:32:06 -0500 Subject: [PATCH 068/138] p12_npas.c: Remove call with unused return value CLA: trivial Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23275) --- crypto/pkcs12/p12_npas.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crypto/pkcs12/p12_npas.c b/crypto/pkcs12/p12_npas.c index 78be2b5a8c0c4..37abb3821d4b3 100644 --- a/crypto/pkcs12/p12_npas.c +++ b/crypto/pkcs12/p12_npas.c @@ -212,8 +212,7 @@ static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter, if (pbe2 == NULL) goto done; - X509_ALGOR_get0(&aoid, &aparamtype, &aparam, pbe2->keyfunc); - pbenid = OBJ_obj2nid(aoid); + X509_ALGOR_get0(NULL, &aparamtype, &aparam, pbe2->keyfunc); X509_ALGOR_get0(&aoid, NULL, NULL, pbe2->encryption); encnid = OBJ_obj2nid(aoid); From 68c7575afc5ec33fd44c9c1c571d882d6095c8ef Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 16:20:02 -0400 Subject: [PATCH 069/138] Enable ipv6 use if available Recently, it appears alpine containers added ipv6, which breaks our ipv6 ssl old tests because the perl test recipie runs the ipv6 test based on runtime availability, even if the build time selection is to disable ipv6. Fix it by modifying the os zoo ci run to enable ipv6 in the build if its available on the container Fixes #24739 Reviewed-by: Bernd Edlinger Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24744) --- .github/workflows/os-zoo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-zoo.yml b/.github/workflows/os-zoo.yml index cd16a778ab5c8..b031ce2253a65 100644 --- a/.github/workflows/os-zoo.yml +++ b/.github/workflows/os-zoo.yml @@ -37,7 +37,7 @@ jobs: ref: ${{ matrix.branch }} - name: config run: | - ./config --banner=Configured no-shared -Wall -Werror enable-fips --strict-warnings -DOPENSSL_USE_IPV6=0 \ + ./config --banner=Configured no-shared -Wall -Werror enable-fips --strict-warnings \ ${EXTRA_CFLAGS} - name: config dump run: ./configdata.pm --dump From 15974897b7b94014e0165d7d906e31ca010e2861 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 16:23:04 -0400 Subject: [PATCH 070/138] Disable default case checks on clang 18 Recent updates in CI have upgraded clang to clang-18, which gripes when it finds a switch statement without a default case. We should add those cases in, but since we have a lot of those, and CI is currently failing, disable the check until we get them fixed up Fixes #24739 Reviewed-by: Bernd Edlinger Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24744) --- .github/workflows/os-zoo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-zoo.yml b/.github/workflows/os-zoo.yml index b031ce2253a65..53e90215d5071 100644 --- a/.github/workflows/os-zoo.yml +++ b/.github/workflows/os-zoo.yml @@ -27,7 +27,7 @@ jobs: image: docker.io/library/alpine:${{ matrix.tag }} env: # https://www.openwall.com/lists/musl/2022/02/16/14 - EXTRA_CFLAGS: ${{ matrix.cc == 'clang' && '-Wno-sign-compare' || '' }} + EXTRA_CFLAGS: ${{ matrix.cc == 'clang' && '-Wno-sign-compare -Wno-switch-default' || '' }} CC: ${{ matrix.cc }} steps: - name: install packages From 93a644d14aeed02a33a1191c0de540103e6cf307 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 16:24:48 -0400 Subject: [PATCH 071/138] Remove macos-11 from CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent build failure on os-zoo reports: A brownout will take place on June, 8:00 AM – 2:00 PM EST to raise awareness of the upcoming macOS-11 environment removal. It appears that github is retiring macos-11, so we may as well remove it to prepare Fixes #24739 Reviewed-by: Bernd Edlinger Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24744) --- .github/workflows/os-zoo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-zoo.yml b/.github/workflows/os-zoo.yml index 53e90215d5071..9dfc2faac80de 100644 --- a/.github/workflows/os-zoo.yml +++ b/.github/workflows/os-zoo.yml @@ -105,7 +105,7 @@ jobs: fail-fast: false matrix: branch: [openssl-3.0, openssl-3.1, master] - os: [macos-11, macos-12, macos-13, macos-14] + os: [macos-12, macos-13, macos-14] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 7afa7731e924d5ac10fc992d8cd777f407d33af9 Mon Sep 17 00:00:00 2001 From: sanumesh Date: Tue, 11 Jun 2024 09:47:07 -0500 Subject: [PATCH 072/138] Add aix-clang and aix64-clang configuration Reviewed-by: Neil Horman Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24609) --- Configurations/10-main.conf | 36 ++++++++++++++++++++++++++++++++++++ Configure | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf index ca70d58e19873..cba57b41273f8 100644 --- a/Configurations/10-main.conf +++ b/Configurations/10-main.conf @@ -1414,6 +1414,25 @@ my %targets = ( AR => add("-X32"), RANLIB => add("-X32"), }, + # To enable openxl compiler for aix + # If 17.1 openxl runtime is available, -latomic can be used + # instead of -DBROKEN_CLANG_ATOMICS + "aix-clang" => { + inherit_from => [ "aix-common" ], + CC => "ibm-clang", + CFLAGS => picker(debug => "-O0 -g", + release => "-O"), + cflags => combine("-Wno-implicit-function-declaration -mcmodel=large -DBROKEN_CLANG_ATOMICS", + threads("-pthread")), + ex_libs => add(threads("-pthread")), + bn_ops => "BN_LLONG RC4_CHAR", + asm_arch => 'ppc32', + perlasm_scheme => "aix32", + shared_cflag => "-fpic", + shared_ldflag => add("-shared"), + AR => add("-X32"), + RANLIB => add("-X32"), + }, # shared_target of "aix-solib" builds shared libraries packaged # without archives. This improves the behavior of inter-library # references (libssl depending on libcrypto) when building with @@ -1445,6 +1464,23 @@ my %targets = ( AR => add("-X64"), RANLIB => add("-X64"), }, + "aix64-clang" => { + inherit_from => [ "aix-common" ], + CC => "ibm-clang", + CFLAGS => picker(debug => "-O0 -g", + release => "-O"), + cflags => combine("-maix64 -Wno-implicit-function-declaration -mcmodel=large", + threads("-pthread")), + ex_libs => add(threads("-pthread")), + bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", + asm_arch => 'ppc64', + perlasm_scheme => "aix64", + shared_cflag => "-fpic", + shared_ldflag => add("-shared"), + shared_extension => "64.so.\$(SHLIB_VERSION_NUMBER)", + AR => add("-X64"), + RANLIB => add("-X64"), + }, "aix64-cc-solib" => { inherit_from => [ "aix64-cc" ], shared_target => "aix-solib", diff --git a/Configure b/Configure index 73a95a000ddaf..71322996111d0 100755 --- a/Configure +++ b/Configure @@ -1673,7 +1673,7 @@ if (!$disabled{makedepend}) { disable('unavailable', 'makedepend') unless $config{makedep_scheme}; } -if (!$disabled{asm} && !$predefined_C{__MACH__} && $^O ne 'VMS') { +if (!$disabled{asm} && !$predefined_C{__MACH__} && $^O ne 'VMS' && !$predefined_C{_AIX}) { # probe for -Wa,--noexecstack option... if ($predefined_C{__clang__}) { # clang has builtin assembler, which doesn't recognize --help, From 1eb122aa0ca152dc564e61674caf3f11acd85b57 Mon Sep 17 00:00:00 2001 From: Pauli Date: Thu, 27 Jun 2024 10:08:05 +1000 Subject: [PATCH 073/138] Clarify DRBG seeding. There is a legacy code path that OpenSSL won't use anymore but applications could. Add a comment indicating this to avoid confusion for people not intimately conversant with the nuances in the RNG code. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24745) --- providers/implementations/rands/drbg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c index 3e88e7d064841..253131b10dbf2 100644 --- a/providers/implementations/rands/drbg.c +++ b/providers/implementations/rands/drbg.c @@ -202,6 +202,11 @@ static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, return ossl_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, prediction_resistance); #else + /* + * In normal use (i.e. OpenSSL's own uses), this is never called. + * Outside of the FIPS provider, OpenSSL sets its DRBGs up so that + * they always have a parent. This remains purely for legacy reasons. + */ return ossl_prov_get_entropy(drbg->provctx, pout, entropy, min_len, max_len); #endif From 5a9c90b1e59b2c368876229862fbff29f2bcf006 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 27 Jun 2024 08:30:28 +0200 Subject: [PATCH 074/138] OpenSSL::Test: Avoid running IPv6 related tests if IPv6 was explicitly disabled It's possible to disable IPv6 explicitly when configuring OpenSSL. In that case, IPv6 related tests should be skipped. This is solved by having OpenSSL::Test::Utils::have_IPv6() check configuration first, before trying to determine if the machine supports IPv6. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24748) --- util/perl/OpenSSL/Test/Utils.pm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/util/perl/OpenSSL/Test/Utils.pm b/util/perl/OpenSSL/Test/Utils.pm index dcff6a5c99679..90469cd6fe3dc 100644 --- a/util/perl/OpenSSL/Test/Utils.pm +++ b/util/perl/OpenSSL/Test/Utils.pm @@ -72,6 +72,8 @@ Returns an item from the %config hash in \$TOP/configdata.pm. =item B Return true if IPv4 / IPv6 is possible to use on the current system. +Additionally, B also checks how OpenSSL was configured, +i.e. if IPv6 was explicitly disabled with -DOPENSSL_USE_IPv6=0. =back @@ -80,6 +82,7 @@ Return true if IPv4 / IPv6 is possible to use on the current system. our %available_protocols; our %disabled; our %config; +our %target; my $configdata_loaded = 0; sub load_configdata { @@ -91,6 +94,7 @@ sub load_configdata { %available_protocols = %configdata::available_protocols; %disabled = %configdata::disabled; %config = %configdata::config; + %target = %configdata::target; }; $configdata_loaded = 1; } @@ -221,6 +225,18 @@ sub have_IPv4 { } sub have_IPv6 { + if ($have_IPv6 < 0) { + load_configdata() unless $configdata_loaded; + # If OpenSSL is configured with IPv6 explicitly disabled, no IPv6 + # related tests should be performed. In other words, pretend IPv6 + # isn't present. + $have_IPv6 = 0 + if grep { $_ eq 'OPENSSL_USE_IPV6=0' } @{$config{CPPDEFINES}}; + # Similarly, if a config target has explicitly disabled IPv6, no + # IPv6 related tests should be performed. + $have_IPv6 = 0 + if grep { $_ eq 'OPENSSL_USE_IPV6=0' } @{$target{defines}}; + } if ($have_IPv6 < 0) { $have_IPv6 = check_IP("::1"); } From fccefa7016b12dfcf362e6169ec3b3b4d0634498 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 28 Jun 2024 07:04:43 -0400 Subject: [PATCH 075/138] Remove appveyor badge and replace it with os zoo badge We don't use appveyor anymore. Replace it with the os zoo badge, so we can more persistently see when its breaking Reviewed-by: Richard Levitte Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24762) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf4ae91524991..9d1344b12df34 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Welcome to the OpenSSL Project [![openssl logo]][www.openssl.org] [![github actions ci badge]][github actions ci] -[![appveyor badge]][appveyor jobs] +![Nightly OS Zoo ci badge](https://github.com/openssl/openssl/actions/workflows/os-zoo.yml/badge.svg) OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the TLS (formerly SSL), DTLS and QUIC (currently client side only) From f96563297ee04d57efd45f56bd6b897d809214b4 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 28 Jun 2024 13:17:41 -0400 Subject: [PATCH 076/138] Add badges for daily checks and provider compat Reviewed-by: Richard Levitte Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24762) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9d1344b12df34..157b33c249a14 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ Welcome to the OpenSSL Project [![github actions ci badge]][github actions ci] ![Nightly OS Zoo ci badge](https://github.com/openssl/openssl/actions/workflows/os-zoo.yml/badge.svg) +![Provider Compatibility]( https://github.com/openssl/openssl/actions/workflows/provider-compatibility.yml/badge.svg) +![Daily checks](https://github.com/openssl/openssl/actions/workflows/run-checker-daily.yml/badge.svg) OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the TLS (formerly SSL), DTLS and QUIC (currently client side only) From 16beec98d26644b96d57bd8da477166d0bc7d05c Mon Sep 17 00:00:00 2001 From: Georgi Valkov Date: Fri, 28 Jun 2024 08:16:10 +0300 Subject: [PATCH 077/138] threads_win: fix build error with VS2010 x86 InterlockedAnd64 and InterlockedAdd64 are not available on VS2010 x86. We already have implemented replacements for other functions, such as InterlockedOr64. Apply the same approach to fix the errors. A CRYPTO_RWLOCK rw_lock is added to rcu_lock_st. Replace InterlockedOr64 and InterlockedOr with CRYPTO_atomic_load and CRYPTO_atomic_load_int, using the existing design pattern. Add documentation and tests for the new atomic functions CRYPTO_atomic_add64, CRYPTO_atomic_and Fixes: libcrypto.lib(libcrypto-lib-threads_win.obj) : error LNK2019: unresolved external symbol _InterlockedAdd64 referenced in function _get_hold_current_qp libcrypto.lib(libcrypto-lib-threads_win.obj) : error LNK2019: unresolved external symbol _InterlockedOr referenced in function _get_hold_current_qp libcrypto.lib(libcrypto-lib-threads_win.obj) : error LNK2019: unresolved external symbol _InterlockedAnd64 referenced in function _update_qp libcrypto.lib(libcrypto-lib-threads_win.obj) : error LNK2019: unresolved external symbol _InterlockedOr64 referenced in function _ossl_synchronize_rcu Signed-off-by: Georgi Valkov Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24405) --- crypto/threads_none.c | 18 ++++++++ crypto/threads_pthread.c | 52 +++++++++++++++++++++ crypto/threads_win.c | 72 +++++++++++++++++++++++++---- doc/man3/CRYPTO_THREAD_run_once.pod | 27 ++++++++++- include/openssl/crypto.h.in | 4 ++ test/threadstest.c | 46 ++++++++++++++++++ util/libcrypto.num | 2 + 7 files changed, 210 insertions(+), 11 deletions(-) diff --git a/crypto/threads_none.c b/crypto/threads_none.c index c2e6173bcac3f..750697926095e 100644 --- a/crypto/threads_none.c +++ b/crypto/threads_none.c @@ -211,6 +211,24 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ + *val += op; + *ret = *val; + + return 1; +} + +int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ + *val &= op; + *ret = *val; + + return 1; +} + int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 0628db542f642..7b545999478f7 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -872,6 +872,58 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ +# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) + if (__atomic_is_lock_free(sizeof(*val), val)) { + *ret = __atomic_add_fetch(val, op, __ATOMIC_ACQ_REL); + return 1; + } +# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) + /* This will work for all future Solaris versions. */ + if (ret != NULL) { + *ret = atomic_add_64_nv(val, op); + return 1; + } +# endif + if (lock == NULL || !CRYPTO_THREAD_write_lock(lock)) + return 0; + *val += op; + *ret = *val; + + if (!CRYPTO_THREAD_unlock(lock)) + return 0; + + return 1; +} + +int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ +# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) + if (__atomic_is_lock_free(sizeof(*val), val)) { + *ret = __atomic_and_fetch(val, op, __ATOMIC_ACQ_REL); + return 1; + } +# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) + /* This will work for all future Solaris versions. */ + if (ret != NULL) { + *ret = atomic_and_64_nv(val, op); + return 1; + } +# endif + if (lock == NULL || !CRYPTO_THREAD_write_lock(lock)) + return 0; + *val &= op; + *ret = *val; + + if (!CRYPTO_THREAD_unlock(lock)) + return 0; + + return 1; +} + int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 5ee0751b041df..c96583f2a8e4e 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -103,6 +103,7 @@ struct rcu_lock_st { CRYPTO_CONDVAR *alloc_signal; CRYPTO_MUTEX *prior_lock; CRYPTO_CONDVAR *prior_signal; + CRYPTO_RWLOCK *rw_lock; }; static struct rcu_qp *allocate_new_qp_group(struct rcu_lock_st *lock, @@ -132,6 +133,7 @@ CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) return NULL; new->ctx = ctx; + new->rw_lock = CRYPTO_THREAD_lock_new(); new->write_lock = ossl_crypto_mutex_new(); new->alloc_signal = ossl_crypto_condvar_new(); new->prior_signal = ossl_crypto_condvar_new(); @@ -143,7 +145,9 @@ CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) || new->prior_signal == NULL || new->write_lock == NULL || new->alloc_lock == NULL - || new->prior_lock == NULL) { + || new->prior_lock == NULL + || new->rw_lock == NULL) { + CRYPTO_THREAD_lock_free(new->rw_lock); OPENSSL_free(new->qp_group); ossl_crypto_condvar_free(&new->alloc_signal); ossl_crypto_condvar_free(&new->prior_signal); @@ -159,6 +163,7 @@ CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock) { + CRYPTO_THREAD_lock_free(lock->rw_lock); OPENSSL_free(lock->qp_group); ossl_crypto_condvar_free(&lock->alloc_signal); ossl_crypto_condvar_free(&lock->prior_signal); @@ -171,14 +176,20 @@ void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock) static ossl_inline struct rcu_qp *get_hold_current_qp(CRYPTO_RCU_LOCK *lock) { uint32_t qp_idx; + uint32_t tmp; + uint64_t tmp64; /* get the current qp index */ for (;;) { - qp_idx = InterlockedOr(&lock->reader_idx, 0); - InterlockedAdd64(&lock->qp_group[qp_idx].users, VAL_READER); - if (qp_idx == InterlockedOr(&lock->reader_idx, 0)) + CRYPTO_atomic_load_int(&lock->reader_idx, (int *)&qp_idx, + lock->rw_lock); + CRYPTO_atomic_add64(&lock->qp_group[qp_idx].users, VAL_READER, &tmp64, + lock->rw_lock); + CRYPTO_atomic_load_int(&lock->reader_idx, (int *)&tmp, lock->rw_lock); + if (qp_idx == tmp) break; - InterlockedAdd64(&lock->qp_group[qp_idx].users, -VAL_READER); + CRYPTO_atomic_add64(&lock->qp_group[qp_idx].users, -VAL_READER, &tmp64, + lock->rw_lock); } return &lock->qp_group[qp_idx]; @@ -254,7 +265,9 @@ void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock) if (data->thread_qps[i].lock == lock) { data->thread_qps[i].depth--; if (data->thread_qps[i].depth == 0) { - ret = InterlockedAdd64(&data->thread_qps[i].qp->users, -VAL_READER); + CRYPTO_atomic_add64(&data->thread_qps[i].qp->users, + -VAL_READER, (uint64_t *)&ret, + lock->rw_lock); OPENSSL_assert(ret >= 0); data->thread_qps[i].qp = NULL; data->thread_qps[i].lock = NULL; @@ -269,6 +282,7 @@ static struct rcu_qp *update_qp(CRYPTO_RCU_LOCK *lock) uint64_t new_id; uint32_t current_idx; uint32_t tmp; + uint64_t tmp64; ossl_crypto_mutex_lock(lock->alloc_lock); /* @@ -292,8 +306,10 @@ static struct rcu_qp *update_qp(CRYPTO_RCU_LOCK *lock) lock->id_ctr++; new_id = VAL_ID(new_id); - InterlockedAnd64(&lock->qp_group[current_idx].users, ID_MASK); - InterlockedAdd64(&lock->qp_group[current_idx].users, new_id); + CRYPTO_atomic_and(&lock->qp_group[current_idx].users, ID_MASK, &tmp64, + lock->rw_lock); + CRYPTO_atomic_add64(&lock->qp_group[current_idx].users, new_id, &tmp64, + lock->rw_lock); /* update the reader index to be the prior qp */ tmp = lock->current_alloc_idx; @@ -328,7 +344,7 @@ void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock) /* wait for the reader count to reach zero */ do { - count = InterlockedOr64(&qp->users, 0); + CRYPTO_atomic_load(&qp->users, &count, lock->rw_lock); } while (READER_COUNT(count) != 0); /* retire in order */ @@ -559,6 +575,44 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ +#if (defined(NO_INTERLOCKEDOR64)) + if (lock == NULL || !CRYPTO_THREAD_write_lock(lock)) + return 0; + *val += op; + *ret = *val; + + if (!CRYPTO_THREAD_unlock(lock)) + return 0; + + return 1; +#else + *ret = (uint64_t)InterlockedAdd64((LONG64 volatile *)val, (LONG64)op); + return 1; +#endif +} + +int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock) +{ +#if (defined(NO_INTERLOCKEDOR64)) + if (lock == NULL || !CRYPTO_THREAD_write_lock(lock)) + return 0; + *val &= op; + *ret = *val; + + if (!CRYPTO_THREAD_unlock(lock)) + return 0; + + return 1; +#else + *ret = (uint64_t)InterlockedAnd64((LONG64 volatile *)val, (LONG64)op) & op; + return 1; +#endif +} + int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { diff --git a/doc/man3/CRYPTO_THREAD_run_once.pod b/doc/man3/CRYPTO_THREAD_run_once.pod index 2b0d0675ab090..e26f406f12178 100644 --- a/doc/man3/CRYPTO_THREAD_run_once.pod +++ b/doc/man3/CRYPTO_THREAD_run_once.pod @@ -5,8 +5,8 @@ CRYPTO_THREAD_run_once, CRYPTO_THREAD_lock_new, CRYPTO_THREAD_read_lock, CRYPTO_THREAD_write_lock, CRYPTO_THREAD_unlock, CRYPTO_THREAD_lock_free, -CRYPTO_atomic_add, CRYPTO_atomic_or, CRYPTO_atomic_load, CRYPTO_atomic_store, -CRYPTO_atomic_load_int, +CRYPTO_atomic_add, CRYPTO_atomic_add64, CRYPTO_atomic_and, CRYPTO_atomic_or, +CRYPTO_atomic_load, CRYPTO_atomic_store, CRYPTO_atomic_load_int, OSSL_set_max_threads, OSSL_get_max_threads, OSSL_get_thread_support_flags, OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL, OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN - OpenSSL thread support @@ -25,6 +25,10 @@ OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN - OpenSSL thread support void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock); int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock); + int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock); + int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock); int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock); int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock); @@ -95,6 +99,25 @@ supported and I is NULL, then the function will fail. =item * +CRYPTO_atomic_add64() atomically adds I to I<*val> and returns the +result of the operation in I<*ret>. I will be locked, unless atomic +operations are supported on the specific platform. Because of this, if a +variable is modified by CRYPTO_atomic_add64() then CRYPTO_atomic_add64() must +be the only way that the variable is modified. If atomic operations are not +supported and I is NULL, then the function will fail. + +=item * + +CRYPTO_atomic_and() performs an atomic bitwise and of I and I<*val> and stores +the result back in I<*val>. It also returns the result of the operation in +I<*ret>. I will be locked, unless atomic operations are supported on the +specific platform. Because of this, if a variable is modified by +CRYPTO_atomic_and() or read by CRYPTO_atomic_load() then CRYPTO_atomic_and() must +be the only way that the variable is modified. If atomic operations are not +supported and I is NULL, then the function will fail. + +=item * + CRYPTO_atomic_or() performs an atomic bitwise or of I and I<*val> and stores the result back in I<*val>. It also returns the result of the operation in I<*ret>. I will be locked, unless atomic operations are supported on the diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index ef87f9754d9c0..1bc8ae4cce06f 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -86,6 +86,10 @@ int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock); void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock); int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock); +int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock); +int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, + CRYPTO_RWLOCK *lock); int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock); int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock); diff --git a/test/threadstest.c b/test/threadstest.c index b2b1ec2555ae5..85d5e1149506e 100644 --- a/test/threadstest.c +++ b/test/threadstest.c @@ -654,6 +654,52 @@ static int test_atomic(void) || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) goto err; + ret64 = 0; + + if (CRYPTO_atomic_and(&val64, 5, &ret64, NULL)) { + /* This succeeds therefore we're on a platform with lockless atomics */ + if (!TEST_uint_eq((unsigned int)val64, 1) + || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) + goto err; + } else { + /* This failed therefore we're on a platform without lockless atomics */ + if (!TEST_uint_eq((unsigned int)val64, 3) + || !TEST_int_eq((unsigned int)ret64, 0)) + goto err; + } + val64 = 3; + ret64 = 0; + + if (!TEST_true(CRYPTO_atomic_and(&val64, 5, &ret64, lock))) + goto err; + + if (!TEST_uint_eq((unsigned int)val64, 1) + || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) + goto err; + + ret64 = 0; + + if (CRYPTO_atomic_add64(&val64, 2, &ret64, NULL)) { + /* This succeeds therefore we're on a platform with lockless atomics */ + if (!TEST_uint_eq((unsigned int)val64, 3) + || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) + goto err; + } else { + /* This failed therefore we're on a platform without lockless atomics */ + if (!TEST_uint_eq((unsigned int)val64, 1) + || !TEST_int_eq((unsigned int)ret64, 0)) + goto err; + } + val64 = 1; + ret64 = 0; + + if (!TEST_true(CRYPTO_atomic_add64(&val64, 2, &ret64, lock))) + goto err; + + if (!TEST_uint_eq((unsigned int)val64, 3) + || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) + goto err; + testresult = 1; err: CRYPTO_THREAD_lock_free(lock); diff --git a/util/libcrypto.num b/util/libcrypto.num index 2c9292d4abe0a..8dc578670b05c 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5688,3 +5688,5 @@ i2d_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: ATTRIBUTES_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: ATTRIBUTES_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: ATTRIBUTES_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: +CRYPTO_atomic_add64 ? 3_4_0 EXIST::FUNCTION: +CRYPTO_atomic_and ? 3_4_0 EXIST::FUNCTION: From 16311dbf53c464726d73b76d77ecf6275c9f9d08 Mon Sep 17 00:00:00 2001 From: JohnnySavages Date: Wed, 26 Jun 2024 21:59:52 -0400 Subject: [PATCH 078/138] Check EC_GROUP_get0_order result before dereference CLA: trivial Reviewed-by: Paul Dale Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24755) --- crypto/ec/ecdsa_ossl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crypto/ec/ecdsa_ossl.c b/crypto/ec/ecdsa_ossl.c index 1e611f7ffce0b..2f3c169d3278f 100644 --- a/crypto/ec/ecdsa_ossl.c +++ b/crypto/ec/ecdsa_ossl.c @@ -172,7 +172,11 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); goto err; } - order = EC_GROUP_get0_order(group); + + if ((order = EC_GROUP_get0_order(group)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } /* Preallocate space */ order_bits = BN_num_bits(order); @@ -308,7 +312,11 @@ ECDSA_SIG *ossl_ecdsa_simple_sign_sig(const unsigned char *dgst, int dgst_len, goto err; } - order = EC_GROUP_get0_order(group); + if ((order = EC_GROUP_get0_order(group)) == NULL) { + ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); + goto err; + } + i = BN_num_bits(order); /* * Need to truncate digest if it is too long: first truncate whole bytes. From 3f7b355733407cf777bfad5ce5b79610588bacc5 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 1 Jul 2024 09:30:56 +0200 Subject: [PATCH 079/138] OPENSSL_hexstr2buf_ex(): Handle zero-length input correctly In case of zero-length input the code wrote one byte before the start of the output buffer. The length of the output was also reported incorrectly in this case. Reviewed-by: Tim Hudson Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24770) --- crypto/o_str.c | 6 ++++-- test/hexstr_test.c | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/crypto/o_str.c b/crypto/o_str.c index 065460336ffb1..dfac215ac3562 100644 --- a/crypto/o_str.c +++ b/crypto/o_str.c @@ -225,12 +225,14 @@ static int buf2hexstr_sep(char *str, size_t str_n, size_t *strlength, int has_sep = (sep != CH_ZERO); size_t len = has_sep ? buflen * 3 : 1 + buflen * 2; + if (len == 0) + ++len; if (strlength != NULL) *strlength = len; if (str == NULL) return 1; - if (str_n < (unsigned long)len) { + if (str_n < len) { ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER); return 0; } @@ -242,7 +244,7 @@ static int buf2hexstr_sep(char *str, size_t str_n, size_t *strlength, if (has_sep) *q++ = sep; } - if (has_sep) + if (has_sep && buflen > 0) --q; *q = CH_ZERO; diff --git a/test/hexstr_test.c b/test/hexstr_test.c index 5a9684e0e6977..89d6d9713978c 100644 --- a/test/hexstr_test.c +++ b/test/hexstr_test.c @@ -120,9 +120,14 @@ static int test_hexstr_ex_to_from(int test_index) return TEST_true(OPENSSL_hexstr2buf_ex(buf, sizeof(buf), &len, test->in, ':')) && TEST_mem_eq(buf, len, test->expected, test->expected_len) + && TEST_false(OPENSSL_buf2hexstr_ex(out, 3 * len - 1, NULL, buf, len, + ':')) && TEST_true(OPENSSL_buf2hexstr_ex(out, sizeof(out), NULL, buf, len, - ':')) - && TEST_str_eq(out, test->in); + ':')) + && TEST_str_eq(out, test->in) + && TEST_true(OPENSSL_buf2hexstr_ex(out, sizeof(out), NULL, buf, 0, + ':')) + && TEST_size_t_eq(strlen(out), 0); } int setup_tests(void) From b1e7bc5bdfc73ef841afa30ac321975b0d63219a Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Mon, 11 Jul 2022 19:55:10 +0200 Subject: [PATCH 080/138] BIO_f_base64.pod and openssl-enc.pod.in: improve description on newline handling Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/18783) --- doc/man1/openssl-enc.pod.in | 11 ++++++++++- doc/man3/BIO_f_base64.pod | 24 +++++++++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/doc/man1/openssl-enc.pod.in b/doc/man1/openssl-enc.pod.in index 14066a31859f9..0f514672eca62 100644 --- a/doc/man1/openssl-enc.pod.in +++ b/doc/man1/openssl-enc.pod.in @@ -98,13 +98,19 @@ Base64 process the data. This means that if encryption is taking place the data is base64 encoded after encryption. If decryption is set then the input data is base64 decoded before being decrypted. +When the B<-A> option not given, +on encoding a newline is inserted after each 64 characters, and +on decoding a newline is expected among the first 1024 bytes of input. + =item B<-base64> Same as B<-a> =item B<-A> -If the B<-a> option is set then base64 process the data on one line. +If the B<-a> option is set then base64 encoding produces output without any +newline character, and base64 decoding does not require any newlines. +Therefore it can be helpful to use the B<-A> option when decoding unknown input. =item B<-k> I @@ -463,6 +469,9 @@ or =head1 BUGS The B<-A> option when used with large files doesn't work properly. +On the other hand, when base64 decoding without the B<-A> option, +if the first 1024 bytes of input do not include a newline character +the first two lines of input are ignored. The B command only supports a fixed number of algorithms with certain parameters. So if, for example, you want to use RC2 with a diff --git a/doc/man3/BIO_f_base64.pod b/doc/man3/BIO_f_base64.pod index c865f0a17ac16..7d10df933c51b 100644 --- a/doc/man3/BIO_f_base64.pod +++ b/doc/man3/BIO_f_base64.pod @@ -21,25 +21,23 @@ any data read through it. Base64 BIOs do not support BIO_gets() or BIO_puts(). -For writing, output is by default divided to lines of length 64 -characters and there is always a newline at the end of output. +For writing, by default output is divided to lines of length 64 +characters and there is a newline at the end of output. +This behavior can be changed with B flag. -For reading, first line should be at most 1024 -characters long. If it is longer then it is ignored completely. -Other input lines can be of any length. There must be a newline -at the end of input. - -This behavior can be changed with BIO_FLAGS_BASE64_NO_NL flag. +For reading, first line should be at most 1024 bytes long including newline +unless the flag B is set. +Further input lines can be of any length (i.e., newlines may appear anywhere +in the input) and a newline at the end of input is not needed. BIO_flush() on a base64 BIO that is being written through is used to signal that no more data is to be encoded: this is used to flush the final block through the BIO. -The flag BIO_FLAGS_BASE64_NO_NL can be set with BIO_set_flags(). +The flag B can be set with BIO_set_flags(). For writing, it causes all data to be written on one line without newline at the end. -For reading, it expects the data to be all on one line (with or -without a trailing newline). +For reading, it removes all expectations on newlines in the input data. =head1 NOTES @@ -85,6 +83,10 @@ data to standard output: =head1 BUGS +On decoding, if the flag B is not set and +the first 1024 bytes of input do not include a newline character +the first two lines of input are ignored. + The ambiguity of EOF in base64 encoded data can cause additional data following the base64 encoded block to be misinterpreted. From 2c7cae53bc61f40baff70af0495cf3d976ed7d14 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 19 Jun 2024 17:53:58 -0400 Subject: [PATCH 081/138] Convert hashtable to using ossl_rcu_deref on lookup The new hashtable has an issue on non-64 bit builds. We use CRYPTO_atomic_load to load a pointer value when doing lookups, but that API relies on the expectation that pointers are 64 bits wide. On 32 bit systems, we try to load 64 bits using CRYPTO_atomic_load into a 32 bit pointer, which overruns our stack Fix this by no longer using CRYPTO_atomic_load for value fetches from the hashtable. Instead use ossl_rcu_deref, whcih operates on void pointers and is safe on all arches Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24682) --- crypto/hashtable/hashtable.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crypto/hashtable/hashtable.c b/crypto/hashtable/hashtable.c index 67c9b190cf8f2..61d11940a9dcb 100644 --- a/crypto/hashtable/hashtable.c +++ b/crypto/hashtable/hashtable.c @@ -639,8 +639,7 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key) CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash, &ehash, h->atomic_lock); if (compare_hash(hash, ehash)) { - CRYPTO_atomic_load((uint64_t *)&md->neighborhoods[neigh_idx].entries[j].value, - (uint64_t *)&vidx, h->atomic_lock); + vidx = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value); ret = (HT_VALUE *)vidx; break; } From bb90a7861cbf27e29790b66077c23a2e9805014b Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 1 Jul 2024 15:28:14 +0200 Subject: [PATCH 082/138] fix: openssl speed: RSA encryption is on the pubkey, not the privkey Reviewed-by: Neil Horman Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24776) --- apps/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/speed.c b/apps/speed.c index 1fd7eb26b6279..c4508def6272a 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -3051,7 +3051,7 @@ int speed_main(int argc, char **argv) ERR_print_errors(bio_err); op_count = 1; } else { - pkey_print_message("private", "rsa encrypt", + pkey_print_message("public", "rsa encrypt", rsa_keys[testnum].bits, seconds.rsa); /* RSA_blinding_on(rsa_key[testnum],NULL); */ Time_F(START); From cfe0bbdecadaebc6ad7ba5a3335b7a03522c434f Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 1 Jul 2024 15:28:39 +0200 Subject: [PATCH 083/138] fix: remove some odd empty lines Reviewed-by: Neil Horman Reviewed-by: Tom Cosgrove Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24776) --- apps/speed.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/speed.c b/apps/speed.c index c4508def6272a..db23ca6716cd6 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -3119,7 +3119,6 @@ int speed_main(int argc, char **argv) loopargs[i].sigsize = loopargs[i].buflen; if (loopargs[i].dsa_sign_ctx[testnum] == NULL || EVP_PKEY_sign_init(loopargs[i].dsa_sign_ctx[testnum]) <= 0 - || EVP_PKEY_sign(loopargs[i].dsa_sign_ctx[testnum], loopargs[i].buf2, &loopargs[i].sigsize, @@ -3196,7 +3195,6 @@ int speed_main(int argc, char **argv) loopargs[i].sigsize = loopargs[i].buflen; if (loopargs[i].ecdsa_sign_ctx[testnum] == NULL || EVP_PKEY_sign_init(loopargs[i].ecdsa_sign_ctx[testnum]) <= 0 - || EVP_PKEY_sign(loopargs[i].ecdsa_sign_ctx[testnum], loopargs[i].buf2, &loopargs[i].sigsize, From b5863e9259e3c610304febe8b43ac3b1e3b22534 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 28 Jun 2024 10:34:23 +0200 Subject: [PATCH 084/138] Configure: Remove -Wswitch-default from strict warnings Also move -Wno-tautological-constant-out-of-range-compare to clang-specific options as it is not supported by gcc. Reviewed-by: Bernd Edlinger Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/24758) (cherry picked from commit 3d9c6b16d8b8e75b73e2fd34849e930e2792f3a4) --- Configure | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Configure b/Configure index 71322996111d0..37e0b51c4f177 100755 --- a/Configure +++ b/Configure @@ -171,7 +171,6 @@ my @gcc_devteam_warn = qw( -Wshadow -Wformat -Wno-type-limits - -Wno-tautological-constant-out-of-range-compare -Wundef -Werror -Wmissing-prototypes @@ -188,11 +187,11 @@ my @gcc_devteam_warn = qw( # -Wextended-offsetof -- no, needed in CMS ASN1 code my @clang_devteam_warn = qw( -Wno-unknown-warning-option - -Wswitch-default -Wno-parentheses-equality -Wno-language-extension-token -Wno-extended-offsetof -Wno-missing-braces + -Wno-tautological-constant-out-of-range-compare -Wconditional-uninitialized -Wincompatible-pointer-types-discards-qualifiers -Wmissing-variable-declarations From e6174ca4d48f6f4f954dd87f2cdf3718af14f064 Mon Sep 17 00:00:00 2001 From: cchinchole Date: Tue, 2 Jul 2024 02:56:22 -0500 Subject: [PATCH 085/138] Fixes for potential deadlock Fixes (#24517): (3/3) Addresses the potential deadlock if an error occurs from up_ref in functions ENGINE_get_first, ENGINE_get_last, ENGINE_get_next, and ENGINE_get_prev in file crypto/engine/eng_list.c CLA: trivial Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24780) --- crypto/engine/eng_list.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/engine/eng_list.c b/crypto/engine/eng_list.c index a2c151d64a04a..eafca3ec49ce8 100644 --- a/crypto/engine/eng_list.c +++ b/crypto/engine/eng_list.c @@ -243,6 +243,7 @@ ENGINE *ENGINE_get_first(void) int ref; if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { + CRYPTO_THREAD_unlock(global_engine_lock); ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); return NULL; } @@ -269,6 +270,7 @@ ENGINE *ENGINE_get_last(void) int ref; if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { + CRYPTO_THREAD_unlock(global_engine_lock); ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); return NULL; } @@ -294,6 +296,7 @@ ENGINE *ENGINE_get_next(ENGINE *e) /* Return a valid structural reference to the next ENGINE */ if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { + CRYPTO_THREAD_unlock(global_engine_lock); ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); return NULL; } @@ -320,6 +323,7 @@ ENGINE *ENGINE_get_prev(ENGINE *e) /* Return a valid structural reference to the next ENGINE */ if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { + CRYPTO_THREAD_unlock(global_engine_lock); ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); return NULL; } From 3f4da93678497fe64d262d03c388932f7ecfe74e Mon Sep 17 00:00:00 2001 From: cchinchole Date: Mon, 1 Jul 2024 20:16:03 -0500 Subject: [PATCH 086/138] Unlock only when lock was successful Addressing issue (#24517): Updated the example in CRYPTO_THREAD_run_once.pod to reflect that an unlock call should not be made if a write_lock failed. Updated BIO_lookup_ex in bio_addr.c and ossl_engine_table_select in eng_table.c to not call unlock if the lock failed. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/24779) --- crypto/bio/bio_addr.c | 10 ++++------ crypto/engine/eng_table.c | 6 ++++-- doc/man3/CRYPTO_THREAD_run_once.pod | 9 ++++++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/crypto/bio/bio_addr.c b/crypto/bio/bio_addr.c index 0a64d0749a29b..abdf3523045d6 100644 --- a/crypto/bio/bio_addr.c +++ b/crypto/bio/bio_addr.c @@ -799,14 +799,12 @@ int BIO_lookup_ex(const char *host, const char *service, int lookup_type, if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) { /* Should this be raised inside do_bio_lookup_init()? */ ERR_raise(ERR_LIB_BIO, ERR_R_CRYPTO_LIB); - ret = 0; - goto err; + return 0; } - if (!CRYPTO_THREAD_write_lock(bio_lookup_lock)) { - ret = 0; - goto err; - } + if (!CRYPTO_THREAD_write_lock(bio_lookup_lock)) + return 0; + he_fallback_address = INADDR_ANY; if (host == NULL) { he = &he_fallback; diff --git a/crypto/engine/eng_table.c b/crypto/engine/eng_table.c index 9dc3144bbfd7b..cb43e2d967fa4 100644 --- a/crypto/engine/eng_table.c +++ b/crypto/engine/eng_table.c @@ -215,9 +215,11 @@ ENGINE *ossl_engine_table_select(ENGINE_TABLE **table, int nid, f, l, nid); return NULL; } - ERR_set_mark(); + if (!CRYPTO_THREAD_write_lock(global_engine_lock)) - goto end; + return NULL; + + ERR_set_mark(); /* * Check again inside the lock otherwise we could race against cleanup * operations. But don't worry about a debug printout diff --git a/doc/man3/CRYPTO_THREAD_run_once.pod b/doc/man3/CRYPTO_THREAD_run_once.pod index e26f406f12178..b8894f1db58c5 100644 --- a/doc/man3/CRYPTO_THREAD_run_once.pod +++ b/doc/man3/CRYPTO_THREAD_run_once.pod @@ -244,10 +244,13 @@ This example safely initializes and uses a lock. { int ret = 0; - if (mylock()) { - /* Your code here, do not return without releasing the lock! */ - ret = ... ; + if (!mylock()) { + /* Do not unlock unless the lock was successfully acquired. */ + return 0; } + + /* Your code here, do not return without releasing the lock! */ + ret = ... ; myunlock(); return ret; } From 070b6a965485e91b02453919e0a47c0659420d9a Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Fri, 14 Jun 2024 14:57:28 +0200 Subject: [PATCH 087/138] Allow shared iOS builds Fixes #24545 Reviewed-by: Todd Short Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24649) --- Configurations/15-ios.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configurations/15-ios.conf b/Configurations/15-ios.conf index 478f30f47e7f1..6f33df381f7cd 100644 --- a/Configurations/15-ios.conf +++ b/Configurations/15-ios.conf @@ -11,7 +11,7 @@ my %targets = ( template => 1, inherit_from => [ "darwin-common" ], sys_id => "iOS", - disable => [ "shared", "async" ], + disable => [ "async" ], }, "ios-xcrun" => { inherit_from => [ "ios-common" ], From 2ef6fa1cdda8dc79ee520d129a87bd3525a37a1f Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Fri, 28 Jun 2024 09:57:25 +0000 Subject: [PATCH 088/138] feat: support userNotice X.509v3 extension Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24761) --- crypto/x509/build.info | 3 +- crypto/x509/ext_dat.h | 1 + crypto/x509/standard_exts.h | 1 + crypto/x509/v3_sda.c | 12 ++--- crypto/x509/v3_usernotice.c | 94 +++++++++++++++++++++++++++++++++++++ doc/man3/X509_dup.pod | 9 ++-- doc/man3/d2i_X509.pod | 6 ++- include/openssl/x509v3.h.in | 11 ++++- util/libcrypto.num | 15 ++++-- 9 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 crypto/x509/v3_usernotice.c diff --git a/crypto/x509/build.info b/crypto/x509/build.info index ff648e99976f5..0404d7c94fa47 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -16,7 +16,8 @@ SOURCE[../../libcrypto]=\ pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \ v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_no_rev_avail.c \ v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ - x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c v3_sda.c + x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c v3_sda.c \ + v3_usernotice.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index 3c59f32baabf6..43a29448249c9 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -38,3 +38,4 @@ extern const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs; extern const X509V3_EXT_METHOD ossl_v3_associated_info; extern const X509V3_EXT_METHOD ossl_v3_acc_cert_policies; extern const X509V3_EXT_METHOD ossl_v3_acc_priv_policies; +extern const X509V3_EXT_METHOD ossl_v3_user_notice; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index 879226eabebd0..9e2ca47bad9f7 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -76,6 +76,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_tls_feature, &ossl_v3_ext_admission, &ossl_v3_delegated_name_constraints, + &ossl_v3_user_notice, &ossl_v3_soa_identifier, &ossl_v3_acc_cert_policies, &ossl_v3_acc_priv_policies, diff --git a/crypto/x509/v3_sda.c b/crypto/x509/v3_sda.c index 35602fc6811f0..a27c31711ad74 100644 --- a/crypto/x509/v3_sda.c +++ b/crypto/x509/v3_sda.c @@ -12,14 +12,14 @@ #include #include "ext_dat.h" -ASN1_ITEM_TEMPLATE(ATTRIBUTES_SYNTAX) = +ASN1_ITEM_TEMPLATE(OSSL_ATTRIBUTES_SYNTAX) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Attributes, X509_ATTRIBUTE) -ASN1_ITEM_TEMPLATE_END(ATTRIBUTES_SYNTAX) +ASN1_ITEM_TEMPLATE_END(OSSL_ATTRIBUTES_SYNTAX) -IMPLEMENT_ASN1_FUNCTIONS(ATTRIBUTES_SYNTAX) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATTRIBUTES_SYNTAX) static int i2r_ATTRIBUTES_SYNTAX(X509V3_EXT_METHOD *method, - ATTRIBUTES_SYNTAX *attrlst, + OSSL_ATTRIBUTES_SYNTAX *attrlst, BIO *out, int indent) { X509_ATTRIBUTE *attr; @@ -71,7 +71,7 @@ static int i2r_ATTRIBUTES_SYNTAX(X509V3_EXT_METHOD *method, const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs = { NID_subject_directory_attributes, X509V3_EXT_MULTILINE, - ASN1_ITEM_ref(ATTRIBUTES_SYNTAX), + ASN1_ITEM_ref(OSSL_ATTRIBUTES_SYNTAX), 0, 0, 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2R)i2r_ATTRIBUTES_SYNTAX, @@ -81,7 +81,7 @@ const X509V3_EXT_METHOD ossl_v3_subj_dir_attrs = { const X509V3_EXT_METHOD ossl_v3_associated_info = { NID_associated_information, X509V3_EXT_MULTILINE, - ASN1_ITEM_ref(ATTRIBUTES_SYNTAX), + ASN1_ITEM_ref(OSSL_ATTRIBUTES_SYNTAX), 0, 0, 0, 0, 0, 0, 0, 0, (X509V3_EXT_I2R)i2r_ATTRIBUTES_SYNTAX, diff --git a/crypto/x509/v3_usernotice.c b/crypto/x509/v3_usernotice.c new file mode 100644 index 0000000000000..cc99132525043 --- /dev/null +++ b/crypto/x509/v3_usernotice.c @@ -0,0 +1,94 @@ +/* + * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include "ext_dat.h" + +ASN1_ITEM_TEMPLATE(OSSL_USER_NOTICE_SYNTAX) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, OSSL_USER_NOTICE_SYNTAX, USERNOTICE) +ASN1_ITEM_TEMPLATE_END(OSSL_USER_NOTICE_SYNTAX) + +IMPLEMENT_ASN1_FUNCTIONS(OSSL_USER_NOTICE_SYNTAX) + +static int print_notice(BIO *out, USERNOTICE *notice, int indent) +{ + int i; + ASN1_INTEGER *num; + char *tmp; + + if (notice->noticeref) { + NOTICEREF *ref; + ref = notice->noticeref; + if (BIO_printf(out, "%*sOrganization: %.*s\n", indent, "", + ref->organization->length, + ref->organization->data) <= 0) + return 0; + if (BIO_printf(out, "%*sNumber%s: ", indent, "", + sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "") <= 0) + return 0; + for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) { + num = sk_ASN1_INTEGER_value(ref->noticenos, i); + if (i && BIO_puts(out, ", ") <= 0) + return 0; + if (num == NULL && BIO_puts(out, "(null)") <= 0) + return 0; + else { + tmp = i2s_ASN1_INTEGER(NULL, num); + if (tmp == NULL) + return 0; + if (BIO_puts(out, tmp) <= 0) { + OPENSSL_free(tmp); + return 0; + } + OPENSSL_free(tmp); + } + } + if (notice->exptext && BIO_puts(out, "\n") <= 0) + return 0; + } + if (notice->exptext == NULL) + return 1; + + return BIO_printf(out, "%*sExplicit Text: %.*s", indent, "", + notice->exptext->length, + notice->exptext->data) >= 0; +} + +static int i2r_USER_NOTICE_SYNTAX(X509V3_EXT_METHOD *method, + OSSL_USER_NOTICE_SYNTAX *uns, + BIO *out, int indent) +{ + int i; + USERNOTICE *unotice; + + if (BIO_printf(out, "%*sUser Notices:\n", indent, "") <= 0) + return 0; + + for (i = 0; i < sk_USERNOTICE_num(uns); i++) { + unotice = sk_USERNOTICE_value(uns, i); + if (!print_notice(out, unotice, indent + 4)) + return 0; + if (BIO_puts(out, "\n\n") <= 0) + return 0; + } + return 1; +} + +const X509V3_EXT_METHOD ossl_v3_user_notice = { + NID_user_notice, 0, + ASN1_ITEM_ref(OSSL_USER_NOTICE_SYNTAX), + 0, 0, 0, 0, + 0, + 0, + 0, 0, + (X509V3_EXT_I2R)i2r_USER_NOTICE_SYNTAX, + 0, + NULL +}; diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index 6ffcca79db142..f766e68069d7d 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -19,9 +19,6 @@ ASIdentifiers_free, ASIdentifiers_new, ASRange_free, ASRange_new, -ATTRIBUTES_SYNTAX_free, -ATTRIBUTES_SYNTAX_it, -ATTRIBUTES_SYNTAX_new, AUTHORITY_INFO_ACCESS_free, AUTHORITY_INFO_ACCESS_new, AUTHORITY_KEYID_free, @@ -139,6 +136,9 @@ OCSP_SIGNATURE_free, OCSP_SIGNATURE_new, OCSP_SINGLERESP_free, OCSP_SINGLERESP_new, +OSSL_ATTRIBUTES_SYNTAX_free, +OSSL_ATTRIBUTES_SYNTAX_it, +OSSL_ATTRIBUTES_SYNTAX_new, OSSL_CMP_ATAVS_new, OSSL_CMP_ATAVS_free, OSSL_CMP_ATAVS_it, @@ -204,6 +204,9 @@ OSSL_ISSUER_SERIAL_free, OSSL_ISSUER_SERIAL_new, OSSL_OBJECT_DIGEST_INFO_free, OSSL_OBJECT_DIGEST_INFO_new, +OSSL_USER_NOTICE_SYNTAX_free, +OSSL_USER_NOTICE_SYNTAX_new, +OSSL_USER_NOTICE_SYNTAX_it, OTHERNAME_free, OTHERNAME_new, PBE2PARAM_free, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 86a653ad148ad..1f0a4dae7aa04 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -38,7 +38,6 @@ d2i_ASN1_UTCTIME, d2i_ASN1_UTF8STRING, d2i_ASN1_VISIBLESTRING, d2i_ASRange, -d2i_ATTRIBUTES_SYNTAX, d2i_AUTHORITY_INFO_ACCESS, d2i_AUTHORITY_KEYID, d2i_BASIC_CONSTRAINTS, @@ -90,6 +89,7 @@ d2i_OCSP_REVOKEDINFO, d2i_OCSP_SERVICELOC, d2i_OCSP_SIGNATURE, d2i_OCSP_SINGLERESP, +d2i_OSSL_ATTRIBUTES_SYNTAX, d2i_OSSL_CMP_ATAVS, d2i_OSSL_CMP_MSG, d2i_OSSL_CMP_PKIHEADER, @@ -109,6 +109,7 @@ d2i_OSSL_TARGET_CERT, d2i_OSSL_TARGET, d2i_OSSL_TARGETING_INFORMATION, d2i_OSSL_TARGETS, +d2i_OSSL_USER_NOTICE_SYNTAX, d2i_OTHERNAME, d2i_PBE2PARAM, d2i_PBEPARAM, @@ -221,7 +222,6 @@ i2d_ASN1_UTF8STRING, i2d_ASN1_VISIBLESTRING, i2d_ASN1_bio_stream, i2d_ASRange, -i2d_ATTRIBUTES_SYNTAX, i2d_AUTHORITY_INFO_ACCESS, i2d_AUTHORITY_KEYID, i2d_BASIC_CONSTRAINTS, @@ -273,6 +273,7 @@ i2d_OCSP_REVOKEDINFO, i2d_OCSP_SERVICELOC, i2d_OCSP_SIGNATURE, i2d_OCSP_SINGLERESP, +i2d_OSSL_ATTRIBUTES_SYNTAX, i2d_OSSL_CMP_ATAVS, i2d_OSSL_CMP_MSG, i2d_OSSL_CMP_PKIHEADER, @@ -292,6 +293,7 @@ i2d_OSSL_TARGET_CERT, i2d_OSSL_TARGET, i2d_OSSL_TARGETING_INFORMATION, i2d_OSSL_TARGETS, +i2d_OSSL_USER_NOTICE_SYNTAX, i2d_OTHERNAME, i2d_PBE2PARAM, i2d_PBEPARAM, diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 10fc663e6dc56..2f859e0f13056 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1021,8 +1021,15 @@ void PROFESSION_INFO_set0_registrationNumber( int OSSL_GENERAL_NAMES_print(BIO *out, GENERAL_NAMES *gens, int indent); -typedef STACK_OF(X509_ATTRIBUTE) ATTRIBUTES_SYNTAX; -DECLARE_ASN1_FUNCTIONS(ATTRIBUTES_SYNTAX) +typedef STACK_OF(X509_ATTRIBUTE) OSSL_ATTRIBUTES_SYNTAX; +DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTES_SYNTAX) + +typedef STACK_OF(USERNOTICE) OSSL_USER_NOTICE_SYNTAX; +DECLARE_ASN1_FUNCTIONS(OSSL_USER_NOTICE_SYNTAX) + +{- + generate_stack_macros("USERNOTICE"); +-} # ifdef __cplusplus } diff --git a/util/libcrypto.num b/util/libcrypto.num index 8dc578670b05c..9e73024f3aa51 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5683,10 +5683,15 @@ OSSL_TARGETING_INFORMATION_free ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_new ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_it ? 3_4_0 EXIST::FUNCTION: OSSL_GENERAL_NAMES_print ? 3_4_0 EXIST::FUNCTION: -d2i_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: -i2d_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: -ATTRIBUTES_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: -ATTRIBUTES_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: -ATTRIBUTES_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: CRYPTO_atomic_add64 ? 3_4_0 EXIST::FUNCTION: CRYPTO_atomic_and ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: +i2d_OSSL_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: +OSSL_ATTRIBUTES_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: +OSSL_ATTRIBUTES_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: +OSSL_ATTRIBUTES_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_USER_NOTICE_SYNTAX ? 3_4_0 EXIST::FUNCTION: +i2d_OSSL_USER_NOTICE_SYNTAX ? 3_4_0 EXIST::FUNCTION: +OSSL_USER_NOTICE_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: +OSSL_USER_NOTICE_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: +OSSL_USER_NOTICE_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: From 708b8559f145a1aee1ed18809ab64146de864761 Mon Sep 17 00:00:00 2001 From: "Jonathan M. Wilbur" Date: Fri, 28 Jun 2024 09:57:37 +0000 Subject: [PATCH 089/138] test: userNotice X.509v3 extension Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24761) --- test/certs/ext-userNotice.pem | 13 +++++++++++++ test/recipes/25-test_x509.t | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/certs/ext-userNotice.pem diff --git a/test/certs/ext-userNotice.pem b/test/certs/ext-userNotice.pem new file mode 100644 index 0000000000000..7061deda10677 --- /dev/null +++ b/test/certs/ext-userNotice.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB8jCCAd6gAwIBAgIDAQIDMAsGCSqGSIb3DQEBBTAAMCIYDzIwMjEwODMwMDEw +MjAzWhgPMjAyMTA4MzAwMTAyMDNaMAAwggEgMAsGCSqGSIb3DQEBAQOCAQ8AMIIB +CgKCAQEAtnjLm1ts1hC4fNNt3UnQD9y73bDXgioTyWYSI3ca/KNfuTydjFTEYAmq +nuGrBOUfgbmH3PRQ0AmpqljgWTb3d3K8H4UFvDWQTPSS21IMjm8oqd19nE5GxWir +Gu0oDRzhWLHe1RZ7ZrohCPg/1Ocsy47QZuK2laFB0rEmrRWBmEYbDl3/wxf5XfqI +qpOynJB02thXrTCcTM7Rz1FqCFt/ZVZB5hKY2S+CTdE9OIVKlr4WHMfuvUYeOj06 +GkwLFJHNv2tU+tovI3mYRxUuY4UupkS3MC+Otey7XKm1P+INjWWoegm6iCAt3Vus +pVz+6pU2xgl3nrAVMQHB4fReQPH0pQIDAQABo3kwdzB1BgNVHTEEbjBsMDEwHAwR +V2lsZGJvYXIgU29mdHdhcmUwBwIBewICAcgaEUhleSB0aGVyZSBiaWcgYm9pMDcw +Jx4eAEoAbwBuAGEAdABoAGEAbgAgAFcAaQBsAGIAdQByMAUCAwDFSQwMSWNlIGlj +ZSBiYWJ5MAsGCSqGSIb3DQEBBQMBAA== +-----END CERTIFICATE----- diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t index 22379ec5f9fd3..2501af434f9b0 100644 --- a/test/recipes/25-test_x509.t +++ b/test/recipes/25-test_x509.t @@ -16,7 +16,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_x509"); -plan tests => 88; +plan tests => 93; # Prevent MSys2 filename munging for arguments that look like file paths but # aren't @@ -269,6 +269,23 @@ cert_contains($acc_priv_pol, "organizationName", 1, 'X509v3 Acceptable Certification Policies'); +my $user_notice_cert = srctop_file(@certs, "ext-userNotice.pem"); +cert_contains($user_notice_cert, + "Organization: Wildboar Software", + 1, 'X509v3 User Notice'); +cert_contains($user_notice_cert, + "Numbers: 123, 456", + 1, 'X509v3 User Notice'); +cert_contains($user_notice_cert, + "Explicit Text: Hey there big boi", + 1, 'X509v3 User Notice'); +cert_contains($user_notice_cert, + "Number: 50505", + 1, 'X509v3 User Notice'); +cert_contains($user_notice_cert, + "Explicit Text: Ice ice baby", + 1, 'X509v3 User Notice'); + sub test_errors { # actually tests diagnostics of OSSL_STORE my ($expected, $cert, @opts) = @_; my $infile = srctop_file(@certs, $cert); From 59c415a45f47cb34147427e46c78d945919b1da2 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Wed, 3 Jul 2024 15:12:01 +0200 Subject: [PATCH 090/138] Fix incorrect sentence Remove superfluous "the" from sentence. CLA: trivial Reviewed-by: Neil Horman Reviewed-by: Kurt Roeckx Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24790) --- doc/man3/SSL_CTX_set_cipher_list.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man3/SSL_CTX_set_cipher_list.pod b/doc/man3/SSL_CTX_set_cipher_list.pod index 0fe8be8094c8f..5e93b9ab75f63 100644 --- a/doc/man3/SSL_CTX_set_cipher_list.pod +++ b/doc/man3/SSL_CTX_set_cipher_list.pod @@ -56,7 +56,7 @@ ciphersuite names in order of preference. Valid TLSv1.3 ciphersuite names are: =back -An empty list is permissible. The default value for the this setting is: +An empty list is permissible. The default value for this setting is: "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" From 29696af689df734cae05181d85ee04470c3839d3 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 2 Jul 2024 15:36:03 +0200 Subject: [PATCH 091/138] fuzz/decoder.c: Lower the limits on key checks These checks still take too long time on clusterfuzz so they are longer than the timeout limit. Reviewed-by: Neil Horman Reviewed-by: Kurt Roeckx (Merged from https://github.com/openssl/openssl/pull/24781) --- fuzz/decoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzz/decoder.c b/fuzz/decoder.c index 4888c5cd40e46..f8758d5e344e3 100644 --- a/fuzz/decoder.c +++ b/fuzz/decoder.c @@ -69,12 +69,12 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) * Skip it. */ if ((!EVP_PKEY_is_a(pkey, "DH") && !EVP_PKEY_is_a(pkey, "DHX")) - || EVP_PKEY_get_bits(pkey) <= 8192) + || EVP_PKEY_get_bits(pkey) <= 2048) EVP_PKEY_param_check(ctx); EVP_PKEY_public_check(ctx); /* Private and pairwise checks are unbounded, skip for large keys. */ - if (EVP_PKEY_get_bits(pkey) <= 16384) { + if (EVP_PKEY_get_bits(pkey) <= 4096) { EVP_PKEY_private_check(ctx); EVP_PKEY_pairwise_check(ctx); } From 82a13a1f5053462f826bfb90061f0f77e3cc98a5 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Tue, 14 Nov 2023 02:55:36 +0100 Subject: [PATCH 092/138] Fix possible double-free in pkcs7 add_attribute function The problem is the ownership of the input parameter value is transfered to the X509_ATTRIBUTE object attr, as soon as X509_ATTRIBUTE_create succeeds, but when an error happens after that point there is no way to get the ownership back to the caller, which is necessary to fullfill the API contract. Fixed that by moving the call to X509_ATTRIBUTE_create to the end of the function, and make sure that no errors are possible after that point. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/22721) --- crypto/pkcs7/pk7_doit.c | 43 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index c753a0880b14f..4748d4207d9f0 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -1234,36 +1234,29 @@ static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, void *value) { X509_ATTRIBUTE *attr = NULL; + int i, n; if (*sk == NULL) { if ((*sk = sk_X509_ATTRIBUTE_new_null()) == NULL) return 0; - new_attrib: - if ((attr = X509_ATTRIBUTE_create(nid, atrtype, value)) == NULL) - return 0; - if (!sk_X509_ATTRIBUTE_push(*sk, attr)) { - X509_ATTRIBUTE_free(attr); - return 0; - } - } else { - int i; - - for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) { - attr = sk_X509_ATTRIBUTE_value(*sk, i); - if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) { - X509_ATTRIBUTE_free(attr); - attr = X509_ATTRIBUTE_create(nid, atrtype, value); - if (attr == NULL) - return 0; - if (!sk_X509_ATTRIBUTE_set(*sk, i, attr)) { - X509_ATTRIBUTE_free(attr); - return 0; - } - goto end; - } - } - goto new_attrib; } + n = sk_X509_ATTRIBUTE_num(*sk); + for (i = 0; i < n; i++) { + attr = sk_X509_ATTRIBUTE_value(*sk, i); + if (OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)) == nid) + goto end; + } + if (!sk_X509_ATTRIBUTE_push(*sk, NULL)) + return 0; + end: + attr = X509_ATTRIBUTE_create(nid, atrtype, value); + if (attr == NULL) { + if (i == n) + sk_X509_ATTRIBUTE_pop(*sk); + return 0; + } + X509_ATTRIBUTE_free(sk_X509_ATTRIBUTE_value(*sk, i)); + (void) sk_X509_ATTRIBUTE_set(*sk, i, attr); return 1; } From 35b1472f0764c8691e0cfcd6a2e0265aafd08f93 Mon Sep 17 00:00:00 2001 From: MrRurikov <96385824+MrRurikov@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:20:27 +0300 Subject: [PATCH 093/138] Add (void) cast to result of ossl_quic_rxfc_on_retire() Return value of function 'ossl_quic_rxfc_on_retire', called at quic_stream_map.c:767, is not checked, but it is usually checked for this function. CLA: trivial Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24794) --- ssl/quic/quic_stream_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c index c836721f78170..64700b09d95e0 100644 --- a/ssl/quic/quic_stream_map.c +++ b/ssl/quic/quic_stream_map.c @@ -764,7 +764,7 @@ void ossl_quic_stream_map_remove_from_accept_queue(QUIC_STREAM_MAP *qsm, --qsm->num_accept_uni; if ((max_streams_rxfc = qsm_get_max_streams_rxfc(qsm, s)) != NULL) - ossl_quic_rxfc_on_retire(max_streams_rxfc, 1, rtt); + (void)ossl_quic_rxfc_on_retire(max_streams_rxfc, 1, rtt); } size_t ossl_quic_stream_map_get_accept_queue_len(QUIC_STREAM_MAP *qsm, int is_uni) From f35c0894130e34ff46a429f4373c14ca98437405 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Sat, 6 Jul 2024 17:55:25 +0200 Subject: [PATCH 094/138] check_format.pl: fix detection of 'if' with single stmt in braces without 'else' Reviewed-by: Richard Levitte Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/24805) --- util/check-format-test-negatives.c | 3 +-- util/check-format.pl | 11 +++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/util/check-format-test-negatives.c b/util/check-format-test-negatives.c index 8b3b75db3e01b..3bbe0d46b6be4 100644 --- a/util/check-format-test-negatives.c +++ b/util/check-format-test-negatives.c @@ -335,9 +335,8 @@ size_t UTIL_url_encode(const char *source, int f() { c; - if (1) { + if (1) c; - } c; if (1) if (2) diff --git a/util/check-format.pl b/util/check-format.pl index e1a91bcc58150..04dde14c9d99f 100755 --- a/util/check-format.pl +++ b/util/check-format.pl @@ -167,7 +167,7 @@ my $line_body_start; # number of line where last function body started, or 0 my $line_function_start; # number of line where last function definition started, used for $line_body_start my $last_function_header; # header containing name of last function defined, used if $line_body_start != 0 -my $line_opening_brace; # number of previous line with opening brace after do/while/for, optionally for if/else +my $line_opening_brace; # number of previous line with opening brace after if/do/while/for, optionally for 'else' my $keyword_opening_brace; # name of previous keyword, used if $line_opening_brace != 0 my $block_indent; # currently required normal indentation at block/statement level @@ -972,9 +972,12 @@ sub check_nested_nonblock_indents { # check for code block containing a single line/statement if ($line_before2 > 0 && !$outermost_level && # within function body $in_typedecl == 0 && @nested_indents == 0 && # neither within type declaration nor inside stmt/expr - m/^[\s@]*\}/) { # leading closing brace '}', any preceding blinded comment must not be matched + m/^[\s@]*\}\s*(\w*)/) { # leading closing brace '}', any preceding blinded comment must not be matched # TODO extend detection from single-line to potentially multi-line statement + my $next_word = $1; if ($line_opening_brace > 0 && + ($keyword_opening_brace ne "if" || + $extended_1_stmt || $next_word ne "else") && ($line_opening_brace == $line_before2 || $line_opening_brace == $line_before) && $contents_before =~ m/;/) { # there is at least one terminator ';', so there is some stmt @@ -1132,9 +1135,9 @@ sub check_nested_nonblock_indents { $line_body_start = $contents =~ m/LONG BODY/ ? 0 : $line if $line_function_start != 0; } } else { - $line_opening_brace = $line if $keyword_opening_brace =~ m/do|while|for/; + $line_opening_brace = $line if $keyword_opening_brace =~ m/if|do|while|for/; # using, not assigning, $keyword_opening_brace here because it could be on an earlier line - $line_opening_brace = $line if $keyword_opening_brace =~ m/if|else/ && $extended_1_stmt && + $line_opening_brace = $line if $keyword_opening_brace eq "else" && $extended_1_stmt && # TODO prevent false positives for if/else where braces around single-statement branches # should be avoided but only if all branches have just single statements # The following helps detecting the exception when handling multiple 'if ... else' branches: From c215d75f94fcaa598817e739221f33b71b53fb39 Mon Sep 17 00:00:00 2001 From: Radek Krejci Date: Thu, 21 Mar 2024 13:19:23 +0100 Subject: [PATCH 095/138] Avoid NULL pointer dereference Function readbuffer_gets() misses some of the initial checks of its arguments. Not checking them can lead to a later NULL pointer dereferences. The checks are now unified with the checks in readbuffer_read() function. CLA: trivial Fixes #23915 Signed-off-by: Radek Krejci Reviewed-by: Tom Cosgrove Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23918) --- crypto/bio/bf_readbuff.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crypto/bio/bf_readbuff.c b/crypto/bio/bf_readbuff.c index 135ccef83bf3c..62490b9a2b369 100644 --- a/crypto/bio/bf_readbuff.c +++ b/crypto/bio/bf_readbuff.c @@ -222,10 +222,13 @@ static int readbuffer_gets(BIO *b, char *buf, int size) char *p; int i, j; - if (size == 0) + if (buf == NULL || size == 0) return 0; --size; /* the passed in size includes the terminator - so remove it here */ ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + if (ctx == NULL || b->next_bio == NULL) + return 0; BIO_clear_retry_flags(b); /* If data is already buffered then use this first */ From dd2b22d88c9c974f4ca6bce2550f89ac7fb76839 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 6 Jun 2024 14:37:37 -0400 Subject: [PATCH 096/138] Add defaults api to openssl build Build time defaults aren't great for windows, in which various macros (like OPENSSLDIR) are selected at build time, but may be selected differently at install time. Add an internal defaults api to return the build time constants on unix systems, but instead query registry keys for the form: HLKM\SOFTWARE\OpenSSL-{version}-{wininstallcontext} Such that each built version of openssl may maintain its own set of registry keys to identify these locations, and be set administratiely as appropriate at install or run time Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 22 +++++ crypto/build.info | 2 +- crypto/defaults.c | 198 ++++++++++++++++++++++++++++++++++++++ include/internal/common.h | 5 + 4 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 crypto/defaults.c diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index f4573fd4308d8..e218f28bee768 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -125,6 +125,28 @@ Administrator" before running `nmake install`. The other solution is, of course, to choose a different set of directories by using `--prefix` and `--openssldir` when configuring. +Note that, on Windows platforms (both 32 and 64 bit), the above build time +defaults can be overridden by registry keys. This is done because it is common +practice for windows based installers to allow users to place the installation +tree at various locations not defined at build time. The following keys: + + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\OPENSSLDIR` + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\ENGINESDIR` + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\MODULESDIR` + +Can be administratively set, and openssl will take the paths found there as the +values for OPENSSLDIR, ENGINESDIR and MODULESDIR respectively. If unset, the +build time defaults will be used. + +To enable the reading of registry keys from windows builds, add +`-DWININSTALLCONTEXT=`to the Configure command line. Without setting +this, the library defaults back to reporing the build time defaults without +checking the registry. Note that if you wish to have a private set of registry +keys for your application, you should set `OPENSSL_VERSION` to a unique value + +Note the installer available at will set +these keys when the installer is run. + Special notes for Universal Windows Platform builds, aka `VC-*-UWP` ------------------------------------------------------------------- diff --git a/crypto/build.info b/crypto/build.info index 90a3b78cda28a..881007f8acb17 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -107,7 +107,7 @@ SOURCE[../libcrypto]=$UTIL_COMMON \ comp_methods.c cversion.c info.c cpt_err.c ebcdic.c uid.c o_time.c \ o_dir.c o_fopen.c getenv.c o_init.c init.c trace.c provider.c \ provider_child.c punycode.c passphrase.c sleep.c deterministic_nonce.c \ - quic_vlint.c time.c + quic_vlint.c time.c defaults.c SOURCE[../providers/libfips.a]=$UTIL_COMMON SOURCE[../libcrypto]=$UPLINKSRC diff --git a/crypto/defaults.c b/crypto/defaults.c new file mode 100644 index 0000000000000..792029eab450e --- /dev/null +++ b/crypto/defaults.c @@ -0,0 +1,198 @@ +/* + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include "internal/thread_once.h" +#include "internal/cryptlib.h" +#include "internal/e_os.h" + +#if defined(_WIN32) + +# define TOSTR(x) #x +# define MAKESTR(x) TOSTR(x) +# define NOQUOTE(x) x +#if defined(WININSTALLCONTEXT) +# define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(WININSTALLCONTEXT) +#else +# define REGISTRY_KEY "NONE" +#endif + +/** + * @brief The directory where OpenSSL is installed. + */ +static char openssldir[MAX_PATH + 1]; + +/** + * @brief The directory where OpenSSL engines are located. + */ + +static char enginesdir[MAX_PATH + 1]; + +/** + * @brief The directory where OpenSSL modules are located. + */ +static char modulesdir[MAX_PATH + 1]; + +/** + * @brief Get the list of Windows registry directories. + * + * This function retrieves a list of Windows registry directories. + * + * @return A pointer to a char array containing the registry directories. + */ +static char *get_windows_regdirs(char *dst, LPCTSTR valuename) +{ + DWORD keysize; + DWORD ktype; + HKEY hkey; + LSTATUS ret; + DWORD index = 0; + LPCTCH tempstr = NULL; + char *retval = NULL; + + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT(REGISTRY_KEY), KEY_WOW64_32KEY, + KEY_QUERY_VALUE, &hkey); + if (ret != ERROR_SUCCESS) + goto out; + + ret = RegQueryValueEx(hkey, valuename, NULL, &ktype, NULL, + &keysize); + if (ret != ERROR_SUCCESS) + goto out; + if (ktype != REG_EXPAND_SZ) + goto out; + if (keysize > MAX_PATH) + goto out; + + keysize++; + tempstr = OPENSSL_zalloc(keysize * sizeof(TCHAR)); + + if (tempstr == NULL) + goto out; + + if (RegQueryValueEx(hkey, valuename, + NULL, &ktype, tempstr, &keysize) != ERROR_SUCCESS) + goto out; + + if (!WideCharToMultiByte(CP_UTF8, 0, tempstr, -1, dst, keysize, + NULL, NULL)) + goto out; + + retval = dst; +out: + OPENSSL_free(tempstr); + RegCloseKey(hkey); + return retval; +} + +static CRYPTO_ONCE defaults_setup_init = CRYPTO_ONCE_STATIC_INIT; + +/** + * @brief Function to setup default values to run once. + * Only used in Windows environments. Does run time initalization + * of openssldir/modulesdir/enginesdir from the registry + */ +DEFINE_RUN_ONCE_STATIC(do_defaults_setup) +{ + char *tmp; + tmp = get_windows_regdirs(openssldir, TEXT("OPENSSLDIR")); +# ifdef OPENSSLDIR + if (tmp == NULL) + strncpy(openssldir, OPENSSLDIR, MAX_PATH); +# endif + tmp = get_windows_regdirs(enginesdir, TEXT("ENGINESDIR")); +# ifdef ENGINESDIR + if (tmp == NULL) + strncpy(enginesdir, ENGINESDIR, MAX_PATH); +# endif + tmp = get_windows_regdirs(modulesdir, TEXT("MODULESDIR")); +# ifdef MODULESDIR + if (tmp == NULL) + strncpy(modulesdir, MODULESDIR, MAX_PATH); +# endif + + return 1; +} +#endif + +/** + * @brief Get the directory where OpenSSL is installed. + * + * @return A pointer to a string containing the OpenSSL directory path. + */ +const char *ossl_get_openssldir(void) +{ +#if defined(_WIN32) && defined(WININSTALLCONTEXT) + if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) + return NULL; + return (const char *)openssldir; +#else +# ifdef OPENSSLDIR + return OPENSSLDIR; +# else + return ""; +# endif +#endif +} + +/** + * @brief Get the directory where OpenSSL engines are located. + * + * @return A pointer to a string containing the engines directory path. + */ +const char *ossl_get_enginesdir(void) +{ +#if defined(_WIN32) && defined(WININSTALLCONTEXT) + if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) + return NULL; + return (const char *)enginesdir; +#else +# ifdef OPENSSLDIR + return ENGINESDIR; +# else + return ""; +# endif +#endif +} + +/** + * @brief Get the directory where OpenSSL modules are located. + * + * @return A pointer to a string containing the modules directory path. + */ +const char *ossl_get_modulesdir(void) +{ +#if defined(_WIN32) && defined(WININSTALLCONTEXT) + if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) + return NULL; + return (const char *)modulesdir; +#else +# ifdef OPENSSLDIR + return MODULESDIR; +# else + return ""; +# endif +#endif +} + +/** + * @brief Get the build time defined windows installer context + * + * @return A char pointer to a string representing the windows install context + */ +const char *ossl_get_wininstallcontext(void) +{ +#if defined(_WIN32) && defined (WININSTALLCONTEXT) + return MAKESTR(WININSTALLCONTEXT); +#else + return ""; +#endif +} diff --git a/include/internal/common.h b/include/internal/common.h index b176a27494ed5..0c0415b777bd4 100644 --- a/include/internal/common.h +++ b/include/internal/common.h @@ -228,4 +228,9 @@ static ossl_inline int ossl_is_absolute_path(const char *path) return path[0] == '/'; } +const char *ossl_get_openssldir(void); +const char *ossl_get_enginesdir(void); +const char *ossl_get_modulesdir(void); +const char *ossl_get_wininstallcontext(void); + #endif From e6c77f26855661ec4bfe0a91fcf1c718ac48967f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 6 Jun 2024 14:38:43 -0400 Subject: [PATCH 097/138] convert users of build time defaults to use new defaults api Now that we can query for install time registry keys on windows, convert users of these macros to use the api instead Add a unit test to validate the functionality of our reg key lookups Add a test to check to make sure our registry key lookups work. note this test only runs on windows (clearly), but also only if the registry keys are set via an installer or some other manual process (to be done in the CI workflow) Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- apps/version.c | 16 +++++++---- crypto/cversion.c | 21 ++++---------- crypto/engine/eng_list.c | 4 +-- crypto/info.c | 6 ++-- crypto/provider_core.c | 2 +- crypto/x509/x509_def.c | 51 +++++++++++++++++++++++++++++++++ doc/man1/openssl-version.pod.in | 6 ++++ include/openssl/crypto.h.in | 1 + 8 files changed, 81 insertions(+), 26 deletions(-) diff --git a/apps/version.c b/apps/version.c index 7185e9edcd1dd..50ae1388be03b 100644 --- a/apps/version.c +++ b/apps/version.c @@ -18,7 +18,7 @@ typedef enum OPTION_choice { OPT_COMMON, - OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, OPT_C + OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, OPT_C, OPT_W } OPTION_CHOICE; const OPTIONS version_options[] = { @@ -37,6 +37,7 @@ const OPTIONS version_options[] = { {"r", OPT_R, '-', "Show random seeding options"}, {"v", OPT_V, '-', "Show library version"}, {"c", OPT_C, '-', "Show CPU settings info"}, + {"w", OPT_W, '-', "Show Windows install context"}, {NULL} }; @@ -44,7 +45,7 @@ int version_main(int argc, char **argv) { int ret = 1, dirty = 0, seed = 0; int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0; - int engdir = 0, moddir = 0, cpuinfo = 0; + int engdir = 0, moddir = 0, cpuinfo = 0, windows = 0; char *prog; OPTION_CHOICE o; @@ -90,6 +91,9 @@ int version_main(int argc, char **argv) case OPT_C: dirty = cpuinfo = 1; break; + case OPT_W: + dirty = windows = 1; + break; case OPT_A: seed = options = cflags = version = date = platform = dir = engdir = moddir = cpuinfo @@ -120,17 +124,19 @@ int version_main(int argc, char **argv) if (cflags) printf("%s\n", OpenSSL_version(OPENSSL_CFLAGS)); if (dir) - printf("%s\n", OpenSSL_version(OPENSSL_DIR)); + printf("OPENSSLDIR: %s\n", OpenSSL_version(OPENSSL_DIR)); if (engdir) - printf("%s\n", OpenSSL_version(OPENSSL_ENGINES_DIR)); + printf("ENGINESDIR: %s\n", OpenSSL_version(OPENSSL_ENGINES_DIR)); if (moddir) - printf("%s\n", OpenSSL_version(OPENSSL_MODULES_DIR)); + printf("MODULESDIR: %s\n", OpenSSL_version(OPENSSL_MODULES_DIR)); if (seed) { const char *src = OPENSSL_info(OPENSSL_INFO_SEED_SOURCE); printf("Seeding source: %s\n", src ? src : "N/A"); } if (cpuinfo) printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); + if (windows) + printf("WININSTALLCONTEXT: %s\n", OpenSSL_version(OPENSSL_WININSTALLCONTEXT)); ret = 0; end: return ret; diff --git a/crypto/cversion.c b/crypto/cversion.c index 530b0e805e8dd..d3f193a9efb4c 100644 --- a/crypto/cversion.c +++ b/crypto/cversion.c @@ -8,6 +8,7 @@ */ #include "internal/cryptlib.h" +#include "internal/common.h" #include "buildinf.h" @@ -59,28 +60,18 @@ const char *OpenSSL_version(int t) case OPENSSL_PLATFORM: return PLATFORM; case OPENSSL_DIR: -#ifdef OPENSSLDIR - return "OPENSSLDIR: \"" OPENSSLDIR "\""; -#else - return "OPENSSLDIR: N/A"; -#endif + return ossl_get_openssldir(); case OPENSSL_ENGINES_DIR: -#ifdef ENGINESDIR - return "ENGINESDIR: \"" ENGINESDIR "\""; -#else - return "ENGINESDIR: N/A"; -#endif + return ossl_get_enginesdir(); case OPENSSL_MODULES_DIR: -#ifdef MODULESDIR - return "MODULESDIR: \"" MODULESDIR "\""; -#else - return "MODULESDIR: N/A"; -#endif + return ossl_get_modulesdir(); case OPENSSL_CPU_INFO: if (OPENSSL_info(OPENSSL_INFO_CPU_SETTINGS) != NULL) return ossl_cpu_info_str; else return "CPUINFO: N/A"; + case OPENSSL_WININSTALLCONTEXT: + return ossl_get_wininstallcontext(); } return "not available"; } diff --git a/crypto/engine/eng_list.c b/crypto/engine/eng_list.c index eafca3ec49ce8..b46403e556a9c 100644 --- a/crypto/engine/eng_list.c +++ b/crypto/engine/eng_list.c @@ -408,7 +408,7 @@ static void engine_cpy(ENGINE *dest, const ENGINE *src) ENGINE *ENGINE_by_id(const char *id) { ENGINE *iterator; - char *load_dir = NULL; + const char *load_dir = NULL; if (id == NULL) { ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); return NULL; @@ -459,7 +459,7 @@ ENGINE *ENGINE_by_id(const char *id) */ if (strcmp(id, "dynamic")) { if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL) - load_dir = ENGINESDIR; + load_dir = ossl_get_enginesdir(); iterator = ENGINE_by_id("dynamic"); if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) || !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) || diff --git a/crypto/info.c b/crypto/info.c index c823283279ba9..0dc26bd6f58d0 100644 --- a/crypto/info.c +++ b/crypto/info.c @@ -199,11 +199,11 @@ const char *OPENSSL_info(int t) switch (t) { case OPENSSL_INFO_CONFIG_DIR: - return OPENSSLDIR; + return ossl_get_openssldir(); case OPENSSL_INFO_ENGINES_DIR: - return ENGINESDIR; + return ossl_get_enginesdir(); case OPENSSL_INFO_MODULES_DIR: - return MODULESDIR; + return ossl_get_modulesdir(); case OPENSSL_INFO_DSO_EXTENSION: return DSO_EXTENSION; case OPENSSL_INFO_DIR_FILENAME_SEPARATOR: diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 297b281a39fc0..693e2913d5476 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -920,7 +920,7 @@ static int provider_init(OSSL_PROVIDER *prov) if (load_dir == NULL) { load_dir = ossl_safe_getenv("OPENSSL_MODULES"); if (load_dir == NULL) - load_dir = MODULESDIR; + load_dir = ossl_get_modulesdir(); } DSO_ctrl(prov->module, DSO_CTRL_SET_FLAGS, diff --git a/crypto/x509/x509_def.c b/crypto/x509/x509_def.c index 2851fbcd9f93b..874c61d7f13b9 100644 --- a/crypto/x509/x509_def.c +++ b/crypto/x509/x509_def.c @@ -8,28 +8,79 @@ */ #include +#include "internal/e_os.h" #include "internal/cryptlib.h" +#include "internal/thread_once.h" #include #include +#if defined(_WIN32) + +static char x509_private_dir[MAX_PATH + 1]; +static char x509_cert_area[MAX_PATH + 1]; +static char x509_cert_dir[MAX_PATH + 1]; +static char x509_cert_file[MAX_PATH + 1]; + +static void get_windows_default_path(char *pathname, const char *suffix) +{ + char *ossldir; + + ossldir = ossl_get_openssldir(); + + OPENSSL_strlcpy(pathname, ossldir, MAX_PATH - 1); + if (MAX_PATH - strlen(pathname) > strlen(suffix)) + strcat(pathname, suffix); +} + +static CRYPTO_ONCE openssldir_setup_init = CRYPTO_ONCE_STATIC_INIT; +DEFINE_RUN_ONCE_STATIC(do_openssldir_setup) +{ + get_windows_default_path(x509_private_dir, "\\private"); + get_windows_default_path(x509_cert_area, "\\"); + get_windows_default_path(x509_cert_dir, "\\certs"); + get_windows_default_path(x509_cert_file, "\\cert.pem"); + return 1; +} +#endif + const char *X509_get_default_private_dir(void) { +#if defined (_WIN32) + RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); + return x509_private_dir; +#else return X509_PRIVATE_DIR; +#endif } const char *X509_get_default_cert_area(void) { +#if defined (_WIN32) + RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); + return x509_cert_area; +#else return X509_CERT_AREA; +#endif } const char *X509_get_default_cert_dir(void) { +#if defined (_WIN32) + RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); + return x509_cert_dir; +#else return X509_CERT_DIR; +#endif } const char *X509_get_default_cert_file(void) { +#if defined (_WIN32) + RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); + return x509_cert_file; +#else return X509_CERT_FILE; +#endif } const char *X509_get_default_cert_dir_env(void) diff --git a/doc/man1/openssl-version.pod.in b/doc/man1/openssl-version.pod.in index b2f09107242bc..7b6e2e9788b96 100644 --- a/doc/man1/openssl-version.pod.in +++ b/doc/man1/openssl-version.pod.in @@ -20,6 +20,7 @@ B [B<-m>] [B<-r>] [B<-c>] +[B<-w>] =head1 DESCRIPTION @@ -77,6 +78,11 @@ The random number generator source settings. The OpenSSL CPU settings info. +=item B<-w> + +The OpenSSL WININSTALLCONTEXT build time variable, if set. +Used for computing Windows registry key names + =back =head1 NOTES diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index 1bc8ae4cce06f..ee92bf61d2274 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -170,6 +170,7 @@ const char *OpenSSL_version(int type); # define OPENSSL_FULL_VERSION_STRING 7 # define OPENSSL_MODULES_DIR 8 # define OPENSSL_CPU_INFO 9 +# define OPENSSL_WININSTALLCONTEXT 10 const char *OPENSSL_info(int type); /* From 17309181613ae99b9a3d5cfefe76fd09e32d341b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 6 Jun 2024 14:39:36 -0400 Subject: [PATCH 098/138] Add a unit test to validate the functionality of our reg key lookups Add a test to check to make sure our registry key lookups work. note this test only runs on windows (clearly), but also only if the registry keys are set via an installer or some other manual process (to be done in the CI workflow) Also add workflow steps to set registry keys for testing Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 18 +++++- test/recipes/02-test_windows_registry.t | 85 +++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 test/recipes/02-test_windows_registry.t diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c24e7f894d1e0..48b906ae30979 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -41,7 +41,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured no-makedepend ${{ matrix.platform.config }} + perl ..\Configure --banner=Configured no-makedepend -DWININSTALLCONTEXT=openssl ${{ matrix.platform.config }} perl configdata.pm --dump - name: build working-directory: _build @@ -51,6 +51,18 @@ jobs: with: url: "https://download.sysinternals.com/files/Coreinfo.zip" target: _build/coreinfo/ + - name: Gather openssl version info + working-directory: _build + run: | + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" >> $GITHUB_ENV + - name: Set registry keys + working-directory: _build + run: | + echo $OSSL_VERSION + reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v OPENSSLDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe query HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v OPENSSLDIR /reg:32 - name: get cpu info working-directory: _build continue-on-error: true @@ -88,7 +100,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured enable-demos no-makedepend no-shared no-fips enable-md2 enable-rc5 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers enable-trace enable-crypto-mdebug VC-WIN64A-masm + perl ..\Configure --banner=Configured enable-demos no-makedepend no-shared no-fips enable-md2 enable-rc5 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers enable-trace enable-crypto-mdebug -DWININSTALLCONTEXT=openssl VC-WIN64A-masm perl configdata.pm --dump - name: build working-directory: _build @@ -125,7 +137,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured enable-demos no-makedepend no-bulk no-deprecated no-fips no-asm no-threads -DOPENSSL_SMALL_FOOTPRINT + perl ..\Configure --banner=Configured enable-demos no-makedepend no-bulk no-deprecated no-fips no-asm no-threads -DOPENSSL_SMALL_FOOTPRINT -DWININSTALLCONTEXT=openssl perl configdata.pm --dump - name: build working-directory: _build diff --git a/test/recipes/02-test_windows_registry.t b/test/recipes/02-test_windows_registry.t new file mode 100644 index 0000000000000..cee93a4c006f9 --- /dev/null +++ b/test/recipes/02-test_windows_registry.t @@ -0,0 +1,85 @@ +#! /usr/bin/env perl +# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +use OpenSSL::Test; +use OpenSSL::Test::Utils; +use OpenSSL::Test qw/:DEFAULT bldtop_file data_file srctop_file cmdstr/; + +setup("test_windows_registry"); + +plan skip_all => "Windows registry tests are only available on windows" + if $^O !~ /(MSWin)/; + +my $actual; +my $expect; + +my @tempout = run(app(["openssl", "version", "-w"]), capture => 1); +my $context = "@tempout"; +$context =~ s/^.*: //; + + +@tempout = run(app(["openssl", "version", "-v"]), capture => 1); +my $version = "@tempout"; +$version =~ s/^OpenSSL //; +$version =~ s/-.*\n//; + +my $regkey = "HKLM\\SOFTWARE\\OpenSSL-".$version."-".$context; +$regkey =~ s/\n//g; +print "REGKEY IS $regkey\n"; + +my $exit = run(cmd(["reg.exe", "query", $regkey, "/v", "OPENSSLDIR", "/reg:32"])); + +plan skip_all => "Skipping test as registry keys aren't set" + if $exit == 0; + +plan tests => 3; + +my @expectossldir = run(cmd(["reg.exe", "query", $regkey, "/reg:32", "/t", "REG_EXPAND_SZ", "/v", "OPENSSLDIR"]), capture => 1); + +my @expectengdir = run(cmd(["reg.exe", "query", $regkey, "/reg:32", "/t", "REG_EXPAND_SZ", "/v", "ENGINESDIR"]), capture => 1); + +my @expectmoddir = run(cmd(["reg.exe", "query", $regkey, "/reg:32", "/t", "REG_EXPAND_SZ", "/v", "MODULESDIR"]), capture => 1); + +my @osslversion = run(app(["openssl", "version", "-d"]), capture => 1); + +print "@osslversion"; +$expect = "@expectossldir"; +$actual = "@osslversion"; +$expect =~ s/HKEY_LOCAL_MACHINE.*\n*//; +$expect =~ s/\n//g; +$expect =~ s/.*REG_EXPAND_SZ *//; +$expect =~ s/ .*$//; +$actual =~ s/OPENSSLDIR: *//; + +ok(grep(/$expect/,$actual), "Confirming version output for openssldir from registry"); + +my @osslengineout = run(app(["openssl", "version", "-e"]), capture => 1); + +$expect = "@expectengdir"; +$actual = "@osslengineout"; +$expect =~ s/HKEY_LOCAL_MACHINE.*\n*//; +$expect =~ s/\n//g; +$expect =~ s/.*REG_EXPAND_SZ *//; +$expect =~ s/ .*$//; +$actual =~ s/ENGINESDIR: *//; + +ok(grep(/$expect/, $actual) == 1, "Confirming version output for enginesdir from registry"); + +my @osslmoduleout = run(app(["openssl", "version", "-m"]), capture => 1); + +$expect = "@expectmoddir"; +$actual = "@osslmoduleout"; +$expect =~ s/HKEY_LOCAL_MACHINE.*\n*//; +$expect =~ s/\n//g; +$expect =~ s/.*REG_EXPAND_SZ *//; +$expect =~ s/ .*$//; +$actual =~ s/MODULESSDIR: *//; +ok(grep(/$expect/, $actual) == 1, "Confirming version output for modulesdir from registry"); + + From c1c67561566d8d2ce0a378af110278778b9901d8 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 6 Jun 2024 15:09:57 -0400 Subject: [PATCH 099/138] Correct use of workflow ENV vars on windows On windows ci we're using powershell operations, need to follow those rules Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 48b906ae30979..49ee29669ca18 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -54,15 +54,18 @@ jobs: - name: Gather openssl version info working-directory: _build run: | - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" >> $GITHUB_ENV + apps/openssl.exe version -v + apps/openssl.exe version -v | awk '{print $2}' + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | - echo $OSSL_VERSION - reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v OPENSSLDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 - reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 - reg.exe add HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 - reg.exe query HKLM\SOFTWARE\OpenSSL-$OSSL_VERSION-openssl /v OPENSSLDIR /reg:32 + echo ${Env:OSSL_VERSION} + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe query HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /reg:32 - name: get cpu info working-directory: _build continue-on-error: true From f4540c1b14cb6928daffc53f0db332cd741fe91d Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 7 Jun 2024 13:26:57 -0400 Subject: [PATCH 100/138] dont fall back to build time defaults on windows to prevent security issues, don't fall back to build time default locations, instead return the string "UNDEFINED" Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- crypto/defaults.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/crypto/defaults.c b/crypto/defaults.c index 792029eab450e..e882d35c1f3f9 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -102,23 +102,9 @@ static CRYPTO_ONCE defaults_setup_init = CRYPTO_ONCE_STATIC_INIT; */ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) { - char *tmp; - tmp = get_windows_regdirs(openssldir, TEXT("OPENSSLDIR")); -# ifdef OPENSSLDIR - if (tmp == NULL) - strncpy(openssldir, OPENSSLDIR, MAX_PATH); -# endif - tmp = get_windows_regdirs(enginesdir, TEXT("ENGINESDIR")); -# ifdef ENGINESDIR - if (tmp == NULL) - strncpy(enginesdir, ENGINESDIR, MAX_PATH); -# endif - tmp = get_windows_regdirs(modulesdir, TEXT("MODULESDIR")); -# ifdef MODULESDIR - if (tmp == NULL) - strncpy(modulesdir, MODULESDIR, MAX_PATH); -# endif - + get_windows_regdirs(openssldir, TEXT("OPENSSLDIR")); + get_windows_regdirs(enginesdir, TEXT("ENGINESDIR")); + get_windows_regdirs(modulesdir, TEXT("MODULESDIR")); return 1; } #endif @@ -130,10 +116,14 @@ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) */ const char *ossl_get_openssldir(void) { -#if defined(_WIN32) && defined(WININSTALLCONTEXT) +#if defined(_WIN32) +# if defined(WININSTALLCONTEXT) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)openssldir; +# else + return "UNDEFINED"; +# endif #else # ifdef OPENSSLDIR return OPENSSLDIR; @@ -150,10 +140,14 @@ const char *ossl_get_openssldir(void) */ const char *ossl_get_enginesdir(void) { -#if defined(_WIN32) && defined(WININSTALLCONTEXT) +#if defined(_WIN32) +# if defined(WININSTALLCONTEXT) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)enginesdir; +# else + return "UNDEFINED"; +# endif #else # ifdef OPENSSLDIR return ENGINESDIR; @@ -170,12 +164,16 @@ const char *ossl_get_enginesdir(void) */ const char *ossl_get_modulesdir(void) { -#if defined(_WIN32) && defined(WININSTALLCONTEXT) +#if defined(_WIN32) +# if definied (WININSTALLCONTEXT) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)modulesdir; +# else + return "UNDEFINED"; +# endif #else -# ifdef OPENSSLDIR +# ifdef MODULESDIR return MODULESDIR; # else return ""; From 630e3a168446ab7e269176bad5b1bf79ea54301a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 7 Jun 2024 13:36:46 -0400 Subject: [PATCH 101/138] Change WININSTALLCONTEXT to OSSL_WINCTX Make it more in line with other command line defines, and a bit shorter Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 21 ++++++++++++--------- apps/version.c | 2 +- crypto/cversion.c | 2 +- crypto/defaults.c | 14 +++++++------- include/openssl/crypto.h.in | 2 +- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index e218f28bee768..f19bcab4f64a5 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -130,19 +130,22 @@ defaults can be overridden by registry keys. This is done because it is common practice for windows based installers to allow users to place the installation tree at various locations not defined at build time. The following keys: - `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\OPENSSLDIR` - `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\ENGINESDIR` - `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL\MODULESDIR` + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\OPENSSLDIR` + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\ENGINESDIR` + `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\MODULESDIR` Can be administratively set, and openssl will take the paths found there as the -values for OPENSSLDIR, ENGINESDIR and MODULESDIR respectively. If unset, the -build time defaults will be used. +values for OPENSSLDIR, ENGINESDIR and MODULESDIR respectively. To enable the reading of registry keys from windows builds, add -`-DWININSTALLCONTEXT=`to the Configure command line. Without setting -this, the library defaults back to reporing the build time defaults without -checking the registry. Note that if you wish to have a private set of registry -keys for your application, you should set `OPENSSL_VERSION` to a unique value +`-DOPENSSL_WINCTX=`to the Configure command line. This define is used +at build time to construct library build specific registry key paths of the +format: +`\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\OpenSSL--` +Where `` is the semantic major.minor.patch version of the library being +built, and `` is the value specified by `-DOPENSSL_WINCTX`. This allows +for multiple openssl builds to be created and installed on a single system, in +which each library can use its own set of registry keys. Note the installer available at will set these keys when the installer is run. diff --git a/apps/version.c b/apps/version.c index 50ae1388be03b..278afe8bf9344 100644 --- a/apps/version.c +++ b/apps/version.c @@ -136,7 +136,7 @@ int version_main(int argc, char **argv) if (cpuinfo) printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); if (windows) - printf("WININSTALLCONTEXT: %s\n", OpenSSL_version(OPENSSL_WININSTALLCONTEXT)); + printf("OSSL_WINCTX: %s\n", OpenSSL_version(OPENSSL_WINCTX)); ret = 0; end: return ret; diff --git a/crypto/cversion.c b/crypto/cversion.c index d3f193a9efb4c..219479f19a3f5 100644 --- a/crypto/cversion.c +++ b/crypto/cversion.c @@ -70,7 +70,7 @@ const char *OpenSSL_version(int t) return ossl_cpu_info_str; else return "CPUINFO: N/A"; - case OPENSSL_WININSTALLCONTEXT: + case OPENSSL_WINCTX: return ossl_get_wininstallcontext(); } return "not available"; diff --git a/crypto/defaults.c b/crypto/defaults.c index e882d35c1f3f9..56f2cb417a263 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -18,8 +18,8 @@ # define TOSTR(x) #x # define MAKESTR(x) TOSTR(x) # define NOQUOTE(x) x -#if defined(WININSTALLCONTEXT) -# define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(WININSTALLCONTEXT) +#if defined(OSSL_WINCTX) +# define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(OSSL_WINCTX) #else # define REGISTRY_KEY "NONE" #endif @@ -117,7 +117,7 @@ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) const char *ossl_get_openssldir(void) { #if defined(_WIN32) -# if defined(WININSTALLCONTEXT) +# if defined(OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)openssldir; @@ -141,7 +141,7 @@ const char *ossl_get_openssldir(void) const char *ossl_get_enginesdir(void) { #if defined(_WIN32) -# if defined(WININSTALLCONTEXT) +# if defined(OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)enginesdir; @@ -165,7 +165,7 @@ const char *ossl_get_enginesdir(void) const char *ossl_get_modulesdir(void) { #if defined(_WIN32) -# if definied (WININSTALLCONTEXT) +# if defined (OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)modulesdir; @@ -188,8 +188,8 @@ const char *ossl_get_modulesdir(void) */ const char *ossl_get_wininstallcontext(void) { -#if defined(_WIN32) && defined (WININSTALLCONTEXT) - return MAKESTR(WININSTALLCONTEXT); +#if defined(_WIN32) && defined (OSSL_WINCTX) + return MAKESTR(OSSL_WINCTX); #else return ""; #endif diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index ee92bf61d2274..99041cce065e2 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -170,7 +170,7 @@ const char *OpenSSL_version(int type); # define OPENSSL_FULL_VERSION_STRING 7 # define OPENSSL_MODULES_DIR 8 # define OPENSSL_CPU_INFO 9 -# define OPENSSL_WININSTALLCONTEXT 10 +# define OPENSSL_WINCTX 10 const char *OPENSSL_info(int type); /* From 525f2bf564b3d04680ab5722fff575ce690d7aee Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 7 Jun 2024 14:36:52 -0400 Subject: [PATCH 102/138] Fix windows ci to use proper OSSL_WINCTX define Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 49ee29669ca18..7790145b8c9ef 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -41,7 +41,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured no-makedepend -DWININSTALLCONTEXT=openssl ${{ matrix.platform.config }} + perl ..\Configure --banner=Configured no-makedepend -DOSSL_WINCTX=openssl ${{ matrix.platform.config }} perl configdata.pm --dump - name: build working-directory: _build @@ -103,7 +103,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured enable-demos no-makedepend no-shared no-fips enable-md2 enable-rc5 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers enable-trace enable-crypto-mdebug -DWININSTALLCONTEXT=openssl VC-WIN64A-masm + perl ..\Configure --banner=Configured enable-demos no-makedepend no-shared no-fips enable-md2 enable-rc5 enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers enable-trace enable-crypto-mdebug -DOSSL_WINCTX=openssl VC-WIN64A-masm perl configdata.pm --dump - name: build working-directory: _build @@ -140,7 +140,7 @@ jobs: - name: config working-directory: _build run: | - perl ..\Configure --banner=Configured enable-demos no-makedepend no-bulk no-deprecated no-fips no-asm no-threads -DOPENSSL_SMALL_FOOTPRINT -DWININSTALLCONTEXT=openssl + perl ..\Configure --banner=Configured enable-demos no-makedepend no-bulk no-deprecated no-fips no-asm no-threads -DOPENSSL_SMALL_FOOTPRINT -DOSSL_WINCTX=openssl perl configdata.pm --dump - name: build working-directory: _build From 4edcf0b450cd42d2037155d520b7e6323b624b6a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 21 Jun 2024 10:34:37 -0400 Subject: [PATCH 103/138] Don't fall back to pre-defined constants on windows We don't want to allow windows systems on new installs to use OPENSSLDIR/MODULESDIR/ENGINESDIR at all, as it makes no sense to define paths at build time that have no meaning at install time. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- crypto/defaults.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/crypto/defaults.c b/crypto/defaults.c index 56f2cb417a263..8f60d182e3656 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -121,15 +121,9 @@ const char *ossl_get_openssldir(void) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; return (const char *)openssldir; -# else - return "UNDEFINED"; # endif -#else -# ifdef OPENSSLDIR - return OPENSSLDIR; # else - return ""; -# endif + return OPENSSLDIR; #endif } @@ -149,11 +143,7 @@ const char *ossl_get_enginesdir(void) return "UNDEFINED"; # endif #else -# ifdef OPENSSLDIR return ENGINESDIR; -# else - return ""; -# endif #endif } @@ -173,11 +163,7 @@ const char *ossl_get_modulesdir(void) return "UNDEFINED"; # endif #else -# ifdef MODULESDIR return MODULESDIR; -# else - return ""; -# endif #endif } @@ -191,6 +177,6 @@ const char *ossl_get_wininstallcontext(void) #if defined(_WIN32) && defined (OSSL_WINCTX) return MAKESTR(OSSL_WINCTX); #else - return ""; + return "UNDEFINED"; #endif } From 901e27982c6bcd5ac94e455d2ef87e80398cd474 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 21 Jun 2024 11:05:22 -0400 Subject: [PATCH 104/138] Update NOTES-WINDOWS for typos/grammar Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index f19bcab4f64a5..d39bb90918e86 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -125,10 +125,10 @@ Administrator" before running `nmake install`. The other solution is, of course, to choose a different set of directories by using `--prefix` and `--openssldir` when configuring. -Note that, on Windows platforms (both 32 and 64 bit), the above build time +Note that, on Windows platforms (both 32 and 64 bit), the above build-time defaults can be overridden by registry keys. This is done because it is common -practice for windows based installers to allow users to place the installation -tree at various locations not defined at build time. The following keys: +practice for windows-based installers to allow users to place the installation +tree at an arbitrary location not defined at build-time. The following keys: `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\OPENSSLDIR` `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\ENGINESDIR` @@ -139,7 +139,7 @@ values for OPENSSLDIR, ENGINESDIR and MODULESDIR respectively. To enable the reading of registry keys from windows builds, add `-DOPENSSL_WINCTX=`to the Configure command line. This define is used -at build time to construct library build specific registry key paths of the +at build-time to construct library build specific registry key paths of the format: `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\OpenSSL--` Where `` is the semantic major.minor.patch version of the library being From 4fc9e5e0110e7199eaca43f54d604e36ce579567 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 21 Jun 2024 12:18:00 -0400 Subject: [PATCH 105/138] update windows_comp ci run to use new registry reads Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows_comp.yml | 34 ++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index 104e93d409178..2bf2332a239c5 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -33,10 +33,25 @@ jobs: working-directory: _build run: | vcpkg install zstd:x64-windows + - name: Gather openssl version info + working-directory: _build + run: | + apps/openssl.exe version -v + apps/openssl.exe version -v | awk '{print $2}' + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + - name: Set registry keys + working-directory: _build + run: | + echo ${Env:OSSL_VERSION} + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe query HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /reg:32 - name: config working-directory: _build run: | - perl ..\Configure enable-comp enable-zstd --with-zstd-include=C:\vcpkg\packages\zstd_x64-windows\include --with-zstd-lib=C:\vcpkg\packages\zstd_x64-windows\lib\zstd.lib no-makedepend VC-WIN64A + perl ..\Configure enable-comp enable-zstd --with-zstd-include=C:\vcpkg\packages\zstd_x64-windows\include --with-zstd-lib=C:\vcpkg\packages\zstd_x64-windows\lib\zstd.lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A perl configdata.pm --dump - name: build working-directory: _build @@ -75,10 +90,25 @@ jobs: working-directory: _build run: | vcpkg install brotli:x64-windows + - name: Gather openssl version info + working-directory: _build + run: | + apps/openssl.exe version -v + apps/openssl.exe version -v | awk '{print $2}' + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + - name: Set registry keys + working-directory: _build + run: | + echo ${Env:OSSL_VERSION} + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 + reg.exe query HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /reg:32 - name: config working-directory: _build run: | - perl ..\Configure enable-comp enable-brotli --with-brotli-include=C:\vcpkg\packages\brotli_x64-windows\include --with-brotli-lib=C:\vcpkg\packages\brotli_x64-windows\lib no-makedepend VC-WIN64A + perl ..\Configure enable-comp enable-brotli --with-brotli-include=C:\vcpkg\packages\brotli_x64-windows\include --with-brotli-lib=C:\vcpkg\packages\brotli_x64-windows\lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A perl configdata.pm --dump - name: build working-directory: _build From c7dae9c263fe507adc59e9ba2f34d473de04bbe9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 21 Jun 2024 13:53:59 -0400 Subject: [PATCH 106/138] Update docs Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- doc/man1/openssl-version.pod.in | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/man1/openssl-version.pod.in b/doc/man1/openssl-version.pod.in index 7b6e2e9788b96..dcfd60b9c343b 100644 --- a/doc/man1/openssl-version.pod.in +++ b/doc/man1/openssl-version.pod.in @@ -80,11 +80,28 @@ The OpenSSL CPU settings info. =item B<-w> -The OpenSSL WININSTALLCONTEXT build time variable, if set. -Used for computing Windows registry key names +The OpenSSL B build time variable, if set. +Used for computing Windows registry key names. This option is unavailable on +non-Windows platforms. =back +=head1 HISTORY + +In OpenSSL versions prior to 3.4, OpenSSL had a limitation regarding the +B, B and B build time macros. These macros +were defined at build time, and represented filesystem paths. This is common +practice on unix like systems, as there was an expectation that a given build +would be installed to a pre-determined location. On Windows however, there is +no such expectation, as libraries can be installed to arbitrary locations. +B was introduced as a new build time variable to define a set of +registry keys identified by the name openssl--, in which the + value is derived from the version string in the openssl source, and +the extension is derived from the B variable. The values of +B, B and B can be set to various paths +underneath this key to break the requirement to predict the installation path at +build time. + =head1 NOTES The output of C would typically be used when sending From 917f37195ac95252a4c90e86d7d7414c5569aed8 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 25 Jun 2024 10:57:52 -0400 Subject: [PATCH 107/138] Allow OPENSSLDIR/ENGINESDIR/MODULESDIR to be NULL To prevent inadvertent use of insecure directories, we need to be able to detect and react when our new registry keys aren't set, which implies allowing the values for the dynamic representations of OPENSSLDIR/ENGINESDIR/MODULESDIR to return NULL. This in turn requires that we detect and handle NULL string in several call sites that previously assumed they would never be NULL. This commit fixes those up Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 39 ++++------------ apps/info.c | 4 +- apps/version.c | 21 ++++++--- crypto/conf/conf_mod.c | 2 + crypto/cversion.c | 2 +- crypto/defaults.c | 62 ++++++++++++++++--------- crypto/o_fopen.c | 3 ++ crypto/x509/x509_def.c | 30 ++++++++++-- test/recipes/02-test_windows_registry.t | 2 - 9 files changed, 99 insertions(+), 66 deletions(-) diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index d39bb90918e86..cd8fdfb3f0d1d 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -99,36 +99,12 @@ check the INSTALL.md file. Installation directories ------------------------ -The default installation directories are derived from environment -variables. +On most Unix platform installation directories are determined at build time via +constant defines. On Windows platforms however, installation directories are +determined via registry keys, as it is common practice to build OpenSSL and +install it to a variety of locations. -For VC-WIN32, the following defaults are use: - - PREFIX: %ProgramFiles(x86)%\OpenSSL - OPENSSLDIR: %CommonProgramFiles(x86)%\SSL - -For VC-WIN64, the following defaults are use: - - PREFIX: %ProgramW6432%\OpenSSL - OPENSSLDIR: %CommonProgramW6432%\SSL - -Should those environment variables not exist (on a pure Win32 -installation for examples), these fallbacks are used: - - PREFIX: %ProgramFiles%\OpenSSL - OPENSSLDIR: %CommonProgramFiles%\SSL - -ALSO NOTE that those directories are usually write protected, even if -your account is in the Administrators group. To work around that, -start the command prompt by right-clicking on it and choosing "Run as -Administrator" before running `nmake install`. The other solution -is, of course, to choose a different set of directories by using -`--prefix` and `--openssldir` when configuring. - -Note that, on Windows platforms (both 32 and 64 bit), the above build-time -defaults can be overridden by registry keys. This is done because it is common -practice for windows-based installers to allow users to place the installation -tree at an arbitrary location not defined at build-time. The following keys: +The following keys: `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\OPENSSLDIR` `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\OpenSSL--\ENGINESDIR` @@ -142,6 +118,7 @@ To enable the reading of registry keys from windows builds, add at build-time to construct library build specific registry key paths of the format: `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\OpenSSL--` + Where `` is the semantic major.minor.patch version of the library being built, and `` is the value specified by `-DOPENSSL_WINCTX`. This allows for multiple openssl builds to be created and installed on a single system, in @@ -150,6 +127,10 @@ which each library can use its own set of registry keys. Note the installer available at will set these keys when the installer is run. +If the registry keys above do not exist on a given system, or if the +`OSSL_WINCTX` variable is not defined at build time, OpenSSL makes no attempt to +load configuration, engines of modules from disk. + Special notes for Universal Windows Platform builds, aka `VC-*-UWP` ------------------------------------------------------------------- diff --git a/apps/info.c b/apps/info.c index befc62dac1047..c024ba446eb2b 100644 --- a/apps/info.c +++ b/apps/info.c @@ -40,6 +40,7 @@ int info_main(int argc, char **argv) int ret = 1, dirty = 0, type = 0; char *prog; OPTION_CHOICE o; + const char *typedata; prog = opt_init(argc, argv, info_options); while ((o = opt_next()) != OPT_EOF) { @@ -97,7 +98,8 @@ int info_main(int argc, char **argv) goto opthelp; } - BIO_printf(bio_out, "%s\n", OPENSSL_info(type)); + typedata = OPENSSL_info(type); + BIO_printf(bio_out, "%s\n", typedata == NULL ? "Undefined" : typedata); ret = 0; end: return ret; diff --git a/apps/version.c b/apps/version.c index 278afe8bf9344..bfcb1f15f97c6 100644 --- a/apps/version.c +++ b/apps/version.c @@ -48,6 +48,7 @@ int version_main(int argc, char **argv) int engdir = 0, moddir = 0, cpuinfo = 0, windows = 0; char *prog; OPTION_CHOICE o; + const char *tmp; prog = opt_init(argc, argv, version_options); while ((o = opt_next()) != OPT_EOF) { @@ -123,12 +124,18 @@ int version_main(int argc, char **argv) } if (cflags) printf("%s\n", OpenSSL_version(OPENSSL_CFLAGS)); - if (dir) - printf("OPENSSLDIR: %s\n", OpenSSL_version(OPENSSL_DIR)); - if (engdir) - printf("ENGINESDIR: %s\n", OpenSSL_version(OPENSSL_ENGINES_DIR)); - if (moddir) - printf("MODULESDIR: %s\n", OpenSSL_version(OPENSSL_MODULES_DIR)); + if (dir) { + tmp = OpenSSL_version(OPENSSL_DIR); + printf("OPENSSLDIR: %s\n", tmp == NULL ? "Undefined" : tmp); + } + if (engdir) { + tmp = OpenSSL_version(OPENSSL_ENGINES_DIR); + printf("ENGINESDIR: %s\n", tmp == NULL ? "Undefined" : tmp); + } + if (moddir) { + tmp = OpenSSL_version(OPENSSL_MODULES_DIR); + printf("MODULESDIR: %s\n", tmp == NULL ? "Undefined" : tmp); + } if (seed) { const char *src = OPENSSL_info(OPENSSL_INFO_SEED_SOURCE); printf("Seeding source: %s\n", src ? src : "N/A"); @@ -136,7 +143,7 @@ int version_main(int argc, char **argv) if (cpuinfo) printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); if (windows) - printf("OSSL_WINCTX: %s\n", OpenSSL_version(OPENSSL_WINCTX)); + printf("OSSL_WINCTX: %s\n", OpenSSL_version(OPENSSL_WINCTX)); ret = 0; end: return ret; diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index 1ac3d9f7b7573..5e0681e6db315 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -692,6 +692,8 @@ char *CONF_get1_default_config_file(void) return OPENSSL_strdup(file); t = X509_get_default_cert_area(); + if (t == NULL) + return NULL; #ifndef OPENSSL_SYS_VMS sep = "/"; #endif diff --git a/crypto/cversion.c b/crypto/cversion.c index 219479f19a3f5..9c53041a69757 100644 --- a/crypto/cversion.c +++ b/crypto/cversion.c @@ -71,7 +71,7 @@ const char *OpenSSL_version(int t) else return "CPUINFO: N/A"; case OPENSSL_WINCTX: - return ossl_get_wininstallcontext(); + return ossl_get_wininstallcontext(); } return "not available"; } diff --git a/crypto/defaults.c b/crypto/defaults.c index 8f60d182e3656..2735efc63a94d 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -20,8 +20,6 @@ # define NOQUOTE(x) x #if defined(OSSL_WINCTX) # define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(OSSL_WINCTX) -#else -# define REGISTRY_KEY "NONE" #endif /** @@ -29,17 +27,32 @@ */ static char openssldir[MAX_PATH + 1]; +/** + * @brief The pointer to the opennsldir buffer + */ +static char *openssldirptr = NULL; + /** * @brief The directory where OpenSSL engines are located. */ static char enginesdir[MAX_PATH + 1]; +/** + * @brief The pointer to the enginesdir buffer + */ +static char *enginesdirptr = NULL; + /** * @brief The directory where OpenSSL modules are located. */ static char modulesdir[MAX_PATH + 1]; +/** + * @brief The pointer to the modulesdir buffer + */ +static char *modulesdirptr = NULL; + /** * @brief Get the list of Windows registry directories. * @@ -49,14 +62,15 @@ static char modulesdir[MAX_PATH + 1]; */ static char *get_windows_regdirs(char *dst, LPCTSTR valuename) { + char *retval = NULL; +#ifdef REGISTY_KEY DWORD keysize; DWORD ktype; HKEY hkey; LSTATUS ret; DWORD index = 0; LPCTCH tempstr = NULL; - char *retval = NULL; - + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGISTRY_KEY), KEY_WOW64_32KEY, KEY_QUERY_VALUE, &hkey); @@ -90,6 +104,7 @@ static char *get_windows_regdirs(char *dst, LPCTSTR valuename) out: OPENSSL_free(tempstr); RegCloseKey(hkey); +#endif return retval; } @@ -105,6 +120,19 @@ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) get_windows_regdirs(openssldir, TEXT("OPENSSLDIR")); get_windows_regdirs(enginesdir, TEXT("ENGINESDIR")); get_windows_regdirs(modulesdir, TEXT("MODULESDIR")); + + /* + * Set our pointers only if the directories are fetched properly + */ + if (strlen(openssldir) > 0) + openssldirptr = openssldir; + + if (strlen(enginesdir) > 0) + enginesdirptr = enginesdir; + + if (strlen(modulesdir) > 0) + modulesdirptr = modulesdir; + return 1; } #endif @@ -116,12 +144,10 @@ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) */ const char *ossl_get_openssldir(void) { -#if defined(_WIN32) -# if defined(OSSL_WINCTX) +#if defined(_WIN32) && defined (OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; - return (const char *)openssldir; -# endif + return (const char *)openssldirptr; # else return OPENSSLDIR; #endif @@ -134,14 +160,10 @@ const char *ossl_get_openssldir(void) */ const char *ossl_get_enginesdir(void) { -#if defined(_WIN32) -# if defined(OSSL_WINCTX) +#if defined(_WIN32) && defined (OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; - return (const char *)enginesdir; -# else - return "UNDEFINED"; -# endif + return (const char *)enginesdirptr; #else return ENGINESDIR; #endif @@ -154,14 +176,10 @@ const char *ossl_get_enginesdir(void) */ const char *ossl_get_modulesdir(void) { -#if defined(_WIN32) -# if defined (OSSL_WINCTX) +#if defined(_WIN32) && defined(OSSL_WINCTX) if (!RUN_ONCE(&defaults_setup_init, do_defaults_setup)) return NULL; - return (const char *)modulesdir; -# else - return "UNDEFINED"; -# endif + return (const char *)modulesdirptr; #else return MODULESDIR; #endif @@ -175,8 +193,8 @@ const char *ossl_get_modulesdir(void) const char *ossl_get_wininstallcontext(void) { #if defined(_WIN32) && defined (OSSL_WINCTX) - return MAKESTR(OSSL_WINCTX); + return MAKESTR(OSSL_WINCTX); #else - return "UNDEFINED"; + return "Undefined"; #endif } diff --git a/crypto/o_fopen.c b/crypto/o_fopen.c index 09c28e0bf7574..ed73e95578e05 100644 --- a/crypto/o_fopen.c +++ b/crypto/o_fopen.c @@ -38,6 +38,9 @@ FILE *openssl_fopen(const char *filename, const char *mode) { FILE *file = NULL; + + if (filename == NULL) + return NULL; # if defined(_WIN32) && defined(CP_UTF8) int sz, len_0 = (int)strlen(filename) + 1; DWORD flags; diff --git a/crypto/x509/x509_def.c b/crypto/x509/x509_def.c index 874c61d7f13b9..25fb014fcf79c 100644 --- a/crypto/x509/x509_def.c +++ b/crypto/x509/x509_def.c @@ -17,9 +17,16 @@ #if defined(_WIN32) static char x509_private_dir[MAX_PATH + 1]; +static char *x509_private_dirptr = NULL; + static char x509_cert_area[MAX_PATH + 1]; +static char *x509_cert_areaptr = NULL; + static char x509_cert_dir[MAX_PATH + 1]; +static char *x509_cert_dirptr = NULL; + static char x509_cert_file[MAX_PATH + 1]; +static char *x509_cert_fileptr = NULL; static void get_windows_default_path(char *pathname, const char *suffix) { @@ -27,6 +34,9 @@ static void get_windows_default_path(char *pathname, const char *suffix) ossldir = ossl_get_openssldir(); + if (ossldir == NULL) + return; + OPENSSL_strlcpy(pathname, ossldir, MAX_PATH - 1); if (MAX_PATH - strlen(pathname) > strlen(suffix)) strcat(pathname, suffix); @@ -36,9 +46,21 @@ static CRYPTO_ONCE openssldir_setup_init = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(do_openssldir_setup) { get_windows_default_path(x509_private_dir, "\\private"); + if (strlen(x509_private_dir) > 0) + x509_private_dirptr = x509_private_dir; + get_windows_default_path(x509_cert_area, "\\"); + if (strlen(x509_cert_area) > 0) + x509_cert_areaptr = x509_cert_area; + get_windows_default_path(x509_cert_dir, "\\certs"); + if (strlen(x509_cert_dir) > 0) + x509_cert_dirptr = x509_cert_dir; + get_windows_default_path(x509_cert_file, "\\cert.pem"); + if (strlen(x509_cert_file) > 0) + x509_cert_fileptr = x509_cert_file; + return 1; } #endif @@ -47,7 +69,7 @@ const char *X509_get_default_private_dir(void) { #if defined (_WIN32) RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); - return x509_private_dir; + return x509_private_dirptr; #else return X509_PRIVATE_DIR; #endif @@ -57,7 +79,7 @@ const char *X509_get_default_cert_area(void) { #if defined (_WIN32) RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); - return x509_cert_area; + return x509_cert_areaptr; #else return X509_CERT_AREA; #endif @@ -67,7 +89,7 @@ const char *X509_get_default_cert_dir(void) { #if defined (_WIN32) RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); - return x509_cert_dir; + return x509_cert_dirptr; #else return X509_CERT_DIR; #endif @@ -77,7 +99,7 @@ const char *X509_get_default_cert_file(void) { #if defined (_WIN32) RUN_ONCE(&openssldir_setup_init, do_openssldir_setup); - return x509_cert_file; + return x509_cert_fileptr; #else return X509_CERT_FILE; #endif diff --git a/test/recipes/02-test_windows_registry.t b/test/recipes/02-test_windows_registry.t index cee93a4c006f9..ceb6d99694592 100644 --- a/test/recipes/02-test_windows_registry.t +++ b/test/recipes/02-test_windows_registry.t @@ -81,5 +81,3 @@ $expect =~ s/.*REG_EXPAND_SZ *//; $expect =~ s/ .*$//; $actual =~ s/MODULESSDIR: *//; ok(grep(/$expect/, $actual) == 1, "Confirming version output for modulesdir from registry"); - - From 7c58769a036057f7a595c83db65e74175c116477 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 11:39:26 -0400 Subject: [PATCH 108/138] Add Changes entry Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0f3701c6d5140..7b3ec56fc851e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,12 @@ OpenSSL 3.4 ### Changes between 3.3 and 3.4 [xx XXX xxxx] + * Redesigned Windows use of OPENSSLDIR/ENGINESDIR/MODULESDIR such that + what were formerly build time locations can now be defined at run time + with registry keys. See NOTES-WINDOWS.md + + *Neil Horman* + * Added options `-not_before` and `-not_after` for explicit setting start and end dates of certificates created with the `req` and `x509` apps. Added the same options also to `ca` app as alias for From 62dd0f1762c9c5dd1df5f4220adec0fe5661c7c9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 11:50:46 -0400 Subject: [PATCH 109/138] Update NOTES-WINDOWS.md The behavior of windows with registry keys is somewhat confusing, and based on both build time defines, and reg key availablility. Add a table defining behavior in all cases Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index cd8fdfb3f0d1d..f7984cda0c125 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -99,7 +99,7 @@ check the INSTALL.md file. Installation directories ------------------------ -On most Unix platform installation directories are determined at build time via +On most Unix platforms installation directories are determined at build time via constant defines. On Windows platforms however, installation directories are determined via registry keys, as it is common practice to build OpenSSL and install it to a variety of locations. @@ -119,7 +119,7 @@ at build-time to construct library build specific registry key paths of the format: `\\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\OpenSSL--` -Where `` is the semantic major.minor.patch version of the library being +Where `` is the major.minor version of the library being built, and `` is the value specified by `-DOPENSSL_WINCTX`. This allows for multiple openssl builds to be created and installed on a single system, in which each library can use its own set of registry keys. @@ -127,9 +127,15 @@ which each library can use its own set of registry keys. Note the installer available at will set these keys when the installer is run. -If the registry keys above do not exist on a given system, or if the -`OSSL_WINCTX` variable is not defined at build time, OpenSSL makes no attempt to -load configuration, engines of modules from disk. +A summary table of behavior on Windows platforms + +|`OSSL_WINCTX`|Registry key|OpenSSL Behavior | +|-------------|------------|------------------------------------------| +|Defined | Defined |OpenSSL Reads Paths from Registry | +|Defined | Undefined |OpenSSL returns errors on module/conf load| +|Undefined | N/A |OpenSSL uses build time defaults | + + Special notes for Universal Windows Platform builds, aka `VC-*-UWP` ------------------------------------------------------------------- From 290452f2bd7ba220a4a38a68371bfcd39765b1e9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 11:51:51 -0400 Subject: [PATCH 110/138] Augment version.c to not display -w options on non-windows Don't need the -w option on non-windows builds Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- apps/version.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/version.c b/apps/version.c index bfcb1f15f97c6..4da8d2744717a 100644 --- a/apps/version.c +++ b/apps/version.c @@ -37,7 +37,9 @@ const OPTIONS version_options[] = { {"r", OPT_R, '-', "Show random seeding options"}, {"v", OPT_V, '-', "Show library version"}, {"c", OPT_C, '-', "Show CPU settings info"}, +#if defined(_WIN32) {"w", OPT_W, '-', "Show Windows install context"}, +#endif {NULL} }; @@ -45,7 +47,10 @@ int version_main(int argc, char **argv) { int ret = 1, dirty = 0, seed = 0; int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0; - int engdir = 0, moddir = 0, cpuinfo = 0, windows = 0; + int engdir = 0, moddir = 0, cpuinfo = 0; +#if defined(_WIN32) + int windows = 0; +#endif char *prog; OPTION_CHOICE o; const char *tmp; @@ -92,9 +97,11 @@ int version_main(int argc, char **argv) case OPT_C: dirty = cpuinfo = 1; break; - case OPT_W: - dirty = windows = 1; - break; +#if defined(_WIN32) + case OPT_W: + dirty = windows = 1; + break; +#endif case OPT_A: seed = options = cflags = version = date = platform = dir = engdir = moddir = cpuinfo @@ -142,8 +149,10 @@ int version_main(int argc, char **argv) } if (cpuinfo) printf("%s\n", OpenSSL_version(OPENSSL_CPU_INFO)); +#if defined(_WIN32) if (windows) printf("OSSL_WINCTX: %s\n", OpenSSL_version(OPENSSL_WINCTX)); +#endif ret = 0; end: return ret; From bf74cf35cf47bfa44a89a6f8c3e52a3ec76d828f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 26 Jun 2024 11:52:22 -0400 Subject: [PATCH 111/138] Fixes for defaults code Fix up some indenting, and ensure that the run_once routines don't get defined if OSSL_WINCTX isn't defined to avoid compiler errors Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- NOTES-WINDOWS.md | 4 +--- apps/version.c | 5 ++++- crypto/defaults.c | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/NOTES-WINDOWS.md b/NOTES-WINDOWS.md index f7984cda0c125..21c82e8a7659e 100644 --- a/NOTES-WINDOWS.md +++ b/NOTES-WINDOWS.md @@ -132,11 +132,9 @@ A summary table of behavior on Windows platforms |`OSSL_WINCTX`|Registry key|OpenSSL Behavior | |-------------|------------|------------------------------------------| |Defined | Defined |OpenSSL Reads Paths from Registry | -|Defined | Undefined |OpenSSL returns errors on module/conf load| +|Defined | Undefined |OpenSSL returns errors on module/conf load| |Undefined | N/A |OpenSSL uses build time defaults | - - Special notes for Universal Windows Platform builds, aka `VC-*-UWP` ------------------------------------------------------------------- diff --git a/apps/version.c b/apps/version.c index 4da8d2744717a..efd23a4064377 100644 --- a/apps/version.c +++ b/apps/version.c @@ -18,7 +18,10 @@ typedef enum OPTION_choice { OPT_COMMON, - OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, OPT_C, OPT_W + OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R, OPT_C +#if defined(_WIN32) + ,OPT_W +#endif } OPTION_CHOICE; const OPTIONS version_options[] = { diff --git a/crypto/defaults.c b/crypto/defaults.c index 2735efc63a94d..f9bd077686a8f 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -13,14 +13,14 @@ #include "internal/cryptlib.h" #include "internal/e_os.h" -#if defined(_WIN32) +#if defined(_WIN32) && defined(OSSL_WINCTX) # define TOSTR(x) #x # define MAKESTR(x) TOSTR(x) # define NOQUOTE(x) x -#if defined(OSSL_WINCTX) +# if defined(OSSL_WINCTX) # define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(OSSL_WINCTX) -#endif +# endif /** * @brief The directory where OpenSSL is installed. @@ -63,7 +63,7 @@ static char *modulesdirptr = NULL; static char *get_windows_regdirs(char *dst, LPCTSTR valuename) { char *retval = NULL; -#ifdef REGISTY_KEY +# ifdef REGISTRY_KEY DWORD keysize; DWORD ktype; HKEY hkey; @@ -104,7 +104,7 @@ static char *get_windows_regdirs(char *dst, LPCTSTR valuename) out: OPENSSL_free(tempstr); RegCloseKey(hkey); -#endif +# endif /* REGISTRY_KEY */ return retval; } @@ -135,7 +135,7 @@ DEFINE_RUN_ONCE_STATIC(do_defaults_setup) return 1; } -#endif +#endif /* defined(_WIN32) && defined(OSSL_WINCTX) */ /** * @brief Get the directory where OpenSSL is installed. From caaea8f343c63a828a5861650038b25de2d5983b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 27 Jun 2024 11:12:23 -0400 Subject: [PATCH 112/138] Update defaults to install keys against major.minor we want patch level updates to use the same keys, so only create the key against the major.minor version Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- crypto/defaults.c | 4 ++-- test/recipes/02-test_windows_registry.t | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crypto/defaults.c b/crypto/defaults.c index f9bd077686a8f..27c051508ed8a 100644 --- a/crypto/defaults.c +++ b/crypto/defaults.c @@ -19,7 +19,7 @@ # define MAKESTR(x) TOSTR(x) # define NOQUOTE(x) x # if defined(OSSL_WINCTX) -# define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## NOQUOTE(OPENSSL_VERSION_STR) ##"-"## MAKESTR(OSSL_WINCTX) +# define REGISTRY_KEY "SOFTWARE\\WOW6432Node\\OpenSSL" ##"-"## MAKESTR(OPENSSL_VERSION_MAJOR) ##"."## MAKESTR(OPENSSL_VERSION_MINOR) ##"-"## MAKESTR(OSSL_WINCTX) # endif /** @@ -28,7 +28,7 @@ static char openssldir[MAX_PATH + 1]; /** - * @brief The pointer to the opennsldir buffer + * @brief The pointer to the openssldir buffer */ static char *openssldirptr = NULL; diff --git a/test/recipes/02-test_windows_registry.t b/test/recipes/02-test_windows_registry.t index ceb6d99694592..3029b151e8645 100644 --- a/test/recipes/02-test_windows_registry.t +++ b/test/recipes/02-test_windows_registry.t @@ -27,7 +27,7 @@ $context =~ s/^.*: //; @tempout = run(app(["openssl", "version", "-v"]), capture => 1); my $version = "@tempout"; $version =~ s/^OpenSSL //; -$version =~ s/-.*\n//; +$version =~ s/(^[0-9]+\.[0-9]+)(.*$)/\1/; my $regkey = "HKLM\\SOFTWARE\\OpenSSL-".$version."-".$context; $regkey =~ s/\n//g; @@ -46,11 +46,11 @@ my @expectengdir = run(cmd(["reg.exe", "query", $regkey, "/reg:32", "/t", "REG_E my @expectmoddir = run(cmd(["reg.exe", "query", $regkey, "/reg:32", "/t", "REG_EXPAND_SZ", "/v", "MODULESDIR"]), capture => 1); -my @osslversion = run(app(["openssl", "version", "-d"]), capture => 1); +my @ossldir = run(app(["openssl", "version", "-d"]), capture => 1); -print "@osslversion"; +print "@ossldir"; $expect = "@expectossldir"; -$actual = "@osslversion"; +$actual = "@ossldir"; $expect =~ s/HKEY_LOCAL_MACHINE.*\n*//; $expect =~ s/\n//g; $expect =~ s/.*REG_EXPAND_SZ *//; From aa4fc5ea4a0da5f5f2c1fedf1f2727047d3a6eff Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 28 Jun 2024 07:28:36 -0400 Subject: [PATCH 113/138] Adjust ci to only use major.minor when setting reg keys Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 4 ++-- .github/workflows/windows_comp.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 7790145b8c9ef..110ac4bed9480 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -56,8 +56,8 @@ jobs: run: | apps/openssl.exe version -v apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/' + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index 2bf2332a239c5..fcdf7905a42ed 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -38,8 +38,8 @@ jobs: run: | apps/openssl.exe version -v apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/ + echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | From a8f99f98d601efdc212d958a79af78bbbb0f12e0 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 28 Jun 2024 13:28:55 -0400 Subject: [PATCH 114/138] Avoid chicken and egg problem with reg setting Because openssl with -DOSSL_WINCTX no longer falls back to build time defines, we have a chicken and egg problem. CI needs to query openssl for its version string so registry keys can be set properly, but openssl version refuses to run because no configuration file can be found So we work around it by, for the purposes of setting the registry keys, we set OPENSSL_CONF to a know config file, so that openssl version runs properly. Once the version is extracted, we can set the registry keys, and openssl will function properly without OPENSSL_CONF set Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 1 + .github/workflows/windows_comp.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 110ac4bed9480..a0cb656e36c3f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -54,6 +54,7 @@ jobs: - name: Gather openssl version info working-directory: _build run: | + $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v apps/openssl.exe version -v | awk '{print $2}' apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/' diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index fcdf7905a42ed..a65a6b5244d5f 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -36,9 +36,10 @@ jobs: - name: Gather openssl version info working-directory: _build run: | + $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/ + apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/' echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build From aa08335852a3714075c26690a6eeab456e813a54 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 28 Jun 2024 15:35:36 -0400 Subject: [PATCH 115/138] Fix sed/awk usage in windows ci jobs The addition of sed and awk, while available in the windows vm's for CI in powershell, don't behave as I would expect (though the same commands work with a local installation on windows using GnuWin32). In trying to figure out what was going on I found it was far more stable and predictable to use the powershell -split and -replace commands instead of sed and awk Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 6 +++--- .github/workflows/windows_comp.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a0cb656e36c3f..fc194ebcbbfec 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -56,9 +56,9 @@ jobs: run: | $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v - apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/' - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + apps/openssl.exe version -v | %{($_ -split '\s+')[1]} + apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} + echo "OSSL_VERSION=$(apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'})" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index a65a6b5244d5f..36f4caf084ad8 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -38,9 +38,9 @@ jobs: run: | $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v - apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/' - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/\([0-9]\+\.[0-9]\+\)\(\.[0-9]\+\)\(-*.*$\)/\1/')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + apps/openssl.exe version -v | %{($_ -split '\s+')[1]} + apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} + echo "OSSL_VERSION=$(apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'})" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | From 97bfbb98b0f9f2a381a47a01ae4e20f511adae05 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 1 Jul 2024 10:36:57 -0400 Subject: [PATCH 116/138] Allow openssl version to function in the absence of a config file the openssl application attempts to load a config file on startup always, calling x509_get_default_cert_area() to locate the file. On Windows builds with -DOSSL_WINCTX set, this fails if the corresponding registry keys are unset. allow openssl to continue to function properly for applets that don't actually require a configuration file. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/24450) --- .github/workflows/windows.yml | 1 - .github/workflows/windows_comp.yml | 1 - crypto/conf/conf_mod.c | 12 +++++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index fc194ebcbbfec..a65229fb01017 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -54,7 +54,6 @@ jobs: - name: Gather openssl version info working-directory: _build run: | - $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v apps/openssl.exe version -v | %{($_ -split '\s+')[1]} apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index 36f4caf084ad8..e7f8922ccfb13 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -36,7 +36,6 @@ jobs: - name: Gather openssl version info working-directory: _build run: | - $Env:OPENSSL_CONF="apps\openssl.cnf" apps/openssl.exe version -v apps/openssl.exe version -v | %{($_ -split '\s+')[1]} apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index 5e0681e6db315..9d49a5f69d109 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -692,8 +692,18 @@ char *CONF_get1_default_config_file(void) return OPENSSL_strdup(file); t = X509_get_default_cert_area(); + /* + * On windows systems with -DOSSL_WINCTX set, if the needed registry + * keys are not yet set, openssl applets will return, due to an inability + * to locate various directories, like the default cert area. In that + * event, clone an empty string here, so that commands like openssl version + * continue to operate properly without needing to set OPENSSL_CONF. + * Applets like cms will fail gracefully later when they try to parse an + * empty config file + */ if (t == NULL) - return NULL; + return OPENSSL_strdup(""); + #ifndef OPENSSL_SYS_VMS sep = "/"; #endif From d8def79838cd0d5e7c21d217aa26edb5229f0ab4 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 2 Jul 2024 14:27:42 -0400 Subject: [PATCH 117/138] read lock store on ossl_method_store_do_all Theres a data race between ossl_method_store_insert and ossl_method_store_do_all, as the latter doesn't take the property lock before iterating. However, we can't lock in do_all, as the call stack in several cases later attempts to take the write lock. The choices to fix it are I think: 1) add an argument to indicate to ossl_method_store_do_all weather to take the read or write lock when doing iterations, and add an is_locked api to the ossl_property_[read|write] lock family so that subsequent callers can determine if they need to take a lock or not 2) Clone the algs sparse array in ossl_method_store_do_all and use the clone to iterate with no lock held, ensuring that updates to the parent copy of the sparse array are left untoucheTheres a data race between ossl_method_store_insert and ossl_method_store_do_all, as the latter doesn't take the property lock before iterating. I think method (2), while being a bit more expensive, is probably the far less invasive way to go here Fixes #24672 Reviewed-by: Paul Dale Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24782) --- crypto/property/property.c | 50 ++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/crypto/property/property.c b/crypto/property/property.c index c551c825b19b3..8f31e5da9bef7 100644 --- a/crypto/property/property.c +++ b/crypto/property/property.c @@ -96,6 +96,8 @@ typedef struct { DEFINE_SPARSE_ARRAY_OF(ALGORITHM); +DEFINE_STACK_OF(ALGORITHM) + typedef struct ossl_global_properties_st { OSSL_PROPERTY_LIST *list; #ifndef FIPS_MODULE @@ -461,33 +463,45 @@ static void alg_do_one(ALGORITHM *alg, IMPLEMENTATION *impl, fn(alg->nid, impl->method.method, fnarg); } -struct alg_do_each_data_st { - void (*fn)(int id, void *method, void *fnarg); - void *fnarg; -}; - -static void alg_do_each(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) +static void alg_copy(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) { - struct alg_do_each_data_st *data = arg; - int i, end = sk_IMPLEMENTATION_num(alg->impls); - - for (i = 0; i < end; i++) { - IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i); + STACK_OF(ALGORITHM) *newalg = arg; - alg_do_one(alg, impl, data->fn, data->fnarg); - } + (void)sk_ALGORITHM_push(newalg, alg); } void ossl_method_store_do_all(OSSL_METHOD_STORE *store, void (*fn)(int id, void *method, void *fnarg), void *fnarg) { - struct alg_do_each_data_st data; + int i, j; + int numalgs, numimps; + STACK_OF(ALGORITHM) *tmpalgs; + ALGORITHM *alg; - data.fn = fn; - data.fnarg = fnarg; - if (store != NULL) - ossl_sa_ALGORITHM_doall_arg(store->algs, alg_do_each, &data); + if (store != NULL) { + + if (!ossl_property_read_lock(store)) + return; + + tmpalgs = sk_ALGORITHM_new_reserve(NULL, + ossl_sa_ALGORITHM_num(store->algs)); + if (tmpalgs == NULL) { + ossl_property_unlock(store); + return; + } + + ossl_sa_ALGORITHM_doall_arg(store->algs, alg_copy, tmpalgs); + ossl_property_unlock(store); + numalgs = sk_ALGORITHM_num(tmpalgs); + for (i = 0; i < numalgs; i++) { + alg = sk_ALGORITHM_value(tmpalgs, i); + numimps = sk_IMPLEMENTATION_num(alg->impls); + for (j = 0; j < numimps; j++) + alg_do_one(alg, sk_IMPLEMENTATION_value(alg->impls, j), fn, fnarg); + } + sk_ALGORITHM_free(tmpalgs); + } } int ossl_method_store_fetch(OSSL_METHOD_STORE *store, From 7b1e008d383a7860490b110ee46609e65bf8a9b4 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 3 Jul 2024 11:33:34 +0200 Subject: [PATCH 118/138] os-zoo.yml: Cleanup unnecessary -Wno-switch-default Reviewed-by: Neil Horman Reviewed-by: Tom Cosgrove Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24787) --- .github/workflows/os-zoo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-zoo.yml b/.github/workflows/os-zoo.yml index 9dfc2faac80de..884c08599dfaa 100644 --- a/.github/workflows/os-zoo.yml +++ b/.github/workflows/os-zoo.yml @@ -27,7 +27,7 @@ jobs: image: docker.io/library/alpine:${{ matrix.tag }} env: # https://www.openwall.com/lists/musl/2022/02/16/14 - EXTRA_CFLAGS: ${{ matrix.cc == 'clang' && '-Wno-sign-compare -Wno-switch-default' || '' }} + EXTRA_CFLAGS: ${{ matrix.cc == 'clang' && '-Wno-sign-compare' || '' }} CC: ${{ matrix.cc }} steps: - name: install packages From 775188702574dcd6cc53b7a9d3501a639c146121 Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 8 Jul 2024 11:50:35 +0200 Subject: [PATCH 119/138] Clarify supported curves in the s_client/s_server documentation Mention that supported curves (aka groups) include named EC parameters as well as X25519 and X448 or FFDHE groups. Reviewed-by: Neil Horman Reviewed-by: Dmitry Belyavskiy Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24774) --- doc/man1/openssl-s_client.pod.in | 6 +++++- doc/man1/openssl-s_server.pod.in | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/man1/openssl-s_client.pod.in b/doc/man1/openssl-s_client.pod.in index 51473a65c29cd..2aa8c8d134e81 100644 --- a/doc/man1/openssl-s_client.pod.in +++ b/doc/man1/openssl-s_client.pod.in @@ -656,7 +656,11 @@ For example strings, see L =item B<-curves> I Specifies the list of supported curves to be sent by the client. The curve is -ultimately selected by the server. For a list of all curves, use: +ultimately selected by the server. + +The list of all supported groups includes named EC parameters as well as X25519 +and X448 or FFDHE groups, and may also include groups implemented in 3rd-party +providers. For a list of named EC parameters, use: $ openssl ecparam -list_curves diff --git a/doc/man1/openssl-s_server.pod.in b/doc/man1/openssl-s_server.pod.in index 3049426f829fb..80f8c329929b3 100644 --- a/doc/man1/openssl-s_server.pod.in +++ b/doc/man1/openssl-s_server.pod.in @@ -671,7 +671,10 @@ Signature algorithms to support for client certificate authentication =item B<-named_curve> I Specifies the elliptic curve to use. NOTE: this is single curve, not a list. -For a list of all possible curves, use: + +The list of all supported groups includes named EC parameters as well as X25519 +and X448 or FFDHE groups, and may also include groups implemented in 3rd-party +providers. For a list of named EC parameters, use: $ openssl ecparam -list_curves From 6f811d839fd637fa5dea0ee4286722847ab74b98 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Fri, 21 Jun 2024 15:16:10 +0200 Subject: [PATCH 120/138] Replace and Deprecate TS_VERIFY_CTX Functions Fixes #18854 Replace and deprecate the functions `TS_VERIFY_CTX_set_data`, `TS_VERIFY_CTX_set_store`, `TS_VERIFY_CTX_set_certs`, `TS_VERIFY_CTX_set_imprint` with new versions: `TS_VERIFY_CTX_set0_data`, `TS_VERIFY_CTX_set0_store`, `TS_VERIFY_CTX_set0_certs` and `TS_VERIFY_CTX_set0_imprint`. The previous functions had poorly documented memory handling, potentially leading to memory leaks. The new functions improve memory management and provide clearer usage. Also, update existing code to use the new function calls instead of the deprecated ones. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24701) --- apps/ts.c | 11 +++++------ crypto/ts/ts_verify_ctx.c | 40 ++++++++++++++++++++++++++++++++++++++- include/openssl/ts.h | 17 +++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/apps/ts.c b/apps/ts.c index 18df7d5ace3fb..71b8df1997917 100644 --- a/apps/ts.c +++ b/apps/ts.c @@ -920,7 +920,7 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, f |= TS_VFY_DATA; if ((out = BIO_new_file(data, "rb")) == NULL) goto err; - if (TS_VERIFY_CTX_set_data(ctx, out) == NULL) { + if (!TS_VERIFY_CTX_set0_data(ctx, out)) { BIO_free_all(out); goto err; } @@ -928,7 +928,7 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, long imprint_len; unsigned char *hexstr = OPENSSL_hexstr2buf(digest, &imprint_len); f |= TS_VFY_IMPRINT; - if (TS_VERIFY_CTX_set_imprint(ctx, hexstr, imprint_len) == NULL) { + if (!TS_VERIFY_CTX_set0_imprint(ctx, hexstr, imprint_len)) { BIO_printf(bio_err, "invalid digest string\n"); goto err; } @@ -949,16 +949,15 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, TS_VERIFY_CTX_add_flags(ctx, f | TS_VFY_SIGNATURE); /* Initialising the X509_STORE object. */ - if (TS_VERIFY_CTX_set_store(ctx, - create_cert_store(CApath, CAfile, CAstore, vpm)) - == NULL) + if (!TS_VERIFY_CTX_set0_store(ctx, create_cert_store(CApath, CAfile, + CAstore, vpm))) goto err; /* Loading any extra untrusted certificates. */ if (untrusted != NULL) { certs = load_certs_multifile(untrusted, NULL, "extra untrusted certs", vpm); - if (certs == NULL || TS_VERIFY_CTX_set_certs(ctx, certs) == NULL) + if (certs == NULL || !TS_VERIFY_CTX_set0_certs(ctx, certs)) goto err; } ret = 1; diff --git a/crypto/ts/ts_verify_ctx.c b/crypto/ts/ts_verify_ctx.c index 6dbba3df506ce..4b6a3ada9b2b1 100644 --- a/crypto/ts/ts_verify_ctx.c +++ b/crypto/ts/ts_verify_ctx.c @@ -1,5 +1,5 @@ /* - * Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -46,25 +46,53 @@ int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f) return ctx->flags; } +#ifndef OPENSSL_NO_DEPRECATED_3_4 BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b) { ctx->data = b; return ctx->data; } +#endif +int TS_VERIFY_CTX_set0_data(TS_VERIFY_CTX *ctx, BIO *b) +{ + BIO_free_all(ctx->data); + ctx->data = b; + return 1; +} + +#ifndef OPENSSL_NO_DEPRECATED_3_4 X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s) { ctx->store = s; return ctx->store; } +#endif +int TS_VERIFY_CTX_set0_store(TS_VERIFY_CTX *ctx, X509_STORE *s) +{ + X509_STORE_free(ctx->store); + ctx->store = s; + return 1; +} + +#ifndef OPENSSL_NO_DEPRECATED_3_4 STACK_OF(X509) *TS_VERIFY_CTX_set_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs) { ctx->certs = certs; return ctx->certs; } +#endif +int TS_VERIFY_CTX_set0_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs) +{ + OSSL_STACK_OF_X509_free(ctx->certs); + ctx->certs = certs; + return 1; +} + +#ifndef OPENSSL_NO_DEPRECATED_3_4 unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx, unsigned char *hexstr, long len) { @@ -73,6 +101,16 @@ unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx, ctx->imprint_len = len; return ctx->imprint; } +#endif + +int TS_VERIFY_CTX_set0_imprint(TS_VERIFY_CTX *ctx, + unsigned char *hexstr, long len) +{ + OPENSSL_free(ctx->imprint); + ctx->imprint = hexstr; + ctx->imprint_len = len; + return 1; +} void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx) { diff --git a/include/openssl/ts.h b/include/openssl/ts.h index b09b646dffe1f..7feb45fd4badb 100644 --- a/include/openssl/ts.h +++ b/include/openssl/ts.h @@ -418,14 +418,31 @@ void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx); void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx); int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f); int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f); +# ifndef OPENSSL_NO_DEPRECATED_3_4 +OSSL_DEPRECATEDIN_3_4_FOR("Unclear semantics, replace with TS_VERIFY_CTX_set0_data().") BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b); +# endif +int TS_VERIFY_CTX_set0_data(TS_VERIFY_CTX *ctx, BIO *b); +# ifndef OPENSSL_NO_DEPRECATED_3_4 +OSSL_DEPRECATEDIN_3_4_FOR("Unclear semantics, replace with TS_VERIFY_CTX_set0_imprint().") unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx, unsigned char *hexstr, long len); +# endif +int TS_VERIFY_CTX_set0_imprint(TS_VERIFY_CTX *ctx, + unsigned char *hexstr, long len); +# ifndef OPENSSL_NO_DEPRECATED_3_4 +OSSL_DEPRECATEDIN_3_4_FOR("Unclear semantics, replace with TS_VERIFY_CTX_set0_store().") X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s); +# endif +int TS_VERIFY_CTX_set0_store(TS_VERIFY_CTX *ctx, X509_STORE *s); # ifndef OPENSSL_NO_DEPRECATED_3_0 # define TS_VERIFY_CTS_set_certs(ctx, cert) TS_VERIFY_CTX_set_certs(ctx,cert) # endif +# ifndef OPENSSL_NO_DEPRECATED_3_4 +OSSL_DEPRECATEDIN_3_4_FOR("Unclear semantics, replace with TS_VERIFY_CTX_set0_certs().") STACK_OF(X509) *TS_VERIFY_CTX_set_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs); +# endif +int TS_VERIFY_CTX_set0_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs); /*- * If ctx is NULL, it allocates and returns a new object, otherwise From 2c1ef172f83d78490be553982a5f08503d4b4590 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Fri, 21 Jun 2024 15:21:04 +0200 Subject: [PATCH 121/138] Add and Update Documentation for TS_VERIFY_CTX Functions Mark the existing `TS_VERIFY_CTX_set_certs` function as deprecated in the documentation. Add missing documentation for the deprecated functions `TS_VERIFY_CTX_set_data`, `TS_VERIFY_CTX_set_imprint`, and `TS_VERIFY_CTX_set_store`. Write missing documentation for the following functions: - `TS_VERIFY_CTX_new` - `TS_VERIFY_CTX_init` - `TS_VERIFY_CTX_free` - `TS_VERIFY_CTX_cleanup` - `TS_VERIFY_CTX_set_flags` - `TS_VERIFY_CTX_add_flags` - `TS_VERIFY_CTX_set0_data` - `TS_VERIFY_CTX_set0_imprint` - `TS_VERIFY_CTX_set0_store` - `TS_VERIFY_CTX_set0_certs` Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24701) --- doc/build.info | 12 +-- doc/man3/TS_VERIFY_CTX.pod | 154 +++++++++++++++++++++++++++ doc/man3/TS_VERIFY_CTX_set_certs.pod | 61 ----------- util/libcrypto.num | 12 ++- util/other.syms | 1 + 5 files changed, 169 insertions(+), 71 deletions(-) create mode 100644 doc/man3/TS_VERIFY_CTX.pod delete mode 100644 doc/man3/TS_VERIFY_CTX_set_certs.pod diff --git a/doc/build.info b/doc/build.info index 3a8adb1c66e3e..5227a10c1ad10 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2803,10 +2803,10 @@ DEPEND[html/man3/TS_RESP_CTX_new.html]=man3/TS_RESP_CTX_new.pod GENERATE[html/man3/TS_RESP_CTX_new.html]=man3/TS_RESP_CTX_new.pod DEPEND[man/man3/TS_RESP_CTX_new.3]=man3/TS_RESP_CTX_new.pod GENERATE[man/man3/TS_RESP_CTX_new.3]=man3/TS_RESP_CTX_new.pod -DEPEND[html/man3/TS_VERIFY_CTX_set_certs.html]=man3/TS_VERIFY_CTX_set_certs.pod -GENERATE[html/man3/TS_VERIFY_CTX_set_certs.html]=man3/TS_VERIFY_CTX_set_certs.pod -DEPEND[man/man3/TS_VERIFY_CTX_set_certs.3]=man3/TS_VERIFY_CTX_set_certs.pod -GENERATE[man/man3/TS_VERIFY_CTX_set_certs.3]=man3/TS_VERIFY_CTX_set_certs.pod +DEPEND[html/man3/TS_VERIFY_CTX.html]=man3/TS_VERIFY_CTX.pod +GENERATE[html/man3/TS_VERIFY_CTX.html]=man3/TS_VERIFY_CTX.pod +DEPEND[man/man3/TS_VERIFY_CTX.3]=man3/TS_VERIFY_CTX.pod +GENERATE[man/man3/TS_VERIFY_CTX.3]=man3/TS_VERIFY_CTX.pod DEPEND[html/man3/UI_STRING.html]=man3/UI_STRING.pod GENERATE[html/man3/UI_STRING.html]=man3/UI_STRING.pod DEPEND[man/man3/UI_STRING.3]=man3/UI_STRING.pod @@ -3684,7 +3684,7 @@ html/man3/SSL_stream_reset.html \ html/man3/SSL_want.html \ html/man3/SSL_write.html \ html/man3/TS_RESP_CTX_new.html \ -html/man3/TS_VERIFY_CTX_set_certs.html \ +html/man3/TS_VERIFY_CTX.html \ html/man3/UI_STRING.html \ html/man3/UI_UTIL_read_pw.html \ html/man3/UI_create_method.html \ @@ -4342,7 +4342,7 @@ man/man3/SSL_stream_reset.3 \ man/man3/SSL_want.3 \ man/man3/SSL_write.3 \ man/man3/TS_RESP_CTX_new.3 \ -man/man3/TS_VERIFY_CTX_set_certs.3 \ +man/man3/TS_VERIFY_CTX.3 \ man/man3/UI_STRING.3 \ man/man3/UI_UTIL_read_pw.3 \ man/man3/UI_create_method.3 \ diff --git a/doc/man3/TS_VERIFY_CTX.pod b/doc/man3/TS_VERIFY_CTX.pod new file mode 100644 index 0000000000000..e237bf80fbfbd --- /dev/null +++ b/doc/man3/TS_VERIFY_CTX.pod @@ -0,0 +1,154 @@ +=pod + +=head1 NAME + +TS_VERIFY_CTX, TS_VERIFY_CTX_new, TS_VERIFY_CTX_init, TS_VERIFY_CTX_free, +TS_VERIFY_CTX_cleanup, TS_VERIFY_CTX_set_flags, TS_VERIFY_CTX_add_flags, +TS_VERIFY_CTX_set0_data, TS_VERIFY_CTX_set0_imprint, TS_VERIFY_CTX_set0_store, +TS_VERIFY_CTX_set0_certs, TS_VERIFY_CTX_set_certs, TS_VERIFY_CTS_set_certs, +TS_VERIFY_CTX_set_data, TS_VERIFY_CTX_set_imprint, TS_VERIFY_CTX_set_store +- manage the TS response verification context + +=head1 SYNOPSIS + + #include + + typedef struct TS_verify_ctx TS_VERIFY_CTX; + + TS_VERIFY_CTX *TS_VERIFY_CTX_new(void); + void TS_VERIFY_CTX_init(TS_VERIFY_CTX *ctx); + void TS_VERIFY_CTX_free(TS_VERIFY_CTX *ctx); + void TS_VERIFY_CTX_cleanup(TS_VERIFY_CTX *ctx); + int TS_VERIFY_CTX_set_flags(TS_VERIFY_CTX *ctx, int f); + int TS_VERIFY_CTX_add_flags(TS_VERIFY_CTX *ctx, int f); + int TS_VERIFY_CTX_set0_data(TS_VERIFY_CTX *ctx, BIO *b); + int TS_VERIFY_CTX_set0_imprint(TS_VERIFY_CTX *ctx, + unsigned char *hexstr, long len); + int TS_VERIFY_CTX_set0_store(TS_VERIFY_CTX *ctx, X509_STORE *s); + int TS_VERIFY_CTX_set0_certs(TS_VERIFY_CTX *ctx, STACK_OF(X509) *certs); + +The following functions have been deprecated since OpenSSL 3.4: + + BIO *TS_VERIFY_CTX_set_data(TS_VERIFY_CTX *ctx, BIO *b); + unsigned char *TS_VERIFY_CTX_set_imprint(TS_VERIFY_CTX *ctx, + unsigned char *hexstr, long len); + X509_STORE *TS_VERIFY_CTX_set_store(TS_VERIFY_CTX *ctx, X509_STORE *s); + STACK_OF(X509) *TS_VERIFY_CTX_set_certs(TS_VERIFY_CTX *ctx, + STACK_OF(X509) *certs); + +The following function has been deprecated since OpenSSL 3.0: + + STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx, + STACK_OF(X509) *certs); + +=head1 DESCRIPTION + +The Time-Stamp Protocol (TSP) is defined by RFC 3161. TSP is a protocol used to +provide long-term proof of the existence of certain data before a particular +time. TSP defines a Time Stamping Authority (TSA) and an entity that makes +requests to the TSA. Usually, the TSA is referred to as the server side, and the +requesting entity is referred to as the client. + +In TSP, when a server sends a response to a client, the server normally +needs to sign the response data - the TimeStampToken (TST) - with its private +key. Then the client verifies the received TST using the server's certificate +chain. + +For all the following methods, unless noted otherwise, I is the +verification context created in advance. + +TS_VERIFY_CTX_new() returns an allocated B structure. + +TS_VERIFY_CTX_init() initializes a verification context. + +TS_VERIFY_CTX_free() frees up a B object. I is the +verification context to be freed. If I is NULL, the call is ignored. + +TS_VERIFY_CTX_set_flags() sets the flags in the verification context. I are +the flags to be set. + +TS_VERIFY_CTX_add_flags() adds flags to the verification context. I are the +flags to be added (OR'd). + +TS_VERIFY_CTX_set0_data() sets the data to be verified. I is the B with +the data. A previously assigned B is freed. + +TS_VERIFY_CTX_set0_imprint() sets the message imprint. I is the +message imprint to be assigned. A previously assigned imprint is freed. + +TS_VERIFY_CTX_set0_store() sets the store for the verification context. I is +the store to be assigned. A previously assigned store is freed. + +TS_VERIFY_CTX_set0_certs() is used to set the server's certificate chain when +verifying a TST. I is a stack of B certificates. + +TS_VERIFY_CTX_cleanup() frees all data associated with the given +B object and initializes it. I is the verification context +created in advance. If I is NULL, the call is ignored. + +All of the following functions described are deprecated. Applications should +instead use the functions L, +L, L, +L. + +TS_VERIFY_CTX_set_data() is used to set the BIO with the data to be verified. +A previously assigned BIO is B by this call. I is the B +with the data to assign. + +TS_VERIFY_CTX_set_imprint() is used to set the message imprint. A previously +assigned imprint B by this call. I is the string with the +message imprint to assign. + +TS_VERIFY_CTX_set_store() is used to set the certificate store. A previously +assigned store is B by this call. I is the store to assign. + +TS_VERIFY_CTX_set_certs() is used to set the server's certificate chain. +A previously assigned stack is B by this call. I is a stack +of B certificates. + +TS_VERIFY_CTS_set_certs() is a misspelled version of TS_VERIFY_CTX_set_certs() +which takes the same parameters and returns the same result. + +=head1 RETURN VALUES + +TS_VERIFY_CTX_new() returns an allocated B structure. + +TS_VERIFY_CTX_set_flags() returns the flags passed via parameter I. + +TS_VERIFY_CTX_add_flags() returns the flags of the context after the ones +passed via parameter I are added to it. + +TS_VERIFY_CTX_set0_data(), TS_VERIFY_CTX_set0_imprint(), +TS_VERIFY_CTX_set0_store(), and TS_VERIFY_CTX_set0_certs() return 1 if the +value could be successfully set and 0 in case of any error. + +The deprecated functions TS_VERIFY_CTX_set_data(), TS_VERIFY_CTX_set_imprint(), +TS_VERIFY_CTX_set_store(), TS_VERIFY_CTX_set_certs() return the parameter +the user passes via parameter I, I, I or I. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +TS_VERIFY_CTX_set0_data(), TS_VERIFY_CTX_set0_imprint(), +TS_VERIFY_CTX_set0_store(), TS_VERIFY_CTX_set0_certs() replace the functions +TS_VERIFY_CTX_set_data(), TS_VERIFY_CTX_set_imprint(), +TS_VERIFY_CTX_set_store(), TS_VERIFY_CTX_set_certs() that were deprecated +in OpenSSL 3.4.0. + +The spelling of TS_VERIFY_CTX_set_certs() was corrected in OpenSSL 3.0.0. +The misspelled version TS_VERIFY_CTS_set_certs() has been retained for +compatibility reasons, but it is deprecated in OpenSSL 3.0.0. + +=head1 COPYRIGHT + +Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/TS_VERIFY_CTX_set_certs.pod b/doc/man3/TS_VERIFY_CTX_set_certs.pod deleted file mode 100644 index 5a35302c41006..0000000000000 --- a/doc/man3/TS_VERIFY_CTX_set_certs.pod +++ /dev/null @@ -1,61 +0,0 @@ -=pod - -=head1 NAME - -TS_VERIFY_CTX_set_certs, TS_VERIFY_CTS_set_certs -- set certificates for TS response verification - -=head1 SYNOPSIS - - #include - - STACK_OF(X509) *TS_VERIFY_CTX_set_certs(TS_VERIFY_CTX *ctx, - STACK_OF(X509) *certs); - STACK_OF(X509) *TS_VERIFY_CTS_set_certs(TS_VERIFY_CTX *ctx, - STACK_OF(X509) *certs); - -=head1 DESCRIPTION - -The Time-Stamp Protocol (TSP) is defined by RFC 3161. TSP is a protocol used to -provide long term proof of the existence of a certain datum before a particular -time. TSP defines a Time Stamping Authority (TSA) and an entity who shall make -requests to the TSA. Usually the TSA is denoted as the server side and the -requesting entity is denoted as the client. - -In TSP, when a server is sending a response to a client, the server normally -needs to sign the response data - the TimeStampToken (TST) - with its private -key. Then the client shall verify the received TST by the server's certificate -chain. - -TS_VERIFY_CTX_set_certs() is used to set the server's certificate chain when -verifying a TST. B is the verification context created in advance and -B is a stack of B certificates. - -TS_VERIFY_CTS_set_certs() is a misspelled version of TS_VERIFY_CTX_set_certs() -which takes the same parameters and returns the same result. - -=head1 RETURN VALUES - -TS_VERIFY_CTX_set_certs() returns the stack of B certificates the user -passes in via parameter B. - -=head1 SEE ALSO - -L - -=head1 HISTORY - -The spelling of TS_VERIFY_CTX_set_certs() was corrected in OpenSSL 3.0.0. -The misspelled version TS_VERIFY_CTS_set_certs() has been retained for -compatibility reasons, but it is deprecated in OpenSSL 3.0.0. - -=head1 COPYRIGHT - -Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. - -Licensed under the Apache License 2.0 (the "License"). You may not use -this file except in compliance with the License. You can obtain a copy -in the file LICENSE in the source distribution or at -L. - -=cut diff --git a/util/libcrypto.num b/util/libcrypto.num index 9e73024f3aa51..cbe61d1a99526 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -153,7 +153,7 @@ BN_is_prime_fasttest_ex 155 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3 ERR_load_PKCS12_strings 156 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0 EVP_sha384 157 3_0_0 EXIST::FUNCTION: i2d_DHparams 158 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0,DH -TS_VERIFY_CTX_set_store 159 3_0_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set_store 159 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_4,TS PKCS12_verify_mac 160 3_0_0 EXIST::FUNCTION: X509v3_addr_canonize 161 3_0_0 EXIST::FUNCTION:RFC3779 ASN1_item_ex_i2d 162 3_0_0 EXIST::FUNCTION: @@ -915,7 +915,7 @@ TS_TST_INFO_ext_free 938 3_0_0 EXIST::FUNCTION:TS i2d_X509_CRL_fp 939 3_0_0 EXIST::FUNCTION:STDIO PKCS7_get0_signers 940 3_0_0 EXIST::FUNCTION: X509_STORE_CTX_set_ex_data 941 3_0_0 EXIST::FUNCTION: -TS_VERIFY_CTX_set_certs 942 3_0_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set_certs 942 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_4,TS BN_MONT_CTX_copy 943 3_0_0 EXIST::FUNCTION: OPENSSL_INIT_new 945 3_0_0 EXIST::FUNCTION: TS_ACCURACY_dup 946 3_0_0 EXIST::FUNCTION:TS @@ -2421,7 +2421,7 @@ ASIdOrRange_free 2472 3_0_0 EXIST::FUNCTION:RFC3779 EC_POINT_get_Jprojective_coordinates_GFp 2473 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0,EC EVP_aes_128_cbc_hmac_sha256 2474 3_0_0 EXIST::FUNCTION: i2d_PKCS7_SIGNED 2475 3_0_0 EXIST::FUNCTION: -TS_VERIFY_CTX_set_data 2476 3_0_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set_data 2476 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_4,TS BN_pseudo_rand_range 2477 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0 X509V3_EXT_add_nconf 2478 3_0_0 EXIST::FUNCTION: EVP_CIPHER_CTX_ctrl 2479 3_0_0 EXIST::FUNCTION: @@ -2612,7 +2612,7 @@ RSA_public_encrypt 2670 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_ X509_CRL_get0_extensions 2671 3_0_0 EXIST::FUNCTION: CMS_digest_verify 2672 3_0_0 EXIST::FUNCTION:CMS ASN1_GENERALIZEDTIME_set 2673 3_0_0 EXIST::FUNCTION: -TS_VERIFY_CTX_set_imprint 2674 3_0_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set_imprint 2674 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_4,TS BN_RECP_CTX_set 2675 3_0_0 EXIST::FUNCTION: CRYPTO_secure_zalloc 2676 3_0_0 EXIST::FUNCTION: i2d_EXTENDED_KEY_USAGE 2677 3_0_0 EXIST::FUNCTION: @@ -5683,6 +5683,10 @@ OSSL_TARGETING_INFORMATION_free ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_new ? 3_4_0 EXIST::FUNCTION: OSSL_TARGETING_INFORMATION_it ? 3_4_0 EXIST::FUNCTION: OSSL_GENERAL_NAMES_print ? 3_4_0 EXIST::FUNCTION: +TS_VERIFY_CTX_set0_data ? 3_4_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set0_imprint ? 3_4_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set0_store ? 3_4_0 EXIST::FUNCTION:TS +TS_VERIFY_CTX_set0_certs ? 3_4_0 EXIST::FUNCTION:TS CRYPTO_atomic_add64 ? 3_4_0 EXIST::FUNCTION: CRYPTO_atomic_and ? 3_4_0 EXIST::FUNCTION: d2i_OSSL_ATTRIBUTES_SYNTAX ? 3_4_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index 143b3a33d1a38..3902945ac1ab1 100644 --- a/util/other.syms +++ b/util/other.syms @@ -832,3 +832,4 @@ EVP_PKEY_size define EVP_PKEY_id define EVP_PKEY_base_id define SSL_set_retry_verify define +TS_VERIFY_CTX define From b544047c99c4a7413f793afe82ab1c165f85b5b6 Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Mon, 8 Jul 2024 15:02:59 +0200 Subject: [PATCH 122/138] Add documentation for deprecated CMAC_CTX functions Fixes #5539: Create a new manual page `CMAC_CTX.pod` documenting the deprecated `CMAC_CTX` functions and add the necessary build dependencies. This page includes function descriptions, usage details, and replacement suggestions with the `EVP_MAC` interface. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24814) --- doc/build.info | 6 +++ doc/man3/CMAC_CTX.pod | 114 +++++++++++++++++++++++++++++++++++++++++ util/missingcrypto.txt | 9 ---- util/other.syms | 1 + 4 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 doc/man3/CMAC_CTX.pod diff --git a/doc/build.info b/doc/build.info index 5227a10c1ad10..b2689b7acebf1 100644 --- a/doc/build.info +++ b/doc/build.info @@ -783,6 +783,10 @@ DEPEND[html/man3/BUF_MEM_new.html]=man3/BUF_MEM_new.pod GENERATE[html/man3/BUF_MEM_new.html]=man3/BUF_MEM_new.pod DEPEND[man/man3/BUF_MEM_new.3]=man3/BUF_MEM_new.pod GENERATE[man/man3/BUF_MEM_new.3]=man3/BUF_MEM_new.pod +DEPEND[html/man3/CMAC_CTX.html]=man3/CMAC_CTX.pod +GENERATE[html/man3/CMAC_CTX.html]=man3/CMAC_CTX.pod +DEPEND[man/man3/CMAC_CTX.3]=man3/CMAC_CTX.pod +GENERATE[man/man3/CMAC_CTX.3]=man3/CMAC_CTX.pod DEPEND[html/man3/CMS_EncryptedData_decrypt.html]=man3/CMS_EncryptedData_decrypt.pod GENERATE[html/man3/CMS_EncryptedData_decrypt.html]=man3/CMS_EncryptedData_decrypt.pod DEPEND[man/man3/CMS_EncryptedData_decrypt.3]=man3/CMS_EncryptedData_decrypt.pod @@ -3179,6 +3183,7 @@ html/man3/BN_set_bit.html \ html/man3/BN_swap.html \ html/man3/BN_zero.html \ html/man3/BUF_MEM_new.html \ +html/man3/CMAC_CTX.html \ html/man3/CMS_EncryptedData_decrypt.html \ html/man3/CMS_EncryptedData_encrypt.html \ html/man3/CMS_EnvelopedData_create.html \ @@ -3837,6 +3842,7 @@ man/man3/BN_set_bit.3 \ man/man3/BN_swap.3 \ man/man3/BN_zero.3 \ man/man3/BUF_MEM_new.3 \ +man/man3/CMAC_CTX.3 \ man/man3/CMS_EncryptedData_decrypt.3 \ man/man3/CMS_EncryptedData_encrypt.3 \ man/man3/CMS_EnvelopedData_create.3 \ diff --git a/doc/man3/CMAC_CTX.pod b/doc/man3/CMAC_CTX.pod new file mode 100644 index 0000000000000..fae4fd1516e17 --- /dev/null +++ b/doc/man3/CMAC_CTX.pod @@ -0,0 +1,114 @@ +=pod + +=head1 NAME + +CMAC_CTX, CMAC_CTX_new, CMAC_CTX_cleanup, CMAC_CTX_free, +CMAC_CTX_get0_cipher_ctx, CMAC_CTX_copy, CMAC_Init, CMAC_Update, CMAC_Final, +CMAC_resume +- create cipher-based message authentication codes + +=head1 SYNOPSIS + + #include + +The following functions have been deprecated since OpenSSL 3.0, and can be +disabled entirely by defining B with a suitable version +value, see L. + + typedef struct CMAC_CTX_st CMAC_CTX; + + CMAC_CTX *CMAC_CTX_new(void); + void CMAC_CTX_cleanup(CMAC_CTX *ctx); + void CMAC_CTX_free(CMAC_CTX *ctx); + EVP_CIPHER_CTX *CMAC_CTX_get0_cipher_ctx(CMAC_CTX *ctx); + int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in); + int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, + const EVP_CIPHER *cipher, ENGINE *impl); + int CMAC_Update(CMAC_CTX *ctx, const void *data, size_t dlen); + int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen); + int CMAC_resume(CMAC_CTX *ctx); + +=head1 DESCRIPTION + +The low-level MAC functions documented on this page are deprecated. +Applications should use the new L interface. +Specifically, utilize the following functions for MAC operations: + +=over 4 + +=item L to create a new MAC context. + +=item L to free the MAC context. + +=item L to initialize the MAC context. + +=item L to update the MAC with data. + +=item L to finalize the MAC and retrieve the output. + +=back + +Alternatively, for a single-step MAC computation, use the L +function. + +The B type is a structure used for the provision of CMAC +(Cipher-based Message Authentication Code) operations. + +CMAC_CTX_new() creates a new B structure and returns a pointer to it. + +CMAC_CTX_cleanup() resets the B structure, clearing any internal data +but not freeing the structure itself. + +CMAC_CTX_free() frees the B structure and any associated resources. +If the argument is NULL, no action is taken. + +CMAC_CTX_get0_cipher_ctx() returns a pointer to the internal B +structure within the B. + +CMAC_CTX_copy() copies the state from one B structure to another. + +CMAC_Init() initializes the B structure for a new CMAC calculation +with the specified key, key length, and cipher type. +Optionally, an B can be provided. + +CMAC_Update() processes data to be included in the CMAC calculation. +This function can be called multiple times to update the context with +additional data. + +CMAC_Final() finalizes the CMAC calculation and retrieves the resulting +MAC value. The output is stored in the provided buffer, and the length is +stored in the variable pointed to by I. To determine the required +buffer size, call with I set to NULL, which stores only the length in +I. Allocate a buffer of this size and call CMAC_Final() again with +the allocated buffer to retrieve the MAC. + +CMAC_resume() resumes a previously finalized CMAC calculation, allowing +additional data to be processed and a new MAC to be generated. + +=head1 RETURN VALUES + +CMAC_CTX_new() returns a pointer to a new B structure or NULL if +an error occurs. + +CMAC_CTX_get0_cipher_ctx() returns a pointer to the internal +B structure, or NULL if an error occurs. + +CMAC_CTX_copy(), CMAC_Init(), CMAC_Update(), CMAC_Final() and CMAC_resume() +return 1 for success or 0 if an error occurs. + +=head1 HISTORY + +All functions described here were deprecated in OpenSSL 3.0. For replacements, +see L, L, L, +L, and L. + +=head1 COPYRIGHT + +Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index 08231eddce41d..b7d5091b31912 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -282,15 +282,6 @@ CAST_ofb64_encrypt(3) CAST_set_key(3) CBIGNUM_it(3) CERTIFICATEPOLICIES_it(3) -CMAC_CTX_cleanup(3) -CMAC_CTX_copy(3) -CMAC_CTX_free(3) -CMAC_CTX_get0_cipher_ctx(3) -CMAC_CTX_new(3) -CMAC_Final(3) -CMAC_Init(3) -CMAC_Update(3) -CMAC_resume(3) CMS_ContentInfo_it(3) CMS_EncryptedData_set1_key(3) CMS_ReceiptRequest_it(3) diff --git a/util/other.syms b/util/other.syms index 3902945ac1ab1..094a365a21d99 100644 --- a/util/other.syms +++ b/util/other.syms @@ -833,3 +833,4 @@ EVP_PKEY_id define EVP_PKEY_base_id define SSL_set_retry_verify define TS_VERIFY_CTX define +CMAC_CTX define From 21dfb975968d73b9cd40835d2cd436602079e853 Mon Sep 17 00:00:00 2001 From: Stephen Farrell Date: Thu, 4 Jul 2024 17:34:47 +0100 Subject: [PATCH 123/138] Extend TLSv1.3 record layer padding API calls Added SSL_set_block_padding_ex() and SSL_CTX_set_block_padding_ex() to allow separate padding block size values for handshake messages and application data messages. Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24796) --- doc/man3/SSL_CONF_cmd.pod | 24 ++++++-- .../SSL_CTX_set_record_padding_callback.pod | 10 +++- include/openssl/ssl.h.in | 5 +- ssl/record/methods/recmethod_local.h | 1 + ssl/record/methods/tls13_meth.c | 57 ++++++++++++++----- ssl/record/methods/tls_common.c | 6 ++ ssl/record/rec_layer_s3.c | 2 + ssl/record/record.h | 1 + ssl/ssl_conf.c | 34 +++++++++-- ssl/ssl_lib.c | 55 ++++++++++++++---- ssl/ssl_local.h | 1 + test/sslapitest.c | 18 +++++- util/libssl.num | 2 + util/perl/OpenSSL/paramnames.pm | 1 + 14 files changed, 177 insertions(+), 40 deletions(-) diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod index d9596b82317ee..d2fba6a876a5f 100644 --- a/doc/man3/SSL_CONF_cmd.pod +++ b/doc/man3/SSL_CONF_cmd.pod @@ -227,9 +227,15 @@ deprecated alternative commands below. =item B<-record_padding> I -Attempts to pad TLSv1.3 records so that they are a multiple of B -in length on send. A B of 0 or 1 turns off padding. Otherwise, -the B must be >1 or <=16384. +Controls use of TLSv1.3 record layer padding. B is a string of the +form "number[,number]" where the (required) first number is the padding block +size (in octets) for application data, and the optional second number is the +padding block size for handshake and alert messages. If the optional second +number is omitted, the same padding will be applied to all messages. + +Padding attempts to pad TLSv1.3 records so that they are a multiple of the set +length on send. A value of 0 or 1 turns off padding as relevant. Otherwise, the +values must be >1 or <=16384. =item B<-debug_broken_protocol> @@ -359,9 +365,15 @@ operations are permitted. =item B -Attempts to pad TLSv1.3 records so that they are a multiple of B in -length on send. A B of 0 or 1 turns off padding. Otherwise, the -B must be >1 or <=16384. +Controls use of TLSv1.3 record layer padding. B is a string of the form +"number[,number]" where the (required) first number is the padding block size +(in octets) for application data, and the optional second number is the padding +block size for handshake and alert messages. If the optional second number is +omitted, the same padding will be applied to all messages. + +Padding attempts to pad TLSv1.3 records so that they are a multiple of the set +length on send. A value of 0 or 1 turns off padding as relevant. Otherwise, the +values must be >1 or <=16384. =item B diff --git a/doc/man3/SSL_CTX_set_record_padding_callback.pod b/doc/man3/SSL_CTX_set_record_padding_callback.pod index e91f903b0154a..6d70ebd90073b 100644 --- a/doc/man3/SSL_CTX_set_record_padding_callback.pod +++ b/doc/man3/SSL_CTX_set_record_padding_callback.pod @@ -9,7 +9,9 @@ SSL_set_record_padding_callback_arg, SSL_CTX_get_record_padding_callback_arg, SSL_get_record_padding_callback_arg, SSL_CTX_set_block_padding, -SSL_set_block_padding - install callback to specify TLS 1.3 record padding +SSL_CTX_set_block_padding_ex, +SSL_set_block_padding, +SSL_set_block_padding_ex - install callback to specify TLS 1.3 record padding =head1 SYNOPSIS @@ -26,6 +28,8 @@ SSL_set_block_padding - install callback to specify TLS 1.3 record padding int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size); int SSL_set_block_padding(SSL *ssl, size_t block_size); + int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size, size_t hs_block_size); + int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size, size_t hs_block_size); =head1 DESCRIPTION @@ -46,6 +50,10 @@ SSL_CTX_set_block_padding() and SSL_set_block_padding() pads the record to a mul of the B. A B of 0 or 1 disables block padding. The limit of B is SSL3_RT_MAX_PLAIN_LENGTH. +SSL_CTX_set_block_padding_ex() and SSL_set_block_padding_ex() do similarly but +allow the caller to separately specify the padding block size to be applied to +handshake and application data messages. + The callback is invoked for every record before encryption. The B parameter is the TLS record type that is being processed; may be one of SSL3_RT_APPLICATION_DATA, SSL3_RT_HANDSHAKE, or SSL3_RT_ALERT. diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index c4a40c95c34a8..4bab2ac767f55 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2263,6 +2263,8 @@ void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx, void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg); void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx); int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size); +int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size, + size_t hs_block_size); int SSL_set_record_padding_callback(SSL *ssl, size_t (*cb) (SSL *ssl, int type, @@ -2270,7 +2272,8 @@ int SSL_set_record_padding_callback(SSL *ssl, void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg); void *SSL_get_record_padding_callback_arg(const SSL *ssl); int SSL_set_block_padding(SSL *ssl, size_t block_size); - +int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size, + size_t hs_block_size); int SSL_set_num_tickets(SSL *s, size_t num_tickets); size_t SSL_get_num_tickets(const SSL *s); int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets); diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h index 5a3d010503a86..e08737eb76f99 100644 --- a/ssl/record/methods/recmethod_local.h +++ b/ssl/record/methods/recmethod_local.h @@ -324,6 +324,7 @@ struct ossl_record_layer_st /* TLSv1.3 record padding */ size_t block_padding; + size_t hs_padding; /* Only used by SSLv3 */ unsigned char mac_secret[EVP_MAX_MD_SIZE]; diff --git a/ssl/record/methods/tls13_meth.c b/ssl/record/methods/tls13_meth.c index afae14ad22b20..706a0b8623fdf 100644 --- a/ssl/record/methods/tls13_meth.c +++ b/ssl/record/methods/tls13_meth.c @@ -335,22 +335,51 @@ static int tls13_add_record_padding(OSSL_RECORD_LAYER *rl, size_t padding = 0; size_t max_padding = rl->max_frag_len - rlen; + /* + * We might want to change the "else if" below so that + * library-added padding can still happen even if there + * is an application-layer callback. The reason being + * the application may not be aware that the effectivness + * of ECH could be damaged if the callback e.g. only + * padded application data. However, doing so would be + * a change that could break some application that has + * a client and server that both know what padding they + * like, and that dislike any other padding. That'd need + * one of those to have been updated though so the + * probability may be low enough that we could change + * the "else if" below to just an "if" and pick the + * larger of the library and callback's idea of padding. + * (Still subject to max_padding though.) + */ if (rl->padding != NULL) { padding = rl->padding(rl->cbarg, thistempl->type, rlen); - } else if (rl->block_padding > 0) { - size_t mask = rl->block_padding - 1; - size_t remainder; - - /* optimize for power of 2 */ - if ((rl->block_padding & mask) == 0) - remainder = rlen & mask; - else - remainder = rlen % rl->block_padding; - /* don't want to add a block of padding if we don't have to */ - if (remainder == 0) - padding = 0; - else - padding = rl->block_padding - remainder; + } else if (rl->block_padding > 0 || rl->hs_padding > 0) { + size_t mask, bp = 0, remainder; + + /* + * pad handshake or alert messages based on |hs_padding| + * but application data based on |block_padding| + */ + if (thistempl->type == SSL3_RT_HANDSHAKE && rl->hs_padding > 0) + bp = rl->hs_padding; + else if (thistempl->type == SSL3_RT_ALERT && rl->hs_padding > 0) + bp = rl->hs_padding; + else if (thistempl->type == SSL3_RT_APPLICATION_DATA + && rl->block_padding > 0) + bp = rl->block_padding; + if (bp > 0) { + mask = bp - 1; + /* optimize for power of 2 */ + if ((bp & mask) == 0) + remainder = rlen & mask; + else + remainder = rlen % bp; + /* don't want to add a block of padding if we don't have to */ + if (remainder == 0) + padding = 0; + else + padding = bp - remainder; + } } if (padding > 0) { /* do not allow the record to exceed max plaintext length */ diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c index b09991cafb1d7..0d92bdce9b720 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -1218,6 +1218,12 @@ int tls_set_options(OSSL_RECORD_LAYER *rl, const OSSL_PARAM *options) ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER); return 0; } + p = OSSL_PARAM_locate_const(options, + OSSL_LIBSSL_RECORD_LAYER_PARAM_HS_PADDING); + if (p != NULL && !OSSL_PARAM_get_size_t(p, &rl->hs_padding)) { + ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER); + return 0; + } } if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_APPLICATION) { diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index e61861d9fd16e..14db7dab2cd77 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -1288,6 +1288,8 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, } else { *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING, &s->rlayer.block_padding); + *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_PARAM_HS_PADDING, + &s->rlayer.hs_padding); } *opts = OSSL_PARAM_construct_end(); diff --git a/ssl/record/record.h b/ssl/record/record.h index 9a076a1fb8865..13f09fda8ccb7 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -113,6 +113,7 @@ typedef struct record_layer_st { size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg); void *record_padding_arg; size_t block_padding; + size_t hs_padding; /* How many records we have read from the record layer */ size_t num_recs; diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index 77de00542b06a..0deae1604f7b6 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -649,20 +649,44 @@ static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value) return rv > 0; } +/* + * |value| input is "" + * where the first number is the padding block size for + * application data, and the optional second is the + * padding block size for handshake messages + */ static int cmd_RecordPadding(SSL_CONF_CTX *cctx, const char *value) { int rv = 0; - int block_size = atoi(value); + size_t block_padding = 0, hs_padding = 0; + char *commap = NULL, *copy = NULL; + copy = OPENSSL_strdup(value); + if (copy == NULL) + return 0; + commap = strstr(copy, ","); + if (commap != NULL) { + *commap = '\0'; + if (*(commap + 1) == '\0') { + OPENSSL_free(copy); + return 0; + } + hs_padding = (size_t) atoi(commap + 1); + } + block_padding = (size_t) atoi(copy); + if (commap == NULL) + hs_padding = block_padding; + OPENSSL_free(copy); /* - * All we care about is a non-negative value, + * All we care about are non-negative values, * the setters check the range */ - if (block_size >= 0) { + if (block_padding >= 0 || hs_padding >= 0) { if (cctx->ctx) - rv = SSL_CTX_set_block_padding(cctx->ctx, block_size); + rv = SSL_CTX_set_block_padding_ex(cctx->ctx, block_padding, + hs_padding); if (cctx->ssl) - rv = SSL_set_block_padding(cctx->ssl, block_size); + rv = SSL_set_block_padding_ex(cctx->ssl, block_padding, hs_padding); } return rv; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 589ed2c64d4f9..3b82673957503 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -785,6 +785,7 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method) s->rlayer.record_padding_cb = ctx->record_padding_cb; s->rlayer.record_padding_arg = ctx->record_padding_arg; s->rlayer.block_padding = ctx->block_padding; + s->rlayer.hs_padding = ctx->hs_padding; s->sid_ctx_length = ctx->sid_ctx_length; if (!ossl_assert(s->sid_ctx_length <= sizeof(s->sid_ctx))) goto err; @@ -5713,21 +5714,35 @@ void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx) return ctx->record_padding_arg; } -int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size) +int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size, + size_t hs_block_size) { - if (IS_QUIC_CTX(ctx) && block_size > 1) + if (IS_QUIC_CTX(ctx) && (app_block_size > 1 || hs_block_size > 1)) return 0; /* block size of 0 or 1 is basically no padding */ - if (block_size == 1) + if (app_block_size == 1) { ctx->block_padding = 0; - else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH) - ctx->block_padding = block_size; - else + } else if (app_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) { + ctx->block_padding = app_block_size; + } else { + return 0; + } + if (hs_block_size == 1) { + ctx->hs_padding = 0; + } else if (hs_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) { + ctx->hs_padding = hs_block_size; + } else { return 0; + } return 1; } +int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size) +{ + return SSL_CTX_set_block_padding_ex(ctx, block_size, block_size); +} + int SSL_set_record_padding_callback(SSL *ssl, size_t (*cb) (SSL *ssl, int type, size_t len, void *arg)) @@ -5766,23 +5781,39 @@ void *SSL_get_record_padding_callback_arg(const SSL *ssl) return sc->rlayer.record_padding_arg; } -int SSL_set_block_padding(SSL *ssl, size_t block_size) +int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size, + size_t hs_block_size) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); - if (sc == NULL || (IS_QUIC(ssl) && block_size > 1)) + if (sc == NULL + || (IS_QUIC(ssl) + && (app_block_size > 1 || hs_block_size > 1))) return 0; /* block size of 0 or 1 is basically no padding */ - if (block_size == 1) + if (app_block_size == 1) { sc->rlayer.block_padding = 0; - else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH) - sc->rlayer.block_padding = block_size; - else + } else if (app_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) { + sc->rlayer.block_padding = app_block_size; + } else { + return 0; + } + if (hs_block_size == 1) { + sc->rlayer.hs_padding = 0; + } else if (hs_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) { + sc->rlayer.hs_padding = hs_block_size; + } else { return 0; + } return 1; } +int SSL_set_block_padding(SSL *ssl, size_t block_size) +{ + return SSL_set_block_padding_ex(ssl, block_size, block_size); +} + int SSL_set_num_tickets(SSL *s, size_t num_tickets) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index daab329133cb8..d76a014cabf26 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1126,6 +1126,7 @@ struct ssl_ctx_st { size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg); void *record_padding_arg; size_t block_padding; + size_t hs_padding; /* Session ticket appdata */ SSL_CTX_generate_session_ticket_fn generate_ticket_cb; diff --git a/test/sslapitest.c b/test/sslapitest.c index 7ad12f29713f7..4cd469174d6e6 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -11104,6 +11104,8 @@ static size_t record_pad_cb(SSL *s, int type, size_t len, void *arg) * Test 1: Record padding callback on the SSL * Test 2: Record block padding on the SSL_CTX * Test 3: Record block padding on the SSL + * Test 4: Extended record block padding on the SSL_CTX + * Test 5: Extended record block padding on the SSL */ static int test_tls13_record_padding(int idx) { @@ -11133,6 +11135,10 @@ static int test_tls13_record_padding(int idx) goto end; if (!TEST_true(SSL_CTX_set_block_padding(cctx, 512))) goto end; + } else if (idx == 4) { + /* pad only handshake/alert messages */ + if (!TEST_true(SSL_CTX_set_block_padding_ex(cctx, 0, 512))) + goto end; } if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, @@ -11151,6 +11157,16 @@ static int test_tls13_record_padding(int idx) goto end; if (!TEST_true(SSL_set_block_padding(clientssl, 512))) goto end; + } else if (idx == 5) { + /* Exceeding the max plain length should fail */ + if (!TEST_false(SSL_set_block_padding_ex(clientssl, 0, + SSL3_RT_MAX_PLAIN_LENGTH + 1))) + goto end; + /* pad server and client handshake only */ + if (!TEST_true(SSL_set_block_padding_ex(clientssl, 0, 512))) + goto end; + if (!TEST_true(SSL_set_block_padding_ex(serverssl, 0, 512))) + goto end; } if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) @@ -12637,7 +12653,7 @@ int setup_tests(void) ADD_TEST(test_load_dhfile); #ifndef OSSL_NO_USABLE_TLS1_3 ADD_TEST(test_read_ahead_key_change); - ADD_ALL_TESTS(test_tls13_record_padding, 4); + ADD_ALL_TESTS(test_tls13_record_padding, 6); #endif #if !defined(OPENSSL_NO_TLS1_2) && !defined(OSSL_NO_USABLE_TLS1_3) ADD_ALL_TESTS(test_serverinfo_custom, 4); diff --git a/util/libssl.num b/util/libssl.num index e232d3efd4c51..cd2c7f06a16d7 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -584,3 +584,5 @@ SSL_poll 584 3_3_0 EXIST::FUNCTION: SSL_SESSION_get_time_ex 585 3_3_0 EXIST::FUNCTION: SSL_SESSION_set_time_ex 586 3_3_0 EXIST::FUNCTION: SSL_CTX_flush_sessions_ex 587 3_4_0 EXIST::FUNCTION: +SSL_CTX_set_block_padding_ex ? 3_4_0 EXIST::FUNCTION: +SSL_set_block_padding_ex ? 3_4_0 EXIST::FUNCTION: diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 204a8bb213e6d..6e5c027a223df 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -506,6 +506,7 @@ my %params = ( 'LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN' => "max_frag_len", 'LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA' => "max_early_data", 'LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING' => "block_padding", + 'LIBSSL_RECORD_LAYER_PARAM_HS_PADDING' => "hs_padding", ); # Generate string based macros for public consumption From 2a45839778955ffcab01918f10544d46e42f9a5b Mon Sep 17 00:00:00 2001 From: erbsland-dev Date: Mon, 8 Jul 2024 12:35:55 +0200 Subject: [PATCH 124/138] Enhance documentation for `BN_mask_bits()` Fixes #5537 Added a note that the error check for `BN_mask_bits()` depends on the internal representation that depends on the platform's word size. Included a reference to the `BN_num_bits()` function for precise bit checking. Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24812) --- doc/man3/BN_set_bit.pod | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/man3/BN_set_bit.pod b/doc/man3/BN_set_bit.pod index 349ef9e0562cc..e4d66791e886f 100644 --- a/doc/man3/BN_set_bit.pod +++ b/doc/man3/BN_set_bit.pod @@ -33,8 +33,11 @@ error occurs if B is shorter than B bits. BN_is_bit_set() tests if bit B in B is set. BN_mask_bits() truncates B to an B bit number -(CEn)>). An error occurs if B already is -shorter than B bits. +(CEn)>). An error occurs if B is negative. An error is +also returned if the internal representation of B is already shorter than +B bits. The internal representation depends on the platform's word size, and +this error can be safely ignored. Use L to determine the exact +number of bits if needed. BN_lshift() shifts B left by B bits and places the result in B (C). Note that B must be nonnegative. BN_lshift1() shifts From acae12eb781658479b4fb3fee6334fd14a3c2739 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 8 Jul 2024 08:30:49 -0400 Subject: [PATCH 125/138] Add a check-format-commit.sh script Add a wrapper script to check-format.pl, which is capable of analyzing commits rather than just a file. for a provided commit this script: 1) runs check-format.pl on the files changed in the provided commit 2) filters the output of check-format.pl, only producing lines that match ranges of changed lines in those files Reviewed-by: Tomas Mraz Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/24806) --- util/check-format-commit.sh | 171 ++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100755 util/check-format-commit.sh diff --git a/util/check-format-commit.sh b/util/check-format-commit.sh new file mode 100755 index 0000000000000..7e712dc48cf65 --- /dev/null +++ b/util/check-format-commit.sh @@ -0,0 +1,171 @@ +#!/bin/bash +# Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# You can obtain a copy in the file LICENSE in the source distribution +# or at https://www.openssl.org/source/license.html +# +# This script is a wrapper around check-format.pl. It accepts a commit sha +# value as input, and uses it to identify the files and ranges that were +# changed in that commit, filtering check-format.pl output only to lines that +# fall into the commits change ranges. +# + + +# List of Regexes to use when running check-format.pl. +# Style checks don't apply to any of these +EXCLUDED_FILE_REGEX=("\.pod" \ + "\.pl" \ + "\.pm" \ + "\.t" \ + "\.yml" \ + "\.sh") + +# Exit code for the script +EXIT_CODE=0 + +# Global vars + +# TEMPDIR is used to hold any files this script creates +# And is cleaned on EXIT with a trap function +TEMPDIR=$(mktemp -d /tmp/checkformat.XXXXXX) + +# TOPDIR always points to the root of the git tree we are working in +# used to locate the check-format.pl script +TOPDIR=$(git rev-parse --show-toplevel) + + +# cleanup handler function, returns us to the root of the git tree +# and erases our temp directory +cleanup() { + rm -rf $TEMPDIR + cd $TOPDIR +} + +trap cleanup EXIT + +# Get the canonical sha256 sum for the commit we are checking +# This lets us pass in symbolic ref names like master/etc and +# resolve them to sha256 sums easily +COMMIT=$(git rev-parse $1) + +# Fail gracefully if git rev-parse doesn't produce a valid +# commit +if [ $? -ne 0 ] +then + echo "$1 is not a valid revision" + exit 1 +fi + +# Create a iteratable list of files to check for a +# given commit. It produces output of the format +# , +touch $TEMPDIR/ranges.txt +git show $COMMIT | awk -v mycmt=$COMMIT ' + BEGIN {myfile=""} + /+{3}/ { + gsub(/b\//,"",$2); + myfile=$2 + } + /@@/ { + gsub(/+/,"",$3); + printf mycmt " " myfile " " $3 "\n" + }' >> $TEMPDIR/ranges.txt || true + +# filter out anything that matches on a filter regex +for i in ${EXCLUDED_FILE_REGEX[@]} +do + touch $TEMPDIR/ranges.filter + grep -v "$i" $TEMPDIR/ranges.txt >> $TEMPDIR/ranges.filter || true + REMAINING_FILES=$(wc -l $TEMPDIR/ranges.filter | awk '{print $1}') + if [ $REMAINING_FILES -eq 0 ] + then + echo "This commit has no files that require checking" + exit 0 + fi + mv $TEMPDIR/ranges.filter $TEMPDIR/ranges.txt +done + +# check out the files from the commit level. +# For each file name in ranges, we show that file at the commit +# level we are checking, and redirect it to the same path, relative +# to $TEMPDIR/check-format. This give us the full file to run +# check-format.pl on with line numbers matching the ranges in the +# $TEMPDIR/ranges.txt file +for j in $(grep $COMMIT $TEMPDIR/ranges.txt | awk '{print $2}') +do + FDIR=$(dirname $j) + mkdir -p $TEMPDIR/check-format/$FDIR + git show $COMMIT:$j > $TEMPDIR/check-format/$j +done + +# Now for each file in $TEMPDIR/check-format run check-format.pl +# Note that we use the %P formatter in the find utilty. This strips +# off the $TEMPDIR/check-format path prefix, leaving $j with the +# path to the file relative to the root of the source dir, so that +# output from check-format.pl looks correct, relative to the root +# of the git tree. +for j in $(find $TEMPDIR/check-format -type f -printf "%P\n") +do + range_start=() + range_end=() + + # Get the ranges for this file. Create 2 arrays. range_start contains + # the start lines for valid ranges from the commit. the range_end array + # contains the corresponding end line (note, since diff output gives us + # a line count for a change, the range_end[k] entry is actually + # range_start[k]+line count + for k in $(grep $COMMIT $TEMPDIR/ranges.txt | grep $j | awk '{print $3}') + do + RANGE=$k + RSTART=$(echo $RANGE | awk -F',' '{print $1}') + RLEN=$(echo $RANGE | awk -F',' '{print $2}') + let REND=$RSTART+$RLEN + range_start+=($RSTART) + range_end+=($REND) + done + + # Go to our checked out tree + cd $TEMPDIR/check-format + + # Actually run check-format.pl on the file, capturing the output + # in a temporary file. Note the format of check-patch.pl output is + # ::: + $TOPDIR/util/check-format.pl $j > $TEMPDIR/format-results.txt + + # Now we filter the check-format.pl output based on the changed lines + # captured in the range_start/end arrays + let maxidx=${#range_start[@]}-1 + for k in $(seq 0 1 $maxidx) + do + RSTART=${range_start[$k]} + REND=${range_end[$k]} + + # field 2 of check-format.pl output is the offending line number + # Check here if any line in that output falls between any of the + # start/end ranges defined in the range_start/range_end array. + # If it does fall in that range, print the entire line to stdout + # If anything is printed, have awk exit with a non-zero exit code + awk -v rstart=$RSTART -v rend=$REND -F':' ' + BEGIN {rc=0} + /:/ { + if (($2 >= rstart) && ($2 <= rend)) { + print $0; + rc=1 + } + } + END {exit rc;} + ' $TEMPDIR/format-results.txt + + # If awk exited with a non-zero code, this script will also exit + # with a non-zero code + if [ $? -ne 0 ] + then + EXIT_CODE=1 + fi + done +done + +# Exit with the recorded exit code above +exit $EXIT_CODE From fc22d74c53720d14f99fd880b767d8a3e4986ae2 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 8 Jul 2024 08:32:29 -0400 Subject: [PATCH 126/138] Add a style-check workflow Add a CI job that evaluates style issues, restricted only to lines changed for the affected files in a given commit Also provide a mechanism to waive those style issues. by applying the style:exempted label to a PR, the checks are still run (its nice to see what they are regardless), but the test will pass CI regardless of weather any issues are found. Reviewed-by: Tomas Mraz Reviewed-by: Tom Cosgrove (Merged from https://github.com/openssl/openssl/pull/24806) --- .github/workflows/style-checks.yml | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/style-checks.yml diff --git a/.github/workflows/style-checks.yml b/.github/workflows/style-checks.yml new file mode 100644 index 0000000000000..7ed843f3ba459 --- /dev/null +++ b/.github/workflows/style-checks.yml @@ -0,0 +1,55 @@ +# Copyright 2021-2024 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +name: Coding style validation + +on: [pull_request] + +env: + PR_NUMBER: ${{ github.event.number }} + GH_TOKEN: ${{ github.token }} + +permissions: + contents: read + +jobs: + check-style: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + path: openssl + - name: check style for each commit + working-directory: openssl + shell: bash + run: | + ERRORS_FOUND=0 + git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF + REFSTART=$(git rev-parse $GITHUB_BASE_REF) + REFEND=$(git rev-parse HEAD) + echo "Checking from $REFSTART to $REFEND" + for i in $(git log --no-merges --format=%H $REFSTART..$REFEND) + do + echo "::group::Style report for commit $i" + set +e + ./util/check-format-commit.sh $i + if [ $? -ne 0 ] + then + ERRORS_FOUND=1 + fi + set -e + echo "::endgroup::" + done + SKIP_TEST=$(gh pr view $PR_NUMBER --json labels --jq '.labels[] | select(.name == "style: waived") | .name') + if [ -z "$SKIP_TEST" ] + then + exit $ERRORS_FOUND + else + echo "PR $PR_NUMBER is marked with style: waived, waiving style check errors" + exit 0 + fi From 850bd09cf9f8c44a7c6b1fdcdde8a147748ee513 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 9 Jul 2024 11:12:58 +0200 Subject: [PATCH 127/138] windows_comp.yml: Run openssl after it is built Reviewed-by: Neil Horman Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/24820) --- .github/workflows/windows_comp.yml | 45 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/.github/workflows/windows_comp.yml b/.github/workflows/windows_comp.yml index e7f8922ccfb13..34c5c3208b1ae 100644 --- a/.github/workflows/windows_comp.yml +++ b/.github/workflows/windows_comp.yml @@ -11,6 +11,7 @@ on: pull_request: paths: - 'crypto/comp/*.c' + - '.github/workflows/windows_comp.yml' push: paths: - '**.c' @@ -33,12 +34,21 @@ jobs: working-directory: _build run: | vcpkg install zstd:x64-windows + - name: config + working-directory: _build + run: | + perl ..\Configure enable-comp enable-zstd --with-zstd-include=C:\vcpkg\packages\zstd_x64-windows\include --with-zstd-lib=C:\vcpkg\packages\zstd_x64-windows\lib\zstd.lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A + perl configdata.pm --dump + - name: build + working-directory: _build + run: nmake - name: Gather openssl version info working-directory: _build run: | + $env:Path+=";C:\vcpkg\packages\zstd_x64-windows\bin" apps/openssl.exe version -v apps/openssl.exe version -v | %{($_ -split '\s+')[1]} - apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} + apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} echo "OSSL_VERSION=$(apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'})" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build @@ -48,14 +58,6 @@ jobs: reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 reg.exe query HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /reg:32 - - name: config - working-directory: _build - run: | - perl ..\Configure enable-comp enable-zstd --with-zstd-include=C:\vcpkg\packages\zstd_x64-windows\include --with-zstd-lib=C:\vcpkg\packages\zstd_x64-windows\lib\zstd.lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake - name: download coreinfo uses: suisei-cn/actions-download-file@v1.6.0 with: @@ -65,6 +67,7 @@ jobs: working-directory: _build continue-on-error: true run: | + $env:Path+=";C:\vcpkg\packages\zstd_x64-windows\bin" 7z.exe x coreinfo/Coreinfo.zip ./Coreinfo64.exe -accepteula -f ./apps/openssl.exe version -c @@ -90,13 +93,22 @@ jobs: working-directory: _build run: | vcpkg install brotli:x64-windows + - name: config + working-directory: _build + run: | + perl ..\Configure enable-comp enable-brotli --with-brotli-include=C:\vcpkg\packages\brotli_x64-windows\include --with-brotli-lib=C:\vcpkg\packages\brotli_x64-windows\lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A + perl configdata.pm --dump + - name: build + working-directory: _build + run: nmake - name: Gather openssl version info working-directory: _build run: | + $env:Path+=";C:\vcpkg\packages\brotli_x64-windows\bin" apps/openssl.exe version -v - apps/openssl.exe version -v | awk '{print $2}' - apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//' - echo "OSSL_VERSION=$(apps/openssl.exe version -v | awk '{print $2}' | sed -e's/-.*$//')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + apps/openssl.exe version -v | %{($_ -split '\s+')[1]} + apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'} + echo "OSSL_VERSION=$(apps/openssl.exe version -v | %{($_ -split '\s+')[1] -replace '([0-9]+\.[0-9]+)(\..*)','$1'})" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Set registry keys working-directory: _build run: | @@ -105,14 +117,6 @@ jobs: reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v ENGINESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 reg.exe add HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v MODULESDIR /t REG_EXPAND_SZ /d TESTOPENSSLDIR /reg:32 reg.exe query HKLM\SOFTWARE\OpenSSL-${Env:OSSL_VERSION}-openssl /v OPENSSLDIR /reg:32 - - name: config - working-directory: _build - run: | - perl ..\Configure enable-comp enable-brotli --with-brotli-include=C:\vcpkg\packages\brotli_x64-windows\include --with-brotli-lib=C:\vcpkg\packages\brotli_x64-windows\lib no-makedepend -DOSSL_WINCTX=openssl VC-WIN64A - perl configdata.pm --dump - - name: build - working-directory: _build - run: nmake - name: download coreinfo uses: suisei-cn/actions-download-file@v1.6.0 with: @@ -122,6 +126,7 @@ jobs: working-directory: _build continue-on-error: true run: | + $env:Path+=";C:\vcpkg\packages\brotli_x64-windows\bin" 7z.exe x coreinfo/Coreinfo.zip ./Coreinfo64.exe -accepteula -f ./apps/openssl.exe version -c From 39424d960190706c913c7db2b97ec256aeba6173 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:25:20 +0200 Subject: [PATCH 128/138] apps/req: avoid needless hint on using -help on duplicate extensions added via -addext Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- apps/req.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/req.c b/apps/req.c index dfa8319156e63..2d23861cf6987 100644 --- a/apps/req.c +++ b/apps/req.c @@ -481,7 +481,7 @@ int req_main(int argc, char **argv) } i = duplicated(addexts, p); if (i == 1) - goto opthelp; + goto end; if (i == -1) BIO_printf(bio_err, "Internal error handling -addext %s\n", p); if (i < 0 || BIO_printf(addext_bio, "%s\n", p) < 0) From 77600210e20b566f746fcc7fc18f44f1b01a2313 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:27:54 +0200 Subject: [PATCH 129/138] X509at_add1_attr*(): extend error entry on duplicate attribute Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- crypto/x509/x509_att.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c index 5b002832c1d09..c9e2b26c7a82c 100644 --- a/crypto/x509/x509_att.c +++ b/crypto/x509/x509_att.c @@ -123,7 +123,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, return NULL; } if (*x != NULL && X509at_get_attr_by_OBJ(*x, attr->object, -1) != -1) { - ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + ERR_raise_data(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE, + "name=%s", OBJ_nid2sn(OBJ_obj2nid(attr->object))); return NULL; } @@ -158,7 +159,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) return NULL; } if (*x != NULL && X509at_get_attr_by_OBJ(*x, obj, -1) != -1) { - ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + ERR_raise_data(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE, + "name=%s", OBJ_nid2sn(OBJ_obj2nid(obj))); return NULL; } @@ -191,7 +193,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) return NULL; } if (*x != NULL && X509at_get_attr_by_NID(*x, nid, -1) != -1) { - ERR_raise(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE); + ERR_raise_data(ERR_LIB_X509, X509_R_DUPLICATE_ATTRIBUTE, + "name=%s", OBJ_nid2sn(nid)); return NULL; } From b0ebb87ab5cfdee3e272f5ff9596e8beba4571a6 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:29:14 +0200 Subject: [PATCH 130/138] constify ossl_x509at_add1_attr() Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- crypto/x509/x509_att.c | 2 +- include/crypto/x509.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c index c9e2b26c7a82c..b21aa4d299409 100644 --- a/crypto/x509/x509_att.c +++ b/crypto/x509/x509_att.c @@ -80,7 +80,7 @@ X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) } STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, - X509_ATTRIBUTE *attr) + const X509_ATTRIBUTE *attr) { X509_ATTRIBUTE *new_attr = NULL; STACK_OF(X509_ATTRIBUTE) *sk = NULL; diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 81d543a7a1389..338e58b4919f9 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -373,7 +373,7 @@ int x509v3_add_len_value_uchar(const char *name, const unsigned char *value, size_t vallen, STACK_OF(CONF_VALUE) **extlist); /* Attribute addition functions not checking for duplicate attributes */ STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, - X509_ATTRIBUTE *attr); + const X509_ATTRIBUTE *attr); STACK_OF(X509_ATTRIBUTE) *ossl_x509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, const ASN1_OBJECT *obj, int type, From 94b40ec455dfe18b77e8d74f937b5dce066b2fa8 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:33:42 +0200 Subject: [PATCH 131/138] refactor and constify X509_REQ_get_extensions() Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- crypto/x509/x509_req.c | 40 ++++++++++++++++++---------- doc/man3/X509_REQ_get_extensions.pod | 2 +- include/openssl/types.h | 6 +++++ include/openssl/x509.h.in | 2 +- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c index 74d1d29938f3e..f96a89d671365 100644 --- a/crypto/x509/x509_req.c +++ b/crypto/x509/x509_req.c @@ -117,26 +117,19 @@ void X509_REQ_set_extension_nids(int *nids) ext_nids = nids; } -STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req) +static STACK_OF(X509_EXTENSION) *get_extensions_by_nid(const X509_REQ *req, + int nid) { X509_ATTRIBUTE *attr; ASN1_TYPE *ext = NULL; - int idx, *pnid; const unsigned char *p; + int idx = X509_REQ_get_attr_by_NID(req, nid, -1); - if (req == NULL || !ext_nids) - return NULL; - for (pnid = ext_nids; *pnid != NID_undef; pnid++) { - idx = X509_REQ_get_attr_by_NID(req, *pnid, -1); - if (idx < 0) - continue; - attr = X509_REQ_get_attr(req, idx); - ext = X509_ATTRIBUTE_get0_type(attr, 0); - break; - } - if (ext == NULL) /* no extensions is not an error */ + if (idx < 0) /* no extensions is not an error */ return sk_X509_EXTENSION_new_null(); - if (ext->type != V_ASN1_SEQUENCE) { + attr = X509_REQ_get_attr(req, idx); + ext = X509_ATTRIBUTE_get0_type(attr, 0); + if (ext == NULL || ext->type != V_ASN1_SEQUENCE) { ERR_raise(ERR_LIB_X509, X509_R_WRONG_TYPE); return NULL; } @@ -146,6 +139,25 @@ STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req) ASN1_ITEM_rptr(X509_EXTENSIONS)); } +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(OSSL_FUTURE_CONST X509_REQ *req) +{ + STACK_OF(X509_EXTENSION) *exts = NULL; + int *pnid; + + if (req == NULL || ext_nids == NULL) + return NULL; + for (pnid = ext_nids; *pnid != NID_undef; pnid++) { + exts = get_extensions_by_nid(req, *pnid); + if (exts == NULL) + return NULL; + if (sk_X509_EXTENSION_num(exts) > 0) + return exts; + sk_X509_EXTENSION_free(exts); + } + /* no extensions is not an error */ + return sk_X509_EXTENSION_new_null(); +} + /* * Add a STACK_OF extensions to a certificate request: allow alternative OIDs * in case we want to create a non standard one. diff --git a/doc/man3/X509_REQ_get_extensions.pod b/doc/man3/X509_REQ_get_extensions.pod index 7a3932c3d62aa..73e2ea698a7b0 100644 --- a/doc/man3/X509_REQ_get_extensions.pod +++ b/doc/man3/X509_REQ_get_extensions.pod @@ -10,7 +10,7 @@ X509_REQ_add_extensions, X509_REQ_add_extensions_nid #include - STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); + STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(const X509_REQ *req); int X509_REQ_add_extensions(X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts); int X509_REQ_add_extensions_nid(X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts, int nid); diff --git a/include/openssl/types.h b/include/openssl/types.h index c28028681fcef..91c70813655d7 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -33,6 +33,12 @@ extern "C" { # include # include +# if OPENSSL_VERSION_MAJOR >= 4 +# define OSSL_FUTURE_CONST const +# else +# define OSSL_FUTURE_CONST +# endif + typedef struct ossl_provider_st OSSL_PROVIDER; /* Provider Object */ # ifdef NO_ASN1_TYPEDEFS diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in index 7d7ffa27d08f5..fb755ce452598 100644 --- a/include/openssl/x509.h.in +++ b/include/openssl/x509.h.in @@ -710,7 +710,7 @@ X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req); int X509_REQ_extension_nid(int nid); int *X509_REQ_get_extension_nids(void); void X509_REQ_set_extension_nids(int *nids); -STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(OSSL_FUTURE_CONST X509_REQ *req); int X509_REQ_add_extensions_nid(X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts, int nid); int X509_REQ_add_extensions(X509_REQ *req, const STACK_OF(X509_EXTENSION) *ext); From 4925af7bb88dbe11c323813fd91740dcd813bfd8 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:39:25 +0200 Subject: [PATCH 132/138] add X509v3_add_extensions() Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- crypto/cmp/cmp_msg.c | 30 +----------------------------- crypto/x509/x509_v3.c | 30 ++++++++++++++++++++++++++++++ doc/man3/X509v3_get_ext_by_NID.pod | 26 ++++++++++++++++++++------ include/openssl/x509.h.in | 3 +++ util/libcrypto.num | 1 + 5 files changed, 55 insertions(+), 35 deletions(-) diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c index 4ba7b81087691..9628f0500ad56 100644 --- a/crypto/cmp/cmp_msg.c +++ b/crypto/cmp/cmp_msg.c @@ -145,34 +145,6 @@ static int add1_extension(X509_EXTENSIONS **pexts, int nid, int crit, void *ex) return res; } -/* Add extension list to the referenced extension stack, which may be NULL */ -static int add_extensions(STACK_OF(X509_EXTENSION) **target, - const STACK_OF(X509_EXTENSION) *exts) -{ - int i; - - if (target == NULL) - return 0; - - for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); - int idx = X509v3_get_ext_by_OBJ(*target, obj, -1); - - /* Does extension exist in target? */ - if (idx != -1) { - /* Delete all extensions of same type */ - do { - X509_EXTENSION_free(sk_X509_EXTENSION_delete(*target, idx)); - idx = X509v3_get_ext_by_OBJ(*target, obj, -1); - } while (idx != -1); - } - if (!X509v3_add_ext(target, ext, -1)) - return 0; - } - return 1; -} - /* Add a CRL revocation reason code to extension stack, which may be NULL */ static int add_crl_reason_extension(X509_EXTENSIONS **pexts, int reason_code) { @@ -359,7 +331,7 @@ OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) && !add1_extension(&exts, NID_subject_alt_name, crit, default_sans)) goto err; if (ctx->reqExtensions != NULL /* augment/override existing ones */ - && !add_extensions(&exts, ctx->reqExtensions)) + && X509v3_add_extensions(&exts, ctx->reqExtensions) == NULL) goto err; if (sk_GENERAL_NAME_num(ctx->subjectAltNames) > 0 && !add1_extension(&exts, NID_subject_alt_name, diff --git a/crypto/x509/x509_v3.c b/crypto/x509/x509_v3.c index 1bb0a4b037bff..034b119a2b588 100644 --- a/crypto/x509/x509_v3.c +++ b/crypto/x509/x509_v3.c @@ -142,6 +142,36 @@ STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, return NULL; } +STACK_OF(X509_EXTENSION) + *X509v3_add_extensions(STACK_OF(X509_EXTENSION) **target, + const STACK_OF(X509_EXTENSION) *exts) +{ + int i; + + if (target == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); + int idx = X509v3_get_ext_by_OBJ(*target, obj, -1); + + /* Does extension exist in target? */ + if (idx != -1) { + /* Delete all extensions of same type */ + do { + X509_EXTENSION_free(sk_X509_EXTENSION_delete(*target, idx)); + idx = X509v3_get_ext_by_OBJ(*target, obj, -1); + } while (idx != -1); + } + if (!X509v3_add_ext(target, ext, -1)) + return NULL; + } + return *target; +} + X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid, int crit, ASN1_OCTET_STRING *data) diff --git a/doc/man3/X509v3_get_ext_by_NID.pod b/doc/man3/X509v3_get_ext_by_NID.pod index 4010a71c4371a..0974c8641615f 100644 --- a/doc/man3/X509v3_get_ext_by_NID.pod +++ b/doc/man3/X509v3_get_ext_by_NID.pod @@ -4,7 +4,7 @@ X509v3_get_ext_count, X509v3_get_ext, X509v3_get_ext_by_NID, X509v3_get_ext_by_OBJ, X509v3_get_ext_by_critical, X509v3_delete_ext, -X509v3_add_ext, X509_get_ext_count, X509_get_ext, +X509v3_add_ext, X509v3_add_extensions, X509_get_ext_count, X509_get_ext, X509_get_ext_by_NID, X509_get_ext_by_OBJ, X509_get_ext_by_critical, X509_delete_ext, X509_add_ext, X509_CRL_get_ext_count, X509_CRL_get_ext, X509_CRL_get_ext_by_NID, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext_by_critical, @@ -29,6 +29,9 @@ X509_REVOKED_add_ext - extension stack utility functions X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, X509_EXTENSION *ex, int loc); + STACK_OF(X509_EXTENSION) + *X509v3_add_extensions(STACK_OF(X509_EXTENSION) **target, + const STACK_OF(X509_EXTENSION) *exts); int X509_get_ext_count(const X509 *x); X509_EXTENSION *X509_get_ext(const X509 *x, int loc); @@ -79,10 +82,16 @@ X509v3_delete_ext() deletes the extension with index I from I. The deleted extension is returned and must be freed by the caller. If I is an invalid index value, NULL is returned. -X509v3_add_ext() adds extension I to STACK I<*x> at position I. If -I is -1, the new extension is added to the end. If I<*x> is NULL, -a new STACK will be allocated. The passed extension I is duplicated -internally so it must be freed after use. +X509v3_add_ext() inserts extension I to STACK I<*x> at position I. +If I is -1, the new extension is added to the end. +A new STACK is allocated if I<*x> is NULL. +The passed extension I is duplicated so it must be freed after use. + +X509v3_add_extensions() adds the list of extensions I to STACK I<*target>. +The STACK I<*target> is returned unchanged if I is NULL or an empty list. +Otherwise a new stack is allocated if I<*target> is NULL. +An extension to be added +that has the same OID as a pre-existing one replaces this earlier one. X509_get_ext_count(), X509_get_ext(), X509_get_ext_by_NID(), X509_get_ext_by_OBJ(), X509_get_ext_by_critical(), X509_delete_ext() @@ -132,7 +141,8 @@ the extension index or -1 if an error occurs. X509v3_get_ext_by_NID() returns the extension index or negative values if an error occurs. -X509v3_add_ext() returns a STACK of extensions or NULL on error. +X509v3_add_ext() and X509v3_add_extensions() +return a STACK of extensions or NULL on error. X509_add_ext() returns 1 on success and 0 on error. @@ -140,6 +150,10 @@ X509_add_ext() returns 1 on success and 0 on error. L +=head1 HISTORY + +X509v3_add_extensions() was added in OpenSSL 3.4. + =head1 COPYRIGHT Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in index fb755ce452598..99bc4aab29133 100644 --- a/include/openssl/x509.h.in +++ b/include/openssl/x509.h.in @@ -899,6 +899,9 @@ X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, X509_EXTENSION *ex, int loc); +STACK_OF(X509_EXTENSION) + *X509v3_add_extensions(STACK_OF(X509_EXTENSION) **target, + const STACK_OF(X509_EXTENSION) *exts); int X509_get_ext_count(const X509 *x); int X509_get_ext_by_NID(const X509 *x, int nid, int lastpos); diff --git a/util/libcrypto.num b/util/libcrypto.num index cbe61d1a99526..a553a9ae74864 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5649,6 +5649,7 @@ X509_ACERT_verify ? 3_4_0 EXIST::FUNCTION: X509_ACERT_get_ext_d2i ? 3_4_0 EXIST::FUNCTION: X509_ACERT_add1_ext_i2d ? 3_4_0 EXIST::FUNCTION: X509_ACERT_get0_extensions ? 3_4_0 EXIST::FUNCTION: +X509v3_add_extensions ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_it ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_free ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_new ? 3_4_0 EXIST::FUNCTION: From eaf577c865c41946b478b4da5f8c477e132d470d Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Thu, 4 Jul 2024 09:42:00 +0200 Subject: [PATCH 133/138] extend X509_REQ_add_extensions_nid() and thuis APPS/req to support augmenting/overriding existing extensions Fixes #11169 Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24792) --- crypto/x509/x509_req.c | 31 +++++++++++++++++++++++++--- doc/man1/openssl-req.pod.in | 6 +++++- doc/man3/X509_REQ_get_extensions.pod | 16 +++++++------- test/recipes/25-test_req.t | 7 +++++-- test/test.cnf | 3 +++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c index f96a89d671365..4085b587a5e18 100644 --- a/crypto/x509/x509_req.c +++ b/crypto/x509/x509_req.c @@ -168,14 +168,39 @@ int X509_REQ_add_extensions_nid(X509_REQ *req, int extlen; int rv = 0; unsigned char *ext = NULL; + STACK_OF(X509_EXTENSION) *mod_exts = NULL; + int loc; + + if (sk_X509_EXTENSION_num(exts) <= 0) + return 1; /* adding NULL or empty list of exts is a no-op */ + + loc = X509at_get_attr_by_NID(req->req_info.attributes, nid, -1); + if (loc != -1) { + if ((mod_exts = get_extensions_by_nid(req, nid)) == NULL) + return 0; + if (X509v3_add_extensions(&mod_exts, exts) == NULL) + goto end; + } /* Generate encoding of extensions */ - extlen = ASN1_item_i2d((const ASN1_VALUE *)exts, &ext, - ASN1_ITEM_rptr(X509_EXTENSIONS)); + extlen = ASN1_item_i2d((const ASN1_VALUE *) + (mod_exts == NULL ? exts : mod_exts), + &ext, ASN1_ITEM_rptr(X509_EXTENSIONS)); if (extlen <= 0) - return 0; + goto end; + if (mod_exts != NULL) { + X509_ATTRIBUTE *att = X509at_delete_attr(req->req_info.attributes, loc); + + if (att == NULL) + goto end; + X509_ATTRIBUTE_free(att); + } + rv = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext, extlen); OPENSSL_free(ext); + + end: + sk_X509_EXTENSION_pop_free(mod_exts, X509_EXTENSION_free); return rv; } diff --git a/doc/man1/openssl-req.pod.in b/doc/man1/openssl-req.pod.in index 808801348fd59..0eacfc51a4c4f 100644 --- a/doc/man1/openssl-req.pod.in +++ b/doc/man1/openssl-req.pod.in @@ -392,7 +392,11 @@ Add a specific extension to the certificate (if B<-x509> is in use) or certificate request. The argument must have the form of a C pair as it would appear in a config file. +If an extension is added using this option that has the same OID as one +defined in the extension section of the config file, it overrides that one. + This option can be given multiple times. +Doing so, the same key most not be given more than once. =item B<-precert> @@ -552,7 +556,7 @@ BMPStrings and UTF8Strings. This specifies the configuration file section containing a list of extensions to add to the certificate request. It can be overridden -by the B<-reqexts> command line switch. See the +by the B<-reqexts> (or B<-extensions>) command line switch. See the L manual page for details of the extension section format. diff --git a/doc/man3/X509_REQ_get_extensions.pod b/doc/man3/X509_REQ_get_extensions.pod index 73e2ea698a7b0..bd50faa63d155 100644 --- a/doc/man3/X509_REQ_get_extensions.pod +++ b/doc/man3/X509_REQ_get_extensions.pod @@ -22,13 +22,15 @@ found in the attributes of I. The returned list is empty if there are no such extensions in I. The caller is responsible for freeing the list obtained. -X509_REQ_add_extensions() adds to I a list of X.509 extensions I, -which must not be NULL, using the default B. -This function must not be called more than once on the same I. - -X509_REQ_add_extensions_nid() is like X509_REQ_add_extensions() -except that I is used to identify the extensions attribute. -This function must not be called more than once with the same I and I. +X509_REQ_add_extensions_nid() adds to I a list of X.509 extensions I, +using I to identify the extensions attribute. +I is unchanged if I is NULL or an empty list. +This function may be called more than once on the same I and I. +In such case any previous extensions are augmented, where an extension to be +added that has the same OID as a pre-existing one replaces this earlier one. + +X509_REQ_add_extensions() is like X509_REQ_add_extensions_nid() +except that the default B is used. =head1 RETURN VALUES diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index 872ed316fc73c..a0f1efdab1e0d 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_req"); -plan tests => 109; +plan tests => 110; require_ok(srctop_file('test', 'recipes', 'tconversion.pl')); @@ -36,7 +36,7 @@ if (disabled("rsa")) { $ENV{MSYS2_ARG_CONV_EXCL} = "/CN="; # Check for duplicate -addext parameters, and one "working" case. -my @addext_args = ( "openssl", "req", "-new", "-out", "testreq.pem", +my @addext_args = ( "openssl", "req", "-new", "-out", "testreq-addexts.pem", "-key", srctop_file(@certs, "ee-key.pem"), "-config", srctop_file("test", "test.cnf"), @req_new ); my $val = "subjectAltName=DNS:example.com"; @@ -55,6 +55,9 @@ ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3]))); ok(run(app([@addext_args, "-addext", "SXNetID=1:one, 2:two, 3:three"]))); ok(run(app([@addext_args, "-addext", "subjectAltName=dirName:dirname_sec"]))); +ok(run(app([@addext_args, "-addext", "keyUsage=digitalSignature", + "-reqexts", "reqexts"]))); # referring to section in test.cnf + # If a CSR is provided with neither of -key or -CA/-CAkey, this should fail. ok(!run(app(["openssl", "req", "-x509", "-in", srctop_file(@certs, "x509-check.csr"), diff --git a/test/test.cnf b/test/test.cnf index 8f68982a9fa1f..e0135ca206594 100644 --- a/test/test.cnf +++ b/test/test.cnf @@ -78,3 +78,6 @@ C = UK O = My Organization OU = My Unit CN = My Name + +[ reqexts ] +keyUsage = critical,digitalSignature,keyEncipherment From 45cada1339bacc81765b02367bdbaf878445081d Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Fri, 5 Jul 2024 18:05:35 +0000 Subject: [PATCH 134/138] apps/rehash.c: Add the check for the EVP_MD_get_size() Add the check for the return value of EVP_MD_get_size() to avoid invalid negative numbers and then explicitly cast from int to size_t. Add the check to prevent that EVP_MD_get_size() returns a value greater than EVP_MAX_MD_SIZE. Signed-off-by: Jiasheng Jiang Reviewed-by: Neil Horman Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/24802) --- apps/rehash.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/rehash.c b/apps/rehash.c index 9862b9fba916a..9a5be029d3fb9 100644 --- a/apps/rehash.c +++ b/apps/rehash.c @@ -140,7 +140,7 @@ static int add_entry(enum Type type, unsigned int hash, const char *filename, } for (ep = bp->first_entry; ep; ep = ep->next) { - if (digest && memcmp(digest, ep->digest, evpmdsize) == 0) { + if (digest && memcmp(digest, ep->digest, (size_t)evpmdsize) == 0) { BIO_printf(bio_err, "%s: warning: skipping duplicate %s in %s\n", opt_getprog(), @@ -183,7 +183,7 @@ static int add_entry(enum Type type, unsigned int hash, const char *filename, if (need_symlink && !ep->need_symlink) { ep->need_symlink = 1; bp->num_needed++; - memcpy(ep->digest, digest, evpmdsize); + memcpy(ep->digest, digest, (size_t)evpmdsize); } return 0; } @@ -553,6 +553,9 @@ int rehash_main(int argc, char **argv) evpmd = EVP_sha1(); evpmdsize = EVP_MD_get_size(evpmd); + if (evpmdsize <= 0 || evpmdsize > EVP_MAX_MD_SIZE) + goto end; + if (*argv != NULL) { while (*argv != NULL) errs += do_dir(*argv++, h); From 0557d6c62b7d1f46f6f51e0dca87ad9409236164 Mon Sep 17 00:00:00 2001 From: slontis Date: Mon, 1 Jul 2024 11:11:16 +1000 Subject: [PATCH 135/138] Add FIPS indicator callback. Add a FIPS indicator callback that can be set via OSSL_INDICATOR_set_callback(). This callback is intended to be run whenever a non approved algorithm check has occurred and strict checking has been disabled.The callback may be used to log non approved algorithms. The callback is passed a type and description string as well as the cbarg specified in OSSL_INDICATOR_set_callback. The return value can be either 0 or 1. A value of 0 can be used for testing purposes to force an error to occur from the algorithm that called the callback. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24623) --- crypto/build.info | 2 +- crypto/context.c | 11 ++++ crypto/indicator_core.c | 55 ++++++++++++++++ crypto/provider_core.c | 9 +++ doc/build.info | 6 ++ doc/man3/OSSL_INDICATOR_set_callback.pod | 81 ++++++++++++++++++++++++ include/crypto/context.h | 2 + include/internal/cryptlib.h | 3 +- include/openssl/core_dispatch.h | 5 ++ include/openssl/indicator.h | 31 +++++++++ providers/fips/fipsprov.c | 22 ++++++- 11 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 crypto/indicator_core.c create mode 100644 doc/man3/OSSL_INDICATOR_set_callback.pod create mode 100644 include/openssl/indicator.h diff --git a/crypto/build.info b/crypto/build.info index 881007f8acb17..2642d30754b58 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -91,7 +91,7 @@ DEFINE[../providers/libdefault.a]=$CPUIDDEF $CORE_COMMON=provider_core.c provider_predefined.c \ core_fetch.c core_algorithm.c core_namemap.c self_test_core.c -SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c +SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c indicator_core.c SOURCE[../providers/libfips.a]=$CORE_COMMON # Central utilities diff --git a/crypto/context.c b/crypto/context.c index 1059a43b2c80a..f3d9f384fc82a 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -40,6 +40,7 @@ struct ossl_lib_ctx_st { OSSL_METHOD_STORE *encoder_store; OSSL_METHOD_STORE *store_loader_store; void *self_test_cb; + void *indicator_cb; #endif #if defined(OPENSSL_THREADS) void *threads; @@ -177,6 +178,9 @@ static int context_init(OSSL_LIB_CTX *ctx) ctx->self_test_cb = ossl_self_test_set_callback_new(ctx); if (ctx->self_test_cb == NULL) goto err; + ctx->indicator_cb = ossl_indicator_set_callback_new(ctx); + if (ctx->indicator_cb == NULL) + goto err; #endif #ifdef FIPS_MODULE @@ -313,6 +317,11 @@ static void context_deinit_objs(OSSL_LIB_CTX *ctx) } #ifndef FIPS_MODULE + if (ctx->indicator_cb != NULL) { + ossl_indicator_set_callback_free(ctx->indicator_cb); + ctx->indicator_cb = NULL; + } + if (ctx->self_test_cb != NULL) { ossl_self_test_set_callback_free(ctx->self_test_cb); ctx->self_test_cb = NULL; @@ -604,6 +613,8 @@ void *ossl_lib_ctx_get_data(OSSL_LIB_CTX *ctx, int index) return ctx->store_loader_store; case OSSL_LIB_CTX_SELF_TEST_CB_INDEX: return ctx->self_test_cb; + case OSSL_LIB_CTX_INDICATOR_CB_INDEX: + return ctx->indicator_cb; #endif #ifndef OPENSSL_NO_THREAD_POOL case OSSL_LIB_CTX_THREAD_INDEX: diff --git a/crypto/indicator_core.c b/crypto/indicator_core.c new file mode 100644 index 0000000000000..4b3c1227179f8 --- /dev/null +++ b/crypto/indicator_core.c @@ -0,0 +1,55 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "internal/cryptlib.h" +#include "crypto/context.h" + +typedef struct indicator_cb_st +{ + OSSL_INDICATOR_CALLBACK *cb; +} INDICATOR_CB; + +void *ossl_indicator_set_callback_new(OSSL_LIB_CTX *ctx) +{ + INDICATOR_CB *cb; + + cb = OPENSSL_zalloc(sizeof(*cb)); + return cb; +} + +void ossl_indicator_set_callback_free(void *cb) +{ + OPENSSL_free(cb); +} + +static INDICATOR_CB *get_indicator_callback(OSSL_LIB_CTX *libctx) +{ + return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_INDICATOR_CB_INDEX); +} + +void OSSL_INDICATOR_set_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK *cb) +{ + INDICATOR_CB *icb = get_indicator_callback(libctx); + + if (icb != NULL) + icb->cb = cb; +} + +void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb) +{ + INDICATOR_CB *icb = get_indicator_callback(libctx); + + if (cb != NULL) + *cb = (icb != NULL ? icb->cb : NULL); +} diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 693e2913d5476..266423dda9551 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -32,6 +32,7 @@ #include "crypto/context.h" #ifndef FIPS_MODULE # include +# include #endif /* @@ -1934,6 +1935,7 @@ OSSL_FUNC_BIO_up_ref_fn ossl_core_bio_up_ref; OSSL_FUNC_BIO_free_fn ossl_core_bio_free; OSSL_FUNC_BIO_vprintf_fn ossl_core_bio_vprintf; OSSL_FUNC_BIO_vsnprintf_fn BIO_vsnprintf; +static OSSL_FUNC_indicator_cb_fn core_indicator_get_callback; static OSSL_FUNC_self_test_cb_fn core_self_test_get_callback; static OSSL_FUNC_get_entropy_fn rand_get_entropy; static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy; @@ -2097,6 +2099,12 @@ static int core_pop_error_to_mark(const OSSL_CORE_HANDLE *handle) return ERR_pop_to_mark(); } +static void core_indicator_get_callback(OPENSSL_CORE_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb) +{ + OSSL_INDICATOR_get_callback((OSSL_LIB_CTX *)libctx, cb); +} + static void core_self_test_get_callback(OPENSSL_CORE_CTX *libctx, OSSL_CALLBACK **cb, void **cbarg) { @@ -2258,6 +2266,7 @@ static const OSSL_DISPATCH core_dispatch_[] = { { OSSL_FUNC_BIO_VPRINTF, (void (*)(void))ossl_core_bio_vprintf }, { OSSL_FUNC_BIO_VSNPRINTF, (void (*)(void))BIO_vsnprintf }, { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))core_self_test_get_callback }, + { OSSL_FUNC_INDICATOR_CB, (void (*)(void))core_indicator_get_callback }, { OSSL_FUNC_GET_ENTROPY, (void (*)(void))rand_get_entropy }, { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy }, { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))rand_cleanup_entropy }, diff --git a/doc/build.info b/doc/build.info index b2689b7acebf1..5c24273b63f8c 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1747,6 +1747,10 @@ DEPEND[html/man3/OSSL_IETF_ATTR_SYNTAX_print.html]=man3/OSSL_IETF_ATTR_SYNTAX_pr GENERATE[html/man3/OSSL_IETF_ATTR_SYNTAX_print.html]=man3/OSSL_IETF_ATTR_SYNTAX_print.pod DEPEND[man/man3/OSSL_IETF_ATTR_SYNTAX_print.3]=man3/OSSL_IETF_ATTR_SYNTAX_print.pod GENERATE[man/man3/OSSL_IETF_ATTR_SYNTAX_print.3]=man3/OSSL_IETF_ATTR_SYNTAX_print.pod +DEPEND[html/man3/OSSL_INDICATOR_set_callback.html]=man3/OSSL_INDICATOR_set_callback.pod +GENERATE[html/man3/OSSL_INDICATOR_set_callback.html]=man3/OSSL_INDICATOR_set_callback.pod +DEPEND[man/man3/OSSL_INDICATOR_set_callback.3]=man3/OSSL_INDICATOR_set_callback.pod +GENERATE[man/man3/OSSL_INDICATOR_set_callback.3]=man3/OSSL_INDICATOR_set_callback.pod DEPEND[html/man3/OSSL_ITEM.html]=man3/OSSL_ITEM.pod GENERATE[html/man3/OSSL_ITEM.html]=man3/OSSL_ITEM.pod DEPEND[man/man3/OSSL_ITEM.3]=man3/OSSL_ITEM.pod @@ -3424,6 +3428,7 @@ html/man3/OSSL_HTTP_parse_url.html \ html/man3/OSSL_HTTP_transfer.html \ html/man3/OSSL_IETF_ATTR_SYNTAX.html \ html/man3/OSSL_IETF_ATTR_SYNTAX_print.html \ +html/man3/OSSL_INDICATOR_set_callback.html \ html/man3/OSSL_ITEM.html \ html/man3/OSSL_LIB_CTX.html \ html/man3/OSSL_LIB_CTX_set_conf_diagnostics.html \ @@ -4083,6 +4088,7 @@ man/man3/OSSL_HTTP_parse_url.3 \ man/man3/OSSL_HTTP_transfer.3 \ man/man3/OSSL_IETF_ATTR_SYNTAX.3 \ man/man3/OSSL_IETF_ATTR_SYNTAX_print.3 \ +man/man3/OSSL_INDICATOR_set_callback.3 \ man/man3/OSSL_ITEM.3 \ man/man3/OSSL_LIB_CTX.3 \ man/man3/OSSL_LIB_CTX_set_conf_diagnostics.3 \ diff --git a/doc/man3/OSSL_INDICATOR_set_callback.pod b/doc/man3/OSSL_INDICATOR_set_callback.pod new file mode 100644 index 0000000000000..34ead2bd3f1e1 --- /dev/null +++ b/doc/man3/OSSL_INDICATOR_set_callback.pod @@ -0,0 +1,81 @@ +=pod + +=head1 NAME + +OSSL_INDICATOR_set_callback, +OSSL_INDICATOR_get_callback - specify a callback for FIPS indicators + +=head1 SYNOPSIS + + #include + +typedef int (OSSL_INDICATOR_CALLBACK)(const char *type, const char *desc, + const OSSL_PARAM params[]); + + void OSSL_INDICATOR_set_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK *cb); + void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb); + +=head1 DESCRIPTION + +OSSL_INDICATOR_set_callback() sets a user callback I associated with a +I that will be called when a non approved FIPS operation is detected. + +The user's callback may be triggered multiple times during an algorithm operation +to indicate different approved mode checks have failed. + +Non approved operations may only occur if the user has deliberately chosen to do +so (either by setting a global FIPS configuration option or via an option in an +algorithm's operation context). + +The user's callback B I and I +contain the algorithm type and operation that is not approved. +I is not currently used. + +If the user callback returns 0, an error will occur in the caller. This can be +used for testing purposes. + +=head1 RETURN VALUES + +OSSL_INDICATOR_get_callback() returns the callback that has been set via +OSSL_INDICATOR_set_callback() for the given library context I, or NULL +if no callback is currently set. + +=head1 EXAMPLES + +A simple indicator callback to log non approved FIPS operations + + static int indicator_cb(const char *type, const char *desc, + const OSSL_PARAM params[]) + { + if (type != NULL && desc != NULL) + fprintf(stdout, "%s %s is not approved\n", type, desc); +end: + /* For Testing purposes you could return 0 here to cause an error */ + return 1; + } + + OSSL_INDICATOR_set_callback(libctx, indicator_cb); + + +=head1 SEE ALSO + +L, +L +L + +=head1 HISTORY + +The functions described here were added in OpenSSL 3.4. + +=head1 COPYRIGHT + +Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/crypto/context.h b/include/crypto/context.h index 7369a730fb812..8831fcb2a5edc 100644 --- a/include/crypto/context.h +++ b/include/crypto/context.h @@ -20,6 +20,7 @@ void *ossl_bio_core_globals_new(OSSL_LIB_CTX *); void *ossl_child_prov_ctx_new(OSSL_LIB_CTX *); void *ossl_prov_drbg_nonce_ctx_new(OSSL_LIB_CTX *); void *ossl_self_test_set_callback_new(OSSL_LIB_CTX *); +void *ossl_indicator_set_callback_new(OSSL_LIB_CTX *); void *ossl_rand_crng_ctx_new(OSSL_LIB_CTX *); int ossl_thread_register_fips(OSSL_LIB_CTX *); void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *); @@ -38,6 +39,7 @@ void ossl_prov_conf_ctx_free(void *); void ossl_bio_core_globals_free(void *); void ossl_child_prov_ctx_free(void *); void ossl_prov_drbg_nonce_ctx_free(void *); +void ossl_indicator_set_callback_free(void *cb); void ossl_self_test_set_callback_free(void *); void ossl_rand_crng_ctx_free(void *); void ossl_thread_event_ctx_free(void *); diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 1635830500c24..32caabad7e5b0 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -117,7 +117,8 @@ typedef struct ossl_ex_data_global_st { # define OSSL_LIB_CTX_THREAD_INDEX 19 # define OSSL_LIB_CTX_DECODER_CACHE_INDEX 20 # define OSSL_LIB_CTX_COMP_METHODS 21 -# define OSSL_LIB_CTX_MAX_INDEXES 21 +# define OSSL_LIB_CTX_INDICATOR_CB_INDEX 22 +# define OSSL_LIB_CTX_MAX_INDEXES 22 OSSL_LIB_CTX *ossl_lib_ctx_get_concrete(OSSL_LIB_CTX *ctx); int ossl_lib_ctx_is_default(OSSL_LIB_CTX *ctx); diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index a5bc2cf75d345..fa4de4954c124 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -13,6 +13,7 @@ # include # include +# include # ifdef __cplusplus extern "C" { @@ -182,6 +183,9 @@ OSSL_CORE_MAKE_FUNC(int, BIO_ctrl, (OSSL_CORE_BIO *bio, #define OSSL_FUNC_GET_USER_ENTROPY 98 #define OSSL_FUNC_GET_USER_NONCE 99 +#define OSSL_FUNC_INDICATOR_CB 95 +OSSL_CORE_MAKE_FUNC(void, indicator_cb, (OPENSSL_CORE_CTX *ctx, + OSSL_INDICATOR_CALLBACK **cb)) #define OSSL_FUNC_SELF_TEST_CB 100 OSSL_CORE_MAKE_FUNC(void, self_test_cb, (OPENSSL_CORE_CTX *ctx, OSSL_CALLBACK **cb, void **cbarg)) @@ -588,6 +592,7 @@ OSSL_CORE_MAKE_FUNC(void *, keymgmt_new, (void *provctx)) # define OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS 5 # define OSSL_FUNC_KEYMGMT_GEN 6 # define OSSL_FUNC_KEYMGMT_GEN_CLEANUP 7 + OSSL_CORE_MAKE_FUNC(void *, keymgmt_gen_init, (void *provctx, int selection, const OSSL_PARAM params[])) OSSL_CORE_MAKE_FUNC(int, keymgmt_gen_set_template, diff --git a/include/openssl/indicator.h b/include/openssl/indicator.h new file mode 100644 index 0000000000000..3ea0122188642 --- /dev/null +++ b/include/openssl/indicator.h @@ -0,0 +1,31 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OPENSSL_INDICATOR_H +# define OPENSSL_INDICATOR_H +# pragma once + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +typedef int (OSSL_INDICATOR_CALLBACK)(const char *type, const char *desc, + const OSSL_PARAM params[]); + +void OSSL_INDICATOR_set_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK *cb); +void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb); + +# ifdef __cplusplus +} +# endif +#endif /* OPENSSL_INDICATOR_H */ diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 0174c6b33b41d..bae56a8bbae4f 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -14,6 +14,7 @@ #include #include /* RAND_get0_public() */ #include +#include #include "internal/cryptlib.h" #include "prov/implementations.h" #include "prov/names.h" @@ -76,6 +77,7 @@ static OSSL_FUNC_CRYPTO_secure_clear_free_fn *c_CRYPTO_secure_clear_free; static OSSL_FUNC_CRYPTO_secure_allocated_fn *c_CRYPTO_secure_allocated; static OSSL_FUNC_BIO_vsnprintf_fn *c_BIO_vsnprintf; static OSSL_FUNC_self_test_cb_fn *c_stcbfn = NULL; +static OSSL_FUNC_indicator_cb_fn *c_indcbfn = NULL; static OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; typedef struct { @@ -689,6 +691,9 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, case OSSL_FUNC_SELF_TEST_CB: set_func(c_stcbfn, OSSL_FUNC_self_test_cb(in)); break; + case OSSL_FUNC_INDICATOR_CB: + set_func(c_indcbfn, OSSL_FUNC_indicator_cb(in)); + break; default: /* Just ignore anything we don't understand */ break; @@ -954,6 +959,7 @@ FIPS_FEATURE_CHECK(FIPS_security_check_enabled, fips_security_checks) FIPS_FEATURE_CHECK(FIPS_tls_prf_ems_check, fips_tls1_prf_ems_check) FIPS_FEATURE_CHECK(FIPS_restricted_drbg_digests_enabled, fips_restricted_drgb_digests) + #undef FIPS_FEATURE_CHECK void OSSL_SELF_TEST_get_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK **cb, @@ -971,3 +977,17 @@ void OSSL_SELF_TEST_get_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK **cb, *cbarg = NULL; } } + +void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb) +{ + assert(libctx != NULL); + + if (c_indcbfn != NULL && c_get_libctx != NULL) { + /* Get the parent libctx */ + c_indcbfn(c_get_libctx(FIPS_get_core_handle(libctx)), cb); + } else { + if (cb != NULL) + *cb = NULL; + } +} From d4848934a61a668d16078f3118786c9a741b7efd Mon Sep 17 00:00:00 2001 From: slontis Date: Mon, 1 Jul 2024 11:27:58 +1000 Subject: [PATCH 136/138] Add FIPS indicator helpers Each provider algorithm context can use these helpers to add indicator support. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24623) --- providers/common/include/prov/fipsindicator.h | 130 ++++++++++++++++++ providers/fips/build.info | 2 +- providers/fips/fipsindicator.c | 113 +++++++++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 providers/common/include/prov/fipsindicator.h create mode 100644 providers/fips/fipsindicator.c diff --git a/providers/common/include/prov/fipsindicator.h b/providers/common/include/prov/fipsindicator.h new file mode 100644 index 0000000000000..fbfa7e0790d02 --- /dev/null +++ b/providers/common/include/prov/fipsindicator.h @@ -0,0 +1,130 @@ +/* + * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifdef FIPS_MODULE + +# include /* OSSL_CALLBACK, OSSL_LIB_CTX */ +# include +# include "crypto/types.h" +# include + +/* + * There may be multiple settables associated with an algorithm that allow + * overriding the default status. + * We associate an id with each of these. + */ +# define OSSL_FIPS_IND_SETTABLE0 0 +# define OSSL_FIPS_IND_SETTABLE1 1 +# define OSSL_FIPS_IND_SETTABLE2 2 +# define OSSL_FIPS_IND_SETTABLE3 2 +# define OSSL_FIPS_IND_SETTABLE4 2 +# define OSSL_FIPS_IND_SETTABLE5 2 +# define OSSL_FIPS_IND_SETTABLE6 2 +# define OSSL_FIPS_IND_SETTABLE7 2 +# define OSSL_FIPS_IND_SETTABLE_MAX (1 + OSSL_FIPS_IND_SETTABLE7) + +/* Each settable is in one of 3 states */ +#define OSSL_FIPS_IND_STATE_UNKNOWN -1 /* Initial unknown state */ +#define OSSL_FIPS_IND_STATE_STRICT 1 /* Strict enforcement */ +#define OSSL_FIPS_IND_STATE_TOLERANT 0 /* Relaxation of rules */ + +/* + * For each algorithm context there may be multiple checks that determine if + * the algorithm is approved or not. These checks may be in different stages. + * To keep it simple it is assumed that the algorithm is initially approved, + * and may be unapproved when each check happens. Once unapproved the operation + * will remain unapproved (otherwise we need to maintain state for each check). + * The approved state should only be queried after the operation has completed + * e.g. A digest final, or a KDF derive. + * + * If a FIPS approved check fails then we must decide what to do in this case. + * In strict mode we would just return an error. + * To override strict mode we either need to have a settable variable or have a + * fips config flag that overrides strict mode. + * If there are multiple checks, each one could possible have a different + * configurable item. Each configurable item can be overriden by a different + * settable. + */ +typedef struct ossl_fips_ind_st { + unsigned int approved; + int settable[OSSL_FIPS_IND_SETTABLE_MAX]; /* See OSSL_FIPS_IND_STATE */ +} OSSL_FIPS_IND; + +typedef int (OSSL_FIPS_IND_CHECK_CB)(OSSL_LIB_CTX *libctx); + +int ossl_FIPS_IND_callback(OSSL_LIB_CTX *libctx, const char *type, + const char *desc); + +void ossl_FIPS_IND_init(OSSL_FIPS_IND *ind); +void ossl_FIPS_IND_set_approved(OSSL_FIPS_IND *ind); +void ossl_FIPS_IND_set_settable(OSSL_FIPS_IND *ind, int id, int enable); +int ossl_FIPS_IND_get_settable(const OSSL_FIPS_IND *ind, int id); +int ossl_FIPS_IND_on_unapproved(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, + const char *algname, const char *opname, + OSSL_FIPS_IND_CHECK_CB *config_check_fn); +int ossl_FIPS_IND_set_ctx_param(OSSL_FIPS_IND *ind, int id, + const OSSL_PARAM params[], const char *name); +int ossl_FIPS_IND_get_ctx_param(const OSSL_FIPS_IND *ind, + OSSL_PARAM params[]); +void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src); + +/* Place this in the algorithm ctx structure */ +# define OSSL_FIPS_IND_DECLARE OSSL_FIPS_IND indicator; +/* Call this to initialize the indicator */ +# define OSSL_FIPS_IND_INIT(ctx) ossl_FIPS_IND_init(&ctx->indicator); +/* + * Use the copy if an algorithm has a dup function that does not copy the src to + * the dst. + */ +# define OSSL_FIPS_IND_COPY(dst, src) ossl_FIPS_IND_copy(&dst->indicator, &src->indicator); + +/* + * Required for reset - since once something becomes unapproved it will remain + * unapproved unless this is used. This should be used in the init before + * params are set into the ctx & before any FIPS checks are done. + */ +# define OSSL_FIPS_IND_SET_APPROVED(ctx) ossl_FIPS_IND_set_approved(&ctx->indicator); +/* + * This should be called if a FIPS check fails, to indicate the operation is not approved + * If there is more than 1 strict check flag per algorithm ctx, the id represents + * the index. + */ +# define OSSL_FIPS_IND_ON_UNAPPROVED(ctx, id, libctx, algname, opname, config_check_fn) \ + ossl_FIPS_IND_on_unapproved(&ctx->indicator, id, libctx, algname, opname, config_check_fn) + +# define OSSL_FIPS_IND_SETTABLE_CTX_PARAM(name) \ + OSSL_PARAM_int(name, NULL), + +/* + * The id here must match the one used by OSSL_FIPS_IND_ON_UNAPPROVED + * The name must match the param used by OSSL_FIPS_IND_SETTABLE_CTX_PARAM + */ +# define OSSL_FIPS_IND_SET_CTX_PARAM(ctx, id, params, name) \ + ossl_FIPS_IND_set_ctx_param(&((ctx)->indicator), id, params, name) + +# define OSSL_FIPS_IND_GETTABLE_CTX_PARAM() \ + OSSL_PARAM_int(OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR, NULL), + +# define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, prms) \ + ossl_FIPS_IND_get_ctx_param(&((ctx)->indicator), prms) + +#define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator) + +#else +# define OSSL_FIPS_IND_DECLARE +# define OSSL_FIPS_IND_INIT(ctx) +# define OSSL_FIPS_IND_SET_APPROVED(ctx) +# define OSSL_FIPS_IND_ON_UNAPPROVED(ctx, id, libctx, algname, opname, configopt_fn) +# define OSSL_FIPS_IND_SETTABLE_CTX_PARAM(name) +# define OSSL_FIPS_IND_SET_CTX_PARAM(ctx, id, params, name) 1 +# define OSSL_FIPS_IND_GETTABLE_CTX_PARAM() +# define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params) 1 +# define OSSL_FIPS_IND_COPY(dst, src) + +#endif diff --git a/providers/fips/build.info b/providers/fips/build.info index 2bfc58501e941..9756ad3f792d1 100644 --- a/providers/fips/build.info +++ b/providers/fips/build.info @@ -1,6 +1,6 @@ # We include the provider implementation into ../libfips.a, so that all # platforms can resolve symbols in other members of that library. -SOURCE[../libfips.a]=fipsprov.c self_test.c self_test_kats.c +SOURCE[../libfips.a]=fipsprov.c self_test.c self_test_kats.c fipsindicator.c # It is necessary to have an explicit entry point SOURCE[../fips]=fips_entry.c diff --git a/providers/fips/fipsindicator.c b/providers/fips/fipsindicator.c new file mode 100644 index 0000000000000..9956c19884bec --- /dev/null +++ b/providers/fips/fipsindicator.c @@ -0,0 +1,113 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "prov/fipsindicator.h" +#include "internal/common.h" /* for ossl_assert() */ + +void ossl_FIPS_IND_init(OSSL_FIPS_IND *ind) +{ + ossl_FIPS_IND_set_approved(ind); /* Assume we are approved by default */ + memset(ind->settable, OSSL_FIPS_IND_STATE_UNKNOWN, sizeof(ind->settable)); +} + +void ossl_FIPS_IND_set_approved(OSSL_FIPS_IND *ind) +{ + ind->approved = 1; +} + +void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src) +{ + *dst = *src; +} + +void ossl_FIPS_IND_set_settable(OSSL_FIPS_IND *ind, int id, int state) +{ + if (!ossl_assert(id < OSSL_FIPS_IND_SETTABLE_MAX)) + return; + if (!ossl_assert(state == OSSL_FIPS_IND_STATE_STRICT + || state == OSSL_FIPS_IND_STATE_TOLERANT)) + return; + ind->settable[id] = state; +} + +int ossl_FIPS_IND_get_settable(const OSSL_FIPS_IND *ind, int id) +{ + if (!ossl_assert(id < OSSL_FIPS_IND_SETTABLE_MAX)) + return OSSL_FIPS_IND_STATE_UNKNOWN; + return ind->settable[id]; +} + +/* + * This should only be called when a strict FIPS algorithm check fails. + * It assumes that we are in strict mode by default. + * If the logic here is not sufficient for all cases, then additional + * ossl_FIPS_IND_on_unapproved() functions may be required. + */ +int ossl_FIPS_IND_on_unapproved(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + const char *algname, const char *opname, + OSSL_FIPS_IND_CHECK_CB *config_check_fn) +{ + /* Set to unapproved. Once unapproved mode is set this will not be reset */ + ind->approved = 0; + + /* + * We only trigger the indicator callback if the ctx variable is cleared OR + * the configurable item is cleared. If the values are unknown they are + * assumed to be strict. + */ + if (ossl_FIPS_IND_get_settable(ind, id) == OSSL_FIPS_IND_STATE_TOLERANT + || (config_check_fn != NULL + && config_check_fn(libctx) == OSSL_FIPS_IND_STATE_TOLERANT)) { + return ossl_FIPS_IND_callback(libctx, algname, opname); + } + /* Strict mode gets here: This returns an error */ + return 0; +} + +int ossl_FIPS_IND_set_ctx_param(OSSL_FIPS_IND *ind, int id, + const OSSL_PARAM params[], const char *name) +{ + int in = 0; + const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, name); + + if (p != NULL) { + if (!OSSL_PARAM_get_int(p, &in)) + return 0; + ossl_FIPS_IND_set_settable(ind, id, in); + } + return 1; +} + +int ossl_FIPS_IND_get_ctx_param(const OSSL_FIPS_IND *ind, OSSL_PARAM params[]) +{ + OSSL_PARAM *p = OSSL_PARAM_locate(params, OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR); + + return p == NULL || OSSL_PARAM_set_int(p, ind->approved); +} + +/* + * Can be used during application testing to log that an indicator was + * triggered. The callback will return 1 if the application wants an error + * to occur based on the indicator type and description. + */ +int ossl_FIPS_IND_callback(OSSL_LIB_CTX *libctx, const char *type, + const char *desc) +{ + OSSL_INDICATOR_CALLBACK *cb = NULL; + + OSSL_INDICATOR_get_callback(libctx, &cb); + if (cb == NULL) + return 1; + + return cb(type, desc, NULL); +} From c13ddf0a6c71efac8ef546f0d3632341afab3f07 Mon Sep 17 00:00:00 2001 From: slontis Date: Mon, 1 Jul 2024 11:36:58 +1000 Subject: [PATCH 137/138] Change all existing FIPS configurable checks to use FIPS indicators. This changes the logic to always do the security checks and then decide what to do based on if this passes or not. Failure of a check causes either a failure OR the FIPS indicator callback to be triggered. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24623) --- doc/man7/EVP_ASYM_CIPHER-RSA.pod | 4 + doc/man7/EVP_KDF-TLS1_PRF.pod | 16 ++ doc/man7/EVP_KEM-RSA.pod | 7 +- doc/man7/EVP_KEYEXCH-DH.pod | 14 +- doc/man7/EVP_KEYEXCH-ECDH.pod | 14 +- doc/man7/EVP_SIGNATURE-DSA.pod | 9 +- doc/man7/EVP_SIGNATURE-ECDSA.pod | 6 + doc/man7/EVP_SIGNATURE-RSA.pod | 11 +- doc/man7/provider-asym_cipher.pod | 19 ++ doc/man7/provider-kem.pod | 31 ++- doc/man7/provider-keyexch.pod | 28 ++ doc/man7/provider-rand.pod | 18 ++ doc/man7/provider-signature.pod | 30 ++- providers/common/include/prov/fipsindicator.h | 14 + providers/common/include/prov/securitycheck.h | 24 +- providers/common/securitycheck.c | 250 +++++++----------- providers/common/securitycheck_default.c | 5 +- providers/common/securitycheck_fips.c | 91 ++++++- .../implementations/asymciphers/rsa_enc.c | 37 ++- providers/implementations/exchange/dh_exch.c | 55 +++- .../implementations/exchange/ecdh_exch.c | 49 +++- providers/implementations/kdfs/tls1_prf.c | 67 +++-- providers/implementations/kem/rsa_kem.c | 40 ++- providers/implementations/rands/drbg.c | 37 ++- providers/implementations/rands/drbg_ctr.c | 2 + providers/implementations/rands/drbg_hash.c | 10 +- providers/implementations/rands/drbg_hmac.c | 10 +- providers/implementations/rands/drbg_local.h | 5 +- providers/implementations/signature/dsa_sig.c | 100 +++++-- .../implementations/signature/ecdsa_sig.c | 82 ++++-- providers/implementations/signature/rsa_sig.c | 122 ++++++--- util/perl/OpenSSL/paramnames.pm | 17 ++ 32 files changed, 882 insertions(+), 342 deletions(-) diff --git a/doc/man7/EVP_ASYM_CIPHER-RSA.pod b/doc/man7/EVP_ASYM_CIPHER-RSA.pod index c68cad6c42f9e..b36927082dc28 100644 --- a/doc/man7/EVP_ASYM_CIPHER-RSA.pod +++ b/doc/man7/EVP_ASYM_CIPHER-RSA.pod @@ -57,6 +57,10 @@ See L for further details. =item "oaep-label" (B) +=item "fips-indicator" (B) + +=item "key-check" (B) + =item "tls-client-version" (B) See B on the page L. diff --git a/doc/man7/EVP_KDF-TLS1_PRF.pod b/doc/man7/EVP_KDF-TLS1_PRF.pod index 8a60e97315549..1c0bf750badd7 100644 --- a/doc/man7/EVP_KDF-TLS1_PRF.pod +++ b/doc/man7/EVP_KDF-TLS1_PRF.pod @@ -44,6 +44,22 @@ This parameter sets the context seed. The length of the context seed cannot exceed 1024 bytes; this should be more than enough for any normal use of the TLS PRF. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling EVP_KDF_derive. It returns 0 if the "ems_check" +is set to 0 and the "extended master secret" test fails. +This option is used by the OpenSSL FIPS provider. + +=item "ems_check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +"master secret" is used instead of "extended master secret" Setting this to zero +will ignore the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + + =back =head1 NOTES diff --git a/doc/man7/EVP_KEM-RSA.pod b/doc/man7/EVP_KEM-RSA.pod index 3a89f5db39a3d..2733be6a6cb4a 100644 --- a/doc/man7/EVP_KEM-RSA.pod +++ b/doc/man7/EVP_KEM-RSA.pod @@ -31,8 +31,13 @@ The decapsulate function recovers the secret using the RSA private key. This can be set using EVP_PKEY_CTX_set_kem_op(). -=back +=item "fips-indicator" (B) + +=item "key-check" (B) +These parameters are described in L. + +=back =head1 CONFORMING TO diff --git a/doc/man7/EVP_KEYEXCH-DH.pod b/doc/man7/EVP_KEYEXCH-DH.pod index a6927afefb24e..1ccc469318274 100644 --- a/doc/man7/EVP_KEYEXCH-DH.pod +++ b/doc/man7/EVP_KEYEXCH-DH.pod @@ -28,22 +28,20 @@ the KDF type is set to "X942KDF-ASN1" (B). =item "kdf-type" (B) -See L. - =item "kdf-digest" (B) -See L. - =item "kdf-digest-props" (B) -See L. - =item "kdf-outlen" (B) -See L. - =item "kdf-ukm" (B) +=item "fips-indicator" (B) + +=item "key-check" (B) + +=item "digest-check" (B) + See L. =item "cekalg" (B) diff --git a/doc/man7/EVP_KEYEXCH-ECDH.pod b/doc/man7/EVP_KEYEXCH-ECDH.pod index f9579dab2f2eb..28e8d2a7608aa 100644 --- a/doc/man7/EVP_KEYEXCH-ECDH.pod +++ b/doc/man7/EVP_KEYEXCH-ECDH.pod @@ -33,22 +33,20 @@ per-key basis. =item "kdf-type" (B) -See L. - =item "kdf-digest" (B) -See L. - =item "kdf-digest-props" (B) -See L. - =item "kdf-outlen" (B) -See L. - =item "kdf-ukm" (B) +=item "fips-indicator" (B) + +=item "key-check" (B) + +=item "digest-check" (B) + See L. =back diff --git a/doc/man7/EVP_SIGNATURE-DSA.pod b/doc/man7/EVP_SIGNATURE-DSA.pod index 290041a2dd66e..2e761cb6679e7 100644 --- a/doc/man7/EVP_SIGNATURE-DSA.pod +++ b/doc/man7/EVP_SIGNATURE-DSA.pod @@ -14,7 +14,8 @@ See L for information related to DSA keys. The following signature parameters can be set using EVP_PKEY_CTX_set_params(). This may be called after EVP_PKEY_sign_init() or EVP_PKEY_verify_init(), -and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). +and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). They may also be set +using EVP_PKEY_sign_init_ex() or EVP_PKEY_verify_init_ex(). =over 4 @@ -24,6 +25,10 @@ and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). =item "nonce-type" (B) +=item "key-check" (B) + +=item "digest-check" (B) + The settable parameters are described in L. =back @@ -39,6 +44,8 @@ EVP_PKEY_CTX_get_params(). =item "nonce-type" (B) +=item "fips-indicator" (B) + The gettable parameters are described in L. =back diff --git a/doc/man7/EVP_SIGNATURE-ECDSA.pod b/doc/man7/EVP_SIGNATURE-ECDSA.pod index a19d467c0d758..4d47b8c9bfce4 100644 --- a/doc/man7/EVP_SIGNATURE-ECDSA.pod +++ b/doc/man7/EVP_SIGNATURE-ECDSA.pod @@ -23,6 +23,10 @@ and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). =item "nonce-type" (B) +=item "key-check" (B) + +=item "digest-check" (B) + These parameters are described in L. =back @@ -38,6 +42,8 @@ EVP_PKEY_CTX_get_params(). =item "nonce-type" (B) +=item "fips-indicator" (B) + The parameters are described in L. =back diff --git a/doc/man7/EVP_SIGNATURE-RSA.pod b/doc/man7/EVP_SIGNATURE-RSA.pod index de6869786c9d5..9398e77019cc4 100644 --- a/doc/man7/EVP_SIGNATURE-RSA.pod +++ b/doc/man7/EVP_SIGNATURE-RSA.pod @@ -14,7 +14,8 @@ See L for information related to RSA keys. The following signature parameters can be set using EVP_PKEY_CTX_set_params(). This may be called after EVP_PKEY_sign_init() or EVP_PKEY_verify_init(), -and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). +and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). They may also be set +using EVP_PKEY_sign_init_ex() or EVP_PKEY_verify_init_ex(). =over 4 @@ -22,6 +23,10 @@ and before calling EVP_PKEY_sign() or EVP_PKEY_verify(). =item "properties" (B) +=item "key-check" (B) + +=item "digest-check" (B) + These common parameters are described in L. =item "pad-mode" (B) @@ -84,7 +89,9 @@ EVP_PKEY_CTX_get_params(). =item "algorithm-id" (B) -This common parameter is described in L. +=item "fips-indicator" (B) + +These common parameter are described in L. =item "digest" (B) diff --git a/doc/man7/provider-asym_cipher.pod b/doc/man7/provider-asym_cipher.pod index 24fe160bf751f..9602367da8e27 100644 --- a/doc/man7/provider-asym_cipher.pod +++ b/doc/man7/provider-asym_cipher.pod @@ -243,6 +243,23 @@ This makes exploitation of the Bleichenbacher significantly harder, even if the code using the RSA decryption API is not implemented in side-channel free manner. Set by default. Requires provider support. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling either OSSL_FUNC_asym_cipher_encrypt() or +OSSL_FUNC_asym_cipher_decrypt(). It may return 0 if "key-check" is set to 0. +This option is used by the OpenSSL FIPS provider. + +=item "key-check" (B) + +If required this parameter should be set using either +OSSL_FUNC_asym_cipher_encrypt_init() or OSSL_FUNC_asym_cipher_decrypt_init(). +The default value of 1 causes an error during the init if the key is not FIPS +approved (e.g. The key has a security strength of less than 112 bits). Setting +this to 0 will ignore the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + =back OSSL_FUNC_asym_cipher_gettable_ctx_params() and OSSL_FUNC_asym_cipher_settable_ctx_params() @@ -264,6 +281,8 @@ L =head1 HISTORY The provider ASYM_CIPHER interface was introduced in OpenSSL 3.0. +The Asymmetric Cipher Parameters "fips-indicator" and "key-check" +were added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man7/provider-kem.pod b/doc/man7/provider-kem.pod index 970105a269a57..eb04beb4291f0 100644 --- a/doc/man7/provider-kem.pod +++ b/doc/man7/provider-kem.pod @@ -186,12 +186,36 @@ See L for further details on the parameters structure used by the OSSL_FUNC_kem_get_ctx_params() and OSSL_FUNC_kem_set_ctx_params() functions. -OSSL_FUNC_kem_get_ctx_params() gets asymmetric kem parameters associated +Common parameters currently recognised by built-in key encapsulation algorithms +are as follows. + +=over 4 + +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling either OSSL_FUNC_kem_encapsulate() or +OSSL_FUNC_kem_decapsulate(). It may return 0 if the "key-check" is set to 0. +This option is used by the OpenSSL FIPS provider. + +=item "key-check" (B) + +If required this parameter should be set using OSSL_FUNC_kem_encapsulate_init() +or OSSL_FUNC_kem_decapsulate_init(). +The default value of 1 causes an error during the init if the key is not FIPS +approved (e.g. The key has a security strength of less than 112 bits). Setting +this to 0 will ignore the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +=back + +OSSL_FUNC_kem_get_ctx_params() gets asymmetric KEM parameters associated with the given provider side asymmetric kem context I and stores them in I. Passing NULL for I should return true. -OSSL_FUNC_kem_set_ctx_params() sets the asymmetric kem parameters associated +OSSL_FUNC_kem_set_ctx_params() sets the asymmetric KEM parameters associated with the given provider side asymmetric kem context I to I. Any parameter settings are additional to any that were previously set. Passing NULL for I should return true. @@ -221,6 +245,9 @@ The provider KEM interface was introduced in OpenSSL 3.0. OSSL_FUNC_kem_auth_encapsulate_init() and OSSL_FUNC_kem_auth_decapsulate_init() were added in OpenSSL 3.2. +The Asymmetric Key Encapsulation Parameters "fips-indicator" and "key-check" +were added in OpenSSL 3.4. + =head1 COPYRIGHT Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man7/provider-keyexch.pod b/doc/man7/provider-keyexch.pod index 9e146d31c719b..702bfb01f6b64 100644 --- a/doc/man7/provider-keyexch.pod +++ b/doc/man7/provider-keyexch.pod @@ -204,6 +204,31 @@ usually do not need to support this gettable parameter as its sole purpose is to support functionality of the deprecated EVP_PKEY_CTX_get0_ecdh_kdf_ukm() and EVP_PKEY_CTX_get0_dh_kdf_ukm() functions. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling OSSL_FUNC_keyexch_derive(). It may +return 0 if either the "digest-check" or the "key-check" are set to 0. +This option is used by the OpenSSL FIPS provider. + +=item "key-check" (B) + +If required this parameter should be set using OSSL_FUNC_keyexch_init(). +The default value of 1 causes an error during the init if the key is not FIPS +approved (e.g. The key has a security strength of less than 112 bits). Setting +this to 0 will ignore the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +=item "digest-check" (B) + +If required this parameter should be set before any optional digest is set. +The default value of 1 causes an error when the digest is set if the digest is +not FIPS approved. Setting this to 0 will ignore the error and set the +approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + =back =head1 RETURN VALUES @@ -226,6 +251,9 @@ L The provider KEYEXCH interface was introduced in OpenSSL 3.0. +The Key Exchange Parameters "fips-indicator", "key-check" and "digest-check" +were added in OpenSSL 3.4. + =head1 COPYRIGHT Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man7/provider-rand.pod b/doc/man7/provider-rand.pod index e115d845dcd90..aa1df965f65a5 100644 --- a/doc/man7/provider-rand.pod +++ b/doc/man7/provider-rand.pod @@ -254,6 +254,22 @@ Sets the properties to be queried when trying to fetch an underlying algorithm. This must be given together with the algorithm naming parameter to be considered valid. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling OSSL_FUNC_rand_generate(). It may +return 0 if the "digest-check" is set to 0. +This option is used by the OpenSSL FIPS provider. + +=item "digest-check" (B) + +If required this parameter should be set before the digest is set. +The default value of 1 causes an error when the digest is set if the digest is +not FIPS approved (e.g. truncated digests). Setting this to 0 will ignore +the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + =back =head1 RETURN VALUES @@ -289,6 +305,8 @@ L =head1 HISTORY The provider RAND interface was introduced in OpenSSL 3.0. +The Rand Parameters "fips-indicator" and "digest-check" were added in +OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man7/provider-signature.pod b/doc/man7/provider-signature.pod index b26b8b6a5b4cf..7763112d06e72 100644 --- a/doc/man7/provider-signature.pod +++ b/doc/man7/provider-signature.pod @@ -257,7 +257,7 @@ the I parameter. =head2 Digest Sign Functions -OSSL_FUNC_signature_digeset_sign_init() initialises a context for signing given a +OSSL_FUNC_signature_digest_sign_init() initialises a context for signing given a provider side signature context in the I parameter, and a pointer to a provider key object in the I parameter. The I, if not NULL, should be set on the context in a manner similar to @@ -388,6 +388,32 @@ was successful. Known answer tests can be performed if the random generator is overridden to supply known values that either pass or fail. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling either the sign or verify final functions. It may +return 0 if either the "digest-check" or the "key-check" are set to 0. +This option is used by the OpenSSL FIPS provider. + +=item "key-check" (B) + +If required this parameter should be set early via an init function +(e.g. OSSL_FUNC_signature_sign_init() or OSSL_FUNC_signature_verify_init()). +The default value of 1 causes an error during the init if the key is not FIPS +approved (e.g. The key has a security strength of less than 112 bits). +Setting this to 0 will ignore the error and set the approved "indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +=item "digest-check" (B) + +If required this parameter should be set before the signature digest is set. +The default value of 1 causes an error when the digest is set if the digest is +not FIPS approved (e.g. SHA1 is used for signing). Setting this to 0 will ignore +the error and set the approved "fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + =back OSSL_FUNC_signature_gettable_ctx_params() and OSSL_FUNC_signature_settable_ctx_params() get a @@ -438,6 +464,8 @@ L =head1 HISTORY The provider SIGNATURE interface was introduced in OpenSSL 3.0. +The Signature Parameters "fips-indicator", "key-check" and "digest-check" +were added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/providers/common/include/prov/fipsindicator.h b/providers/common/include/prov/fipsindicator.h index fbfa7e0790d02..0b6c52ed8cbfb 100644 --- a/providers/common/include/prov/fipsindicator.h +++ b/providers/common/include/prov/fipsindicator.h @@ -116,6 +116,20 @@ void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src); #define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator) +int ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, + const RSA *rsa, const char *desc, int protect); +# ifndef OPENSSL_NO_EC +int ossl_fips_ind_ec_key_check(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, + const EC_GROUP *group, const char *desc, + int protect); +# endif +int ossl_fips_ind_digest_check(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, + const EVP_MD *md, const char *desc); +int ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + int nid, int sha1_allowed, + const char *desc); + #else # define OSSL_FIPS_IND_DECLARE # define OSSL_FIPS_IND_INIT(ctx) diff --git a/providers/common/include/prov/securitycheck.h b/providers/common/include/prov/securitycheck.h index 611c6d531b136..4db5202c5931b 100644 --- a/providers/common/include/prov/securitycheck.h +++ b/providers/common/include/prov/securitycheck.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -8,24 +8,24 @@ */ #include "crypto/types.h" +#include /* Functions that are common */ -int ossl_rsa_check_key(OSSL_LIB_CTX *ctx, const RSA *rsa, int operation); -int ossl_ec_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect); -int ossl_dsa_check_key(OSSL_LIB_CTX *ctx, const DSA *dsa, int sign); -int ossl_dh_check_key(OSSL_LIB_CTX *ctx, const DH *dh); +int ossl_rsa_key_op_get_protect(const RSA *rsa, int operation, int *outprotect); +int ossl_rsa_check_key_size(const RSA *rsa, int protect); -int ossl_digest_is_allowed(OSSL_LIB_CTX *ctx, const EVP_MD *md); -/* With security check enabled it can return -1 to indicate disallowed md */ -int ossl_digest_get_approved_nid_with_sha1(OSSL_LIB_CTX *ctx, const EVP_MD *md, - int sha1_allowed); +#ifndef OPENSSL_NO_EC +int ossl_ec_check_curve_allowed(const EC_GROUP *group); +int ossl_ec_check_security_strength(const EC_GROUP *group, int protect); +#endif + +int ossl_dsa_check_key(const DSA *dsa, int sign); +int ossl_dh_check_key(const DH *dh); -/* Functions that are common */ int ossl_digest_md_to_nid(const EVP_MD *md, const OSSL_ITEM *it, size_t it_len); int ossl_digest_get_approved_nid(const EVP_MD *md); /* Functions that have different implementations for the FIPS_MODULE */ -int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, - int sha1_allowed); +int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md); int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx); int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx); diff --git a/providers/common/securitycheck.c b/providers/common/securitycheck.c index 0d3acdbe56e2f..e8e1c2400a5a6 100644 --- a/providers/common/securitycheck.c +++ b/providers/common/securitycheck.c @@ -19,14 +19,9 @@ #include #include #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" -/* - * FIPS requires a minimum security strength of 112 bits (for encryption or - * signing), and for legacy purposes 80 bits (for decryption or verifying). - * Set protect = 1 for encryption or signing operations, or 0 otherwise. See - * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf. - */ -int ossl_rsa_check_key(OSSL_LIB_CTX *ctx, const RSA *rsa, int operation) +int ossl_rsa_key_op_get_protect(const RSA *rsa, int operation, int *outprotect) { int protect = 0; @@ -56,25 +51,42 @@ int ossl_rsa_check_key(OSSL_LIB_CTX *ctx, const RSA *rsa, int operation) "invalid operation: %d", operation); return 0; } + *outprotect = protect; + return 1; +} -#if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) { - int sz = RSA_bits(rsa); +/* + * FIPS requires a minimum security strength of 112 bits (for encryption or + * signing), and for legacy purposes 80 bits (for decryption or verifying). + * Set protect = 1 for encryption or signing operations, or 0 otherwise. See + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf. + */ +int ossl_rsa_check_key_size(const RSA *rsa, int protect) +{ + int sz = RSA_bits(rsa); - if (protect ? (sz < 2048) : (sz < 1024)) { - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH, - "operation: %d", operation); - return 0; - } - } -#else - /* make protect used */ - (void)protect; -#endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ + if (protect ? (sz < 2048) : (sz < 1024)) + return 0; return 1; } #ifndef OPENSSL_NO_EC + +int ossl_ec_check_curve_allowed(const EC_GROUP *group) +{ + const char *curve_name; + int nid = EC_GROUP_get_curve_name(group); + + /* Explict curves are not FIPS approved */ + if (nid == NID_undef) + return 0; + /* Only NIST curves are FIPS approved */ + curve_name = EC_curve_nid2nist(nid); + if (curve_name == NULL) + return 0; + return 1; +} + /* * In FIPS mode: * protect should be 1 for any operations that need 112 bits of security @@ -89,56 +101,25 @@ int ossl_rsa_check_key(OSSL_LIB_CTX *ctx, const RSA *rsa, int operation) * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf * "Table 2" */ -int ossl_ec_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect) +int ossl_ec_check_security_strength(const EC_GROUP *group, int protect) { -# if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) { - int nid, strength; - const char *curve_name; - const EC_GROUP *group = EC_KEY_get0_group(ec); - - if (group == NULL) { - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_CURVE, "No group"); - return 0; - } - nid = EC_GROUP_get_curve_name(group); - if (nid == NID_undef) { - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_CURVE, - "Explicit curves are not allowed in fips mode"); - return 0; - } - - curve_name = EC_curve_nid2nist(nid); - if (curve_name == NULL) { - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_CURVE, - "Curve %s is not approved in FIPS mode", curve_name); - return 0; - } - - /* - * For EC the security strength is the (order_bits / 2) - * e.g. P-224 is 112 bits. - */ - strength = EC_GROUP_order_bits(group) / 2; - /* The min security strength allowed for legacy verification is 80 bits */ - if (strength < 80) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); - return 0; - } - - /* - * For signing or key agreement only allow curves with at least 112 bits of - * security strength - */ - if (protect && strength < 112) { - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_CURVE, - "Curve %s cannot be used for signing", curve_name); - return 0; - } - } -# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ + /* + * For EC the security strength is the (order_bits / 2) + * e.g. P-224 is 112 bits. + */ + int strength = EC_GROUP_order_bits(group) / 2; + /* The min security strength allowed for legacy verification is 80 bits */ + if (strength < 80) + return 0; + /* + * For signing or key agreement only allow curves with at least 112 bits of + * security strength + */ + if (protect && strength < 112) + return 0; return 1; } + #endif /* OPENSSL_NO_EC */ #ifndef OPENSSL_NO_DSA @@ -147,48 +128,43 @@ int ossl_ec_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect) * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf * "Table 2" */ -int ossl_dsa_check_key(OSSL_LIB_CTX *ctx, const DSA *dsa, int sign) +int ossl_dsa_check_key(const DSA *dsa, int sign) { -# if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) { - size_t L, N; - const BIGNUM *p, *q; - - if (dsa == NULL) - return 0; - - p = DSA_get0_p(dsa); - q = DSA_get0_q(dsa); - if (p == NULL || q == NULL) + size_t L, N; + const BIGNUM *p, *q; + + if (dsa == NULL) + return 0; + + p = DSA_get0_p(dsa); + q = DSA_get0_q(dsa); + if (p == NULL || q == NULL) + return 0; + + L = BN_num_bits(p); + N = BN_num_bits(q); + + /* + * For Digital signature verification DSA keys with < 112 bits of + * security strength, are still allowed for legacy + * use. The bounds given in SP 800-131Ar2 - Table 2 are + * (512 <= L < 2048 or 160 <= N < 224). + * + * We are a little stricter and insist that both minimums are met. + * For example a L = 256, N = 160 key *would* be allowed by SP 800-131Ar2 + * but we don't. + */ + if (!sign) { + if (L < 512 || N < 160) return 0; - - L = BN_num_bits(p); - N = BN_num_bits(q); - - /* - * For Digital signature verification DSA keys with < 112 bits of - * security strength, are still allowed for legacy - * use. The bounds given in SP 800-131Ar2 - Table 2 are - * (512 <= L < 2048 or 160 <= N < 224). - * - * We are a little stricter and insist that both minimums are met. - * For example a L = 256, N = 160 key *would* be allowed by SP 800-131Ar2 - * but we don't. - */ - if (!sign) { - if (L < 512 || N < 160) - return 0; - if (L < 2048 || N < 224) - return 1; - } - - /* Valid sizes for both sign and verify */ - if (L == 2048 && (N == 224 || N == 256)) /* 112 bits */ + if (L < 2048 || N < 224) return 1; - return (L == 3072 && N == 256); /* 128 bits */ } -# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ - return 1; + + /* Valid sizes for both sign and verify */ + if (L == 2048 && (N == 224 || N == 256)) /* 112 bits */ + return 1; + return (L == 3072 && N == 256); /* 128 bits */ } #endif /* OPENSSL_NO_DSA */ @@ -199,58 +175,30 @@ int ossl_dsa_check_key(OSSL_LIB_CTX *ctx, const DSA *dsa, int sign) * "Section 5.5.1.1FFC Domain Parameter Selection/Generation" and * "Appendix D" FFC Safe-prime Groups */ -int ossl_dh_check_key(OSSL_LIB_CTX *ctx, const DH *dh) +int ossl_dh_check_key(const DH *dh) { -# if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) { - size_t L, N; - const BIGNUM *p, *q; + size_t L, N; + const BIGNUM *p, *q; - if (dh == NULL) - return 0; + if (dh == NULL) + return 0; - p = DH_get0_p(dh); - q = DH_get0_q(dh); - if (p == NULL || q == NULL) - return 0; + p = DH_get0_p(dh); + q = DH_get0_q(dh); + if (p == NULL || q == NULL) + return 0; - L = BN_num_bits(p); - if (L < 2048) - return 0; + L = BN_num_bits(p); + if (L < 2048) + return 0; - /* If it is a safe prime group then it is ok */ - if (DH_get_nid(dh)) - return 1; + /* If it is a safe prime group then it is ok */ + if (DH_get_nid(dh)) + return 1; - /* If not then it must be FFC, which only allows certain sizes. */ - N = BN_num_bits(q); + /* If not then it must be FFC, which only allows certain sizes. */ + N = BN_num_bits(q); - return (L == 2048 && (N == 224 || N == 256)); - } -# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ - return 1; + return (L == 2048 && (N == 224 || N == 256)); } #endif /* OPENSSL_NO_DH */ - -int ossl_digest_get_approved_nid_with_sha1(OSSL_LIB_CTX *ctx, const EVP_MD *md, - int sha1_allowed) -{ - int mdnid = ossl_digest_get_approved_nid(md); - -# if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) { - if (mdnid == NID_undef || (mdnid == NID_sha1 && !sha1_allowed)) - mdnid = -1; /* disallowed by security checks */ - } -# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ - return mdnid; -} - -int ossl_digest_is_allowed(OSSL_LIB_CTX *ctx, const EVP_MD *md) -{ -# if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) - return ossl_digest_get_approved_nid(md) != NID_undef; -# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ - return 1; -} diff --git a/providers/common/securitycheck_default.c b/providers/common/securitycheck_default.c index 246323493eafe..85e5fddd5a38a 100644 --- a/providers/common/securitycheck_default.c +++ b/providers/common/securitycheck_default.c @@ -28,8 +28,7 @@ int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx) return 0; } -int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, - ossl_unused int sha1_allowed) +int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md) { int mdnid; @@ -42,7 +41,7 @@ int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, { NID_ripemd160, OSSL_DIGEST_NAME_RIPEMD160 }, }; - mdnid = ossl_digest_get_approved_nid_with_sha1(ctx, md, 1); + mdnid = ossl_digest_get_approved_nid(md); if (mdnid == NID_undef) mdnid = ossl_digest_md_to_nid(md, name_to_nid, OSSL_NELEM(name_to_nid)); return mdnid; diff --git a/providers/common/securitycheck_fips.c b/providers/common/securitycheck_fips.c index d1262d8795387..84579dc7b3f3a 100644 --- a/providers/common/securitycheck_fips.c +++ b/providers/common/securitycheck_fips.c @@ -18,6 +18,7 @@ #include #include #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "prov/fipscommon.h" int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) @@ -34,12 +35,90 @@ int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx) return FIPS_tls_prf_ems_check(libctx); } -int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, - int sha1_allowed) +int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md) { -#if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS) - if (ossl_securitycheck_enabled(ctx)) - return ossl_digest_get_approved_nid_with_sha1(ctx, md, sha1_allowed); -#endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ return ossl_digest_get_approved_nid(md); } + +int ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + const RSA *rsa, const char *desc, int protect) +{ + int key_approved = ossl_rsa_check_key_size(rsa, protect); + + if (!key_approved) { + if (!ossl_FIPS_IND_on_unapproved(ind, id, libctx, desc, "Key size", + ossl_securitycheck_enabled)) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH, + "operation: %s", desc); + return 0; + } + } + return 1; +} + +# ifndef OPENSSL_NO_EC +int ossl_fips_ind_ec_key_check(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + const EC_GROUP *group, const char *desc, + int protect) +{ + int curve_allowed, strength_allowed; + + if (group == NULL) + return 0; + + curve_allowed = ossl_ec_check_curve_allowed(group); + strength_allowed = ossl_ec_check_security_strength(group, protect); + + if (!strength_allowed || !curve_allowed) { + if (!ossl_FIPS_IND_on_unapproved(ind, id, libctx, desc, "EC Key", + ossl_securitycheck_enabled)) { + if (!curve_allowed) + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE); + if (!strength_allowed) + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} +#endif + +int ossl_fips_ind_digest_check(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + const EVP_MD *md, const char *desc) +{ + int approved = (ossl_digest_get_approved_nid(md) != NID_undef); + + if (!approved) { + if (!ossl_FIPS_IND_on_unapproved(ind, id, libctx, desc, "Digest", + ossl_securitycheck_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + } + return 1; +} + +int ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND *ind, int id, + OSSL_LIB_CTX *libctx, + int nid, int sha1_allowed, + const char *desc) +{ + int approved; + + if (nid == NID_undef) + approved = 0; + else + approved = sha1_allowed || nid != NID_sha1; + + if (!approved) { + if (!ossl_FIPS_IND_on_unapproved(ind, id, libctx, desc, "Digest SHA1", + ossl_securitycheck_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); + return 0; + } + } + return 1; +} diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c index 71bfa344d4864..f88cc96a75f15 100644 --- a/providers/implementations/asymciphers/rsa_enc.c +++ b/providers/implementations/asymciphers/rsa_enc.c @@ -30,6 +30,7 @@ #include "prov/implementations.h" #include "prov/providercommon.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include @@ -77,6 +78,7 @@ typedef struct { unsigned int alt_version; /* PKCS#1 v1.5 decryption mode */ unsigned int implicit_rejection; + OSSL_FIPS_IND_DECLARE } PROV_RSA_CTX; static void *rsa_newctx(void *provctx) @@ -89,21 +91,22 @@ static void *rsa_newctx(void *provctx) if (prsactx == NULL) return NULL; prsactx->libctx = PROV_LIBCTX_OF(provctx); + OSSL_FIPS_IND_INIT(prsactx) return prsactx; } static int rsa_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[], - int operation) + int operation, const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int protect = 0; if (!ossl_prov_is_running() || prsactx == NULL || vrsa == NULL) return 0; - if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) + if (!ossl_rsa_key_op_get_protect(vrsa, operation, &protect)) return 0; - if (!RSA_up_ref(vrsa)) return 0; RSA_free(prsactx->rsa); @@ -120,19 +123,31 @@ static int rsa_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[], ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); return 0; } - return rsa_set_ctx_params(prsactx, params); + + OSSL_FIPS_IND_SET_APPROVED(prsactx) + if (!rsa_set_ctx_params(prsactx, params)) + return 0; +#ifdef FIPS_MODULE + if (!ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND_GET(prsactx), + OSSL_FIPS_IND_SETTABLE0, prsactx->libctx, + prsactx->rsa, desc, protect)) + return 0; +#endif + return 1; } static int rsa_encrypt_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) { - return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCRYPT); + return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCRYPT, + "RSA Encrypt Init"); } static int rsa_decrypt_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) { - return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECRYPT); + return rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECRYPT, + "RSA Decrypt Init"); } static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen, @@ -408,7 +423,8 @@ static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION); if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->implicit_rejection)) return 0; - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(prsactx, params)) + return 0; return 1; } @@ -421,6 +437,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -443,6 +460,10 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_ASYM_CIPHER_PARAM_FIPS_KEY_CHECK)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); if (p != NULL) { str = mdname; @@ -566,7 +587,6 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) return 0; prsactx->implicit_rejection = implicit_rejection; } - return 1; } @@ -580,6 +600,7 @@ static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_ASYM_CIPHER_PARAM_FIPS_KEY_CHECK) OSSL_PARAM_END }; diff --git a/providers/implementations/exchange/dh_exch.c b/providers/implementations/exchange/dh_exch.c index 20b8fa0078c90..717706a174da6 100644 --- a/providers/implementations/exchange/dh_exch.c +++ b/providers/implementations/exchange/dh_exch.c @@ -25,6 +25,7 @@ #include "prov/implementations.h" #include "prov/provider_ctx.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "crypto/dh.h" static OSSL_FUNC_keyexch_newctx_fn dh_newctx; @@ -76,6 +77,7 @@ typedef struct { /* KDF output length */ size_t kdf_outlen; char *kdf_cekalg; + OSSL_FIPS_IND_DECLARE } PROV_DH_CTX; static void *dh_newctx(void *provctx) @@ -88,11 +90,36 @@ static void *dh_newctx(void *provctx) pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX)); if (pdhctx == NULL) return NULL; + OSSL_FIPS_IND_INIT(pdhctx) pdhctx->libctx = PROV_LIBCTX_OF(provctx); pdhctx->kdf_type = PROV_DH_KDF_NONE; return pdhctx; } +#ifdef FIPS_MODULE +static int dh_check_key(PROV_DH_CTX *ctx) +{ + int key_approved = ossl_dh_check_key(ctx->dh); + + if (!key_approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + ctx->libctx, "DH Init", "DH Key", + ossl_securitycheck_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} + +static int digest_check(PROV_DH_CTX *ctx, const EVP_MD *md) +{ + return ossl_fips_ind_digest_check(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE1, ctx->libctx, + md, "DH Set Ctx"); +} +#endif + static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[]) { PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; @@ -105,8 +132,15 @@ static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[]) DH_free(pdhctx->dh); pdhctx->dh = vdh; pdhctx->kdf_type = PROV_DH_KDF_NONE; - return dh_set_ctx_params(pdhctx, params) - && ossl_dh_check_key(pdhctx->libctx, vdh); + + OSSL_FIPS_IND_SET_APPROVED(pdhctx) + if (!dh_set_ctx_params(pdhctx, params)) + return 0; +#ifdef FIPS_MODULE + if (!dh_check_key(pdhctx)) + return 0; +#endif + return 1; } /* The 2 parties must share the same domain parameters */ @@ -317,6 +351,13 @@ static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); if (p != NULL) { str = name; @@ -351,11 +392,13 @@ static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[]) pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops); if (pdhctx->kdf_md == NULL) return 0; - if (!ossl_digest_is_allowed(pdhctx->libctx, pdhctx->kdf_md)) { +#ifdef FIPS_MODULE + if (!digest_check(pdhctx, pdhctx->kdf_md)) { EVP_MD_free(pdhctx->kdf_md); pdhctx->kdf_md = NULL; return 0; } +#endif } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); @@ -416,6 +459,8 @@ static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; @@ -432,6 +477,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -490,7 +536,8 @@ static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[]) && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL ? "" : pdhctx->kdf_cekalg)) return 0; - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdhctx, params)) + return 0; return 1; } diff --git a/providers/implementations/exchange/ecdh_exch.c b/providers/implementations/exchange/ecdh_exch.c index 5b8412aba16df..85b782a39d704 100644 --- a/providers/implementations/exchange/ecdh_exch.c +++ b/providers/implementations/exchange/ecdh_exch.c @@ -26,6 +26,7 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */ static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx; @@ -77,6 +78,7 @@ typedef struct { size_t kdf_ukmlen; /* KDF output length */ size_t kdf_outlen; + OSSL_FIPS_IND_DECLARE } PROV_ECDH_CTX; static @@ -94,6 +96,7 @@ void *ecdh_newctx(void *provctx) pectx->libctx = PROV_LIBCTX_OF(provctx); pectx->cofactor_mode = -1; pectx->kdf_type = PROV_ECDH_KDF_NONE; + OSSL_FIPS_IND_INIT(pectx) return (void *)pectx; } @@ -106,14 +109,24 @@ int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[]) if (!ossl_prov_is_running() || pecdhctx == NULL || vecdh == NULL + || (EC_KEY_get0_group(vecdh) == NULL) || !EC_KEY_up_ref(vecdh)) return 0; EC_KEY_free(pecdhctx->k); pecdhctx->k = vecdh; pecdhctx->cofactor_mode = -1; pecdhctx->kdf_type = PROV_ECDH_KDF_NONE; - return ecdh_set_ctx_params(pecdhctx, params) - && ossl_ec_check_key(pecdhctx->libctx, vecdh, 1); + + OSSL_FIPS_IND_SET_APPROVED(pecdhctx) + if (!ecdh_set_ctx_params(pecdhctx, params)) + return 0; +#ifdef FIPS_MODULE + if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx), + OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx, + EC_KEY_get0_group(vecdh), "ECDH Init", 1)) + return 0; +#endif + return 1; } static @@ -146,9 +159,16 @@ int ecdh_set_peer(void *vpecdhctx, void *vecdh) if (!ossl_prov_is_running() || pecdhctx == NULL || vecdh == NULL - || !ecdh_match_params(pecdhctx->k, vecdh) - || !ossl_ec_check_key(pecdhctx->libctx, vecdh, 1) - || !EC_KEY_up_ref(vecdh)) + || !ecdh_match_params(pecdhctx->k, vecdh)) + return 0; +#ifdef FIPS_MODULE + if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx), + OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx, + EC_KEY_get0_group(vecdh), "ECDH Set Peer", + 1)) + return 0; +#endif + if (!EC_KEY_up_ref(vecdh)) return 0; EC_KEY_free(pecdhctx->peerk); @@ -237,6 +257,13 @@ int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); if (p != NULL) { int mode; @@ -285,11 +312,15 @@ int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[]) pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops); if (pectx->kdf_md == NULL) return 0; - if (!ossl_digest_is_allowed(pectx->libctx, pectx->kdf_md)) { +#ifdef FIPS_MODULE + if (!ossl_fips_ind_digest_check(OSSL_FIPS_IND_GET(pectx), + OSSL_FIPS_IND_SETTABLE1, pectx->libctx, + pectx->kdf_md, "ECDH Set Ctx")) { EVP_MD_free(pectx->kdf_md); pectx->kdf_md = NULL; return 0; } +#endif } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); @@ -323,6 +354,8 @@ static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; @@ -390,7 +423,8 @@ int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[]) if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen)) return 0; - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(pectx, params)) + return 0; return 1; } @@ -401,6 +435,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, NULL, 0), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c index 2792486924df8..cf4b6565462db 100644 --- a/providers/implementations/kdfs/tls1_prf.c +++ b/providers/implementations/kdfs/tls1_prf.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -68,6 +68,7 @@ #include "prov/implementations.h" #include "prov/provider_util.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "internal/e_os.h" #include "internal/safe_math.h" @@ -106,6 +107,7 @@ typedef struct { /* Concatenated seed data */ unsigned char *seed; size_t seedlen; + OSSL_FIPS_IND_DECLARE } TLS1_PRF; static void *kdf_tls1_prf_new(void *provctx) @@ -115,8 +117,10 @@ static void *kdf_tls1_prf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) { ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) + } return ctx; } @@ -161,6 +165,7 @@ static void *kdf_tls1_prf_dup(void *vctx) if (!ossl_prov_memdup(src->seed, src->seedlen, &dest->seed, &dest->seedlen)) goto err; + OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -169,11 +174,39 @@ static void *kdf_tls1_prf_dup(void *vctx) return NULL; } +#ifdef FIPS_MODULE + +static int fips_ems_check_passed(TLS1_PRF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + /* + * Check that TLS is using EMS. + * + * The seed buffer is prepended with a label. + * If EMS mode is enforced then the label "master secret" is not allowed, + * We do the check this way since the PRF is used for other purposes, as well + * as "extended master secret". + */ + int ems_approved = (ctx->seedlen < TLS_MD_MASTER_SECRET_CONST_SIZE + || memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST, + TLS_MD_MASTER_SECRET_CONST_SIZE) != 0); + + if (!ems_approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "TLS_PRF", "EMS", + ossl_tls1_prf_ems_check_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED); + return 0; + } + } + return 1; +} +#endif + static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { TLS1_PRF *ctx = (TLS1_PRF *)vctx; - OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); if (!ossl_prov_is_running() || !kdf_tls1_prf_set_ctx_params(ctx, params)) return 0; @@ -195,20 +228,10 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } - /* - * The seed buffer is prepended with a label. - * If EMS mode is enforced then the label "master secret" is not allowed, - * We do the check this way since the PRF is used for other purposes, as well - * as "extended master secret". - */ - if (ossl_tls1_prf_ems_check_enabled(libctx)) { - if (ctx->seedlen >= TLS_MD_MASTER_SECRET_CONST_SIZE - && memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) { - ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED); - return 0; - } - } +#ifdef FIPS_MODULE + if (!fips_ems_check_passed(ctx)) + return 0; +#endif return tls1_prf_alg(ctx->P_hash, ctx->P_sha1, ctx->sec, ctx->seclen, @@ -225,6 +248,10 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_EMS_CHECK)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { if (OPENSSL_strcasecmp(p->data, SN_md5_sha1) == 0) { if (!ossl_prov_macctx_load_from_params(&ctx->P_hash, params, @@ -289,6 +316,7 @@ static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params( OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_EMS_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -300,7 +328,9 @@ static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[]) if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) return OSSL_PARAM_set_size_t(p, SIZE_MAX); - return -2; + if (!OSSL_FIPS_IND_GET_CTX_PARAM(((TLS1_PRF *)vctx), params)) + return 0; + return 1; } static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( @@ -308,6 +338,7 @@ static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c index ff22ddffcf6c6..28925b7d1339f 100644 --- a/providers/implementations/kem/rsa_kem.c +++ b/providers/implementations/kem/rsa_kem.c @@ -27,6 +27,7 @@ #include "prov/provider_ctx.h" #include "prov/implementations.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" static OSSL_FUNC_kem_newctx_fn rsakem_newctx; static OSSL_FUNC_kem_encapsulate_init_fn rsakem_encapsulate_init; @@ -56,6 +57,7 @@ typedef struct { OSSL_LIB_CTX *libctx; RSA *rsa; int op; + OSSL_FIPS_IND_DECLARE } PROV_RSA_CTX; static const OSSL_ITEM rsakem_opname_id_map[] = { @@ -89,6 +91,7 @@ static void *rsakem_newctx(void *provctx) return NULL; prsactx->libctx = PROV_LIBCTX_OF(provctx); prsactx->op = KEM_OP_UNDEFINED; + OSSL_FIPS_IND_INIT(prsactx) return prsactx; } @@ -119,44 +122,62 @@ static void *rsakem_dupctx(void *vprsactx) } static int rsakem_init(void *vprsactx, void *vrsa, - const OSSL_PARAM params[], int operation) + const OSSL_PARAM params[], int operation, + const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int protect = 0; if (prsactx == NULL || vrsa == NULL) return 0; - if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) + if (!ossl_rsa_key_op_get_protect(vrsa, operation, &protect)) return 0; - if (!RSA_up_ref(vrsa)) return 0; RSA_free(prsactx->rsa); prsactx->rsa = vrsa; - return rsakem_set_ctx_params(prsactx, params); + OSSL_FIPS_IND_SET_APPROVED(prsactx) + if (!rsakem_set_ctx_params(prsactx, params)) + return 0; +#ifdef FIPS_MODULE + if (!ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND_GET(prsactx), + OSSL_FIPS_IND_SETTABLE0, prsactx->libctx, + prsactx->rsa, desc, protect)) + return 0; +#endif + return 1; } static int rsakem_encapsulate_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) { - return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCAPSULATE); + return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCAPSULATE, + "RSA Encapsulate Init"); } static int rsakem_decapsulate_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) { - return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECAPSULATE); + return rsakem_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECAPSULATE, + "RSA Decapsulate Init"); } static int rsakem_get_ctx_params(void *vprsactx, OSSL_PARAM *params) { PROV_RSA_CTX *ctx = (PROV_RSA_CTX *)vprsactx; - return ctx != NULL; + if (ctx == NULL) + return 0; + + if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params)) + return 0; + return 1; } static const OSSL_PARAM known_gettable_rsakem_ctx_params[] = { + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -177,7 +198,9 @@ static int rsakem_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) if (params == NULL) return 1; - + if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KEM_PARAM_FIPS_KEY_CHECK)) + return 0; p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION); if (p != NULL) { if (p->data_type != OSSL_PARAM_UTF8_STRING) @@ -192,6 +215,7 @@ static int rsakem_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) static const OSSL_PARAM known_settable_rsakem_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KEM_PARAM_FIPS_KEY_CHECK) OSSL_PARAM_END }; diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c index 253131b10dbf2..230bba8ae6473 100644 --- a/providers/implementations/rands/drbg.c +++ b/providers/implementations/rands/drbg.c @@ -935,7 +935,8 @@ int ossl_drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time_interval)) return 0; - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(drbg, params)) + return 0; return 1; } @@ -990,13 +991,13 @@ int ossl_drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]) p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time_interval)) return 0; + return 1; } -/* Confirm digest is allowed to be used with a DRBG */ -int ossl_drbg_verify_digest(ossl_unused OSSL_LIB_CTX *libctx, const EVP_MD *md) -{ #ifdef FIPS_MODULE +static int digest_allowed(const EVP_MD *md) +{ /* FIPS 140-3 IG D.R limited DRBG digests to a specific set */ static const char *const allowed_digests[] = { "SHA1", /* SHA 1 allowed */ @@ -1005,12 +1006,28 @@ int ossl_drbg_verify_digest(ossl_unused OSSL_LIB_CTX *libctx, const EVP_MD *md) }; size_t i; - if (FIPS_restricted_drbg_digests_enabled(libctx)) { - for (i = 0; i < OSSL_NELEM(allowed_digests); i++) - if (EVP_MD_is_a(md, allowed_digests[i])) - return 1; - ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); - return 0; + for (i = 0; i < OSSL_NELEM(allowed_digests); i++) { + if (EVP_MD_is_a(md, allowed_digests[i])) + return 1; + } + return 0; +} +#endif + +/* Confirm digest is allowed to be used with a DRBG */ +int ossl_drbg_verify_digest(PROV_DRBG *drbg, OSSL_LIB_CTX *libctx, + const EVP_MD *md) +{ +#ifdef FIPS_MODULE + int approved = digest_allowed(md); + + if (!approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(drbg, OSSL_FIPS_IND_SETTABLE0, + libctx, "DRBG", "Digest", + FIPS_restricted_drbg_digests_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } } #endif /* Outside of FIPS, any digests that are not XOF are allowed */ diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c index 0c4553ad58dda..abd0b1a1c8932 100644 --- a/providers/implementations/rands/drbg_ctr.c +++ b/providers/implementations/rands/drbg_ctr.c @@ -625,6 +625,7 @@ static int drbg_ctr_new(PROV_DRBG *drbg) ctr->use_df = 1; drbg->data = ctr; + OSSL_FIPS_IND_INIT(drbg) return drbg_ctr_init_lengths(drbg); } @@ -697,6 +698,7 @@ static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(ossl_unused void *vctx, OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0), OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL), OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/rands/drbg_hash.c b/providers/implementations/rands/drbg_hash.c index bc401b72a2834..458b356b82f8f 100644 --- a/providers/implementations/rands/drbg_hash.c +++ b/providers/implementations/rands/drbg_hash.c @@ -424,6 +424,8 @@ static int drbg_hash_new(PROV_DRBG *ctx) if (hash == NULL) return 0; + OSSL_FIPS_IND_INIT(ctx) + ctx->data = hash; ctx->seedlen = HASH_PRNG_MAX_SEEDLEN; ctx->max_entropylen = DRBG_MAX_LENGTH; @@ -496,6 +498,7 @@ static const OSSL_PARAM *drbg_hash_gettable_ctx_params(ossl_unused void *vctx, static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -509,12 +512,16 @@ static int drbg_hash_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] const EVP_MD *md; int md_size; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!ossl_prov_digest_load_from_params(&hash->digest, params, libctx)) return 0; md = ossl_prov_digest_md(&hash->digest); if (md != NULL) { - if (!ossl_drbg_verify_digest(libctx, md)) + if (!ossl_drbg_verify_digest(ctx, libctx, md)) return 0; /* Error already raised for us */ /* These are taken from SP 800-90 10.1 Table 2 */ @@ -561,6 +568,7 @@ static const OSSL_PARAM *drbg_hash_settable_ctx_params(ossl_unused void *vctx, OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON, + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; diff --git a/providers/implementations/rands/drbg_hmac.c b/providers/implementations/rands/drbg_hmac.c index 5ebbe52e61f6a..43c75bf434dc9 100644 --- a/providers/implementations/rands/drbg_hmac.c +++ b/providers/implementations/rands/drbg_hmac.c @@ -316,6 +316,8 @@ static int drbg_hmac_new(PROV_DRBG *drbg) if (hmac == NULL) return 0; + OSSL_FIPS_IND_INIT(drbg) + drbg->data = hmac; /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ drbg->max_entropylen = DRBG_MAX_LENGTH; @@ -399,6 +401,7 @@ static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx, OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0), OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), OSSL_PARAM_DRBG_GETTABLE_CTX_COMMON, + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -412,11 +415,15 @@ static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[] const EVP_MD *md; int md_size; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx)) return 0; md = ossl_prov_digest_md(&hmac->digest); - if (md != NULL && !ossl_drbg_verify_digest(libctx, md)) + if (md != NULL && !ossl_drbg_verify_digest(ctx, libctx, md)) return 0; /* Error already raised for us */ if (!ossl_prov_macctx_load_from_params(&hmac->ctx, params, @@ -465,6 +472,7 @@ static const OSSL_PARAM *drbg_hmac_settable_ctx_params(ossl_unused void *vctx, OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0), OSSL_PARAM_DRBG_SETTABLE_CTX_COMMON, + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_DRBG_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; diff --git a/providers/implementations/rands/drbg_local.h b/providers/implementations/rands/drbg_local.h index 902dfc937d285..f8907a3193acf 100644 --- a/providers/implementations/rands/drbg_local.h +++ b/providers/implementations/rands/drbg_local.h @@ -18,6 +18,7 @@ # include "internal/nelem.h" # include "internal/numbers.h" # include "prov/provider_ctx.h" +# include "prov/fipsindicator.h" /* How many times to read the TSC as a randomness source. */ # define TSC_READ_COUNT 4 @@ -171,6 +172,8 @@ struct prov_drbg_st { OSSL_CALLBACK *cleanup_entropy_fn; OSSL_INOUT_CALLBACK *get_nonce_fn; OSSL_CALLBACK *cleanup_nonce_fn; + + OSSL_FIPS_IND_DECLARE }; PROV_DRBG *ossl_rand_drbg_new @@ -255,6 +258,6 @@ void ossl_crngt_cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen); /* Confirm digest is allowed to be used with a DRBG */ -int ossl_drbg_verify_digest(ossl_unused OSSL_LIB_CTX *libctx, const EVP_MD *md); +int ossl_drbg_verify_digest(PROV_DRBG *drbg, OSSL_LIB_CTX *libctx, const EVP_MD *md); #endif diff --git a/providers/implementations/signature/dsa_sig.c b/providers/implementations/signature/dsa_sig.c index 12cbdb4356d57..7df8adfdd5b33 100644 --- a/providers/implementations/signature/dsa_sig.c +++ b/providers/implementations/signature/dsa_sig.c @@ -30,6 +30,7 @@ #include "prov/implementations.h" #include "prov/provider_ctx.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "crypto/dsa.h" #include "prov/der_dsa.h" @@ -88,6 +89,7 @@ typedef struct { EVP_MD *md; EVP_MD_CTX *mdctx; int operation; + OSSL_FIPS_IND_DECLARE } PROV_DSA_CTX; @@ -117,6 +119,7 @@ static void *dsa_newctx(void *provctx, const char *propq) pdsactx->libctx = PROV_LIBCTX_OF(provctx); pdsactx->flag_allow_md = 1; + OSSL_FIPS_IND_INIT(pdsactx) if (propq != NULL && (pdsactx->propq = OPENSSL_strdup(propq)) == NULL) { OPENSSL_free(pdsactx); pdsactx = NULL; @@ -125,19 +128,22 @@ static void *dsa_newctx(void *provctx, const char *propq) } static int dsa_setup_md(PROV_DSA_CTX *ctx, - const char *mdname, const char *mdprops) + const char *mdname, const char *mdprops, + const char *desc) { + EVP_MD *md = NULL; + if (mdprops == NULL) mdprops = ctx->propq; if (mdname != NULL) { - int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); WPACKET pkt; - EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); - int md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, - sha1_allowed); + int md_nid; size_t mdname_len = strlen(mdname); + md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + md_nid = ossl_digest_get_approved_nid(md); + if (md == NULL || md_nid < 0) { if (md == NULL) ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, @@ -148,16 +154,25 @@ static int dsa_setup_md(PROV_DSA_CTX *ctx, if (mdname_len >= sizeof(ctx->mdname)) ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "%s exceeds name buffer length", mdname); - EVP_MD_free(md); - return 0; + goto err; + } +#ifdef FIPS_MODULE + { + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + + if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE1, + ctx->libctx, md_nid, sha1_allowed, + desc)) + goto err; } +#endif if (!ctx->flag_allow_md) { if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, "digest %s != %s", mdname, ctx->mdname); - EVP_MD_free(md); - return 0; + goto err; } EVP_MD_free(md); return 1; @@ -188,10 +203,31 @@ static int dsa_setup_md(PROV_DSA_CTX *ctx, OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname)); } return 1; +err: + EVP_MD_free(md); + return 0; +} + +#ifdef FIPS_MODULE +static int dsa_check_key(PROV_DSA_CTX *ctx, int sign, const char *desc) +{ + int approved = ossl_dsa_check_key(ctx->dsa, sign); + + if (!approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + ctx->libctx, desc, "DSA Key", + ossl_securitycheck_enabled)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; } +#endif static int dsa_signverify_init(void *vpdsactx, void *vdsa, - const OSSL_PARAM params[], int operation) + const OSSL_PARAM params[], int operation, + const char *desc) { PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; @@ -205,11 +241,6 @@ static int dsa_signverify_init(void *vpdsactx, void *vdsa, } if (vdsa != NULL) { - if (!ossl_dsa_check_key(pdsactx->libctx, vdsa, - operation == EVP_PKEY_OP_SIGN)) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); - return 0; - } if (!DSA_up_ref(vdsa)) return 0; DSA_free(pdsactx->dsa); @@ -218,21 +249,27 @@ static int dsa_signverify_init(void *vpdsactx, void *vdsa, pdsactx->operation = operation; + OSSL_FIPS_IND_SET_APPROVED(pdsactx) if (!dsa_set_ctx_params(pdsactx, params)) return 0; - +#ifdef FIPS_MODULE + if (!dsa_check_key(pdsactx, operation == EVP_PKEY_OP_SIGN, desc)) + return 0; +#endif return 1; } static int dsa_sign_init(void *vpdsactx, void *vdsa, const OSSL_PARAM params[]) { - return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_SIGN); + return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_SIGN, + "DSA Sign Init"); } static int dsa_verify_init(void *vpdsactx, void *vdsa, const OSSL_PARAM params[]) { - return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_VERIFY); + return dsa_signverify_init(vpdsactx, vdsa, params, EVP_PKEY_OP_VERIFY, + "DSA Verify Init"); } static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen, @@ -282,17 +319,17 @@ static int dsa_verify(void *vpdsactx, const unsigned char *sig, size_t siglen, static int dsa_digest_signverify_init(void *vpdsactx, const char *mdname, void *vdsa, const OSSL_PARAM params[], - int operation) + int operation, const char *desc) { PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx; if (!ossl_prov_is_running()) return 0; - if (!dsa_signverify_init(vpdsactx, vdsa, params, operation)) + if (!dsa_signverify_init(vpdsactx, vdsa, params, operation, desc)) return 0; - if (!dsa_setup_md(pdsactx, mdname, NULL)) + if (!dsa_setup_md(pdsactx, mdname, NULL, desc)) return 0; pdsactx->flag_allow_md = 0; @@ -318,14 +355,16 @@ static int dsa_digest_sign_init(void *vpdsactx, const char *mdname, void *vdsa, const OSSL_PARAM params[]) { return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params, - EVP_PKEY_OP_SIGN); + EVP_PKEY_OP_SIGN, + "DSA Digest Sign Init"); } static int dsa_digest_verify_init(void *vpdsactx, const char *mdname, void *vdsa, const OSSL_PARAM params[]) { return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params, - EVP_PKEY_OP_VERIFY); + EVP_PKEY_OP_VERIFY, + "DSA Digest Verify Init"); } int dsa_digest_signverify_update(void *vpdsactx, const unsigned char *data, @@ -470,6 +509,8 @@ static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params) p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE); if (p != NULL && !OSSL_PARAM_set_uint(p, pdsactx->nonce_type)) return 0; + if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdsactx, params)) + return 0; return 1; } @@ -478,6 +519,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -497,6 +539,13 @@ static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdsactx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdsactx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); if (p != NULL) { char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname; @@ -510,14 +559,13 @@ static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[]) if (propsp != NULL && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops))) return 0; - if (!dsa_setup_md(pdsactx, mdname, mdprops)) + if (!dsa_setup_md(pdsactx, mdname, mdprops, "DSA Set Ctx")) return 0; } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE); if (p != NULL && !OSSL_PARAM_get_uint(p, &pdsactx->nonce_type)) return 0; - return 1; } @@ -525,6 +573,8 @@ static const OSSL_PARAM settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c index 7cf1f08381c0a..28e102bd0ff3a 100644 --- a/providers/implementations/signature/ecdsa_sig.c +++ b/providers/implementations/signature/ecdsa_sig.c @@ -30,6 +30,7 @@ #include "prov/implementations.h" #include "prov/provider_ctx.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #include "crypto/ec.h" #include "prov/der_ec.h" @@ -105,6 +106,7 @@ typedef struct { #endif /* If this is set then the generated k is not random */ unsigned int nonce_type; + OSSL_FIPS_IND_DECLARE } PROV_ECDSA_CTX; static void *ecdsa_newctx(void *provctx, const char *propq) @@ -118,6 +120,7 @@ static void *ecdsa_newctx(void *provctx, const char *propq) if (ctx == NULL) return NULL; + OSSL_FIPS_IND_INIT(ctx) ctx->flag_allow_md = 1; ctx->libctx = PROV_LIBCTX_OF(provctx); if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) { @@ -128,7 +131,8 @@ static void *ecdsa_newctx(void *provctx, const char *propq) } static int ecdsa_signverify_init(void *vctx, void *ec, - const OSSL_PARAM params[], int operation) + const OSSL_PARAM params[], int operation, + const char *desc) { PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; @@ -142,8 +146,6 @@ static int ecdsa_signverify_init(void *vctx, void *ec, } if (ec != NULL) { - if (!ossl_ec_check_key(ctx->libctx, ec, operation == EVP_PKEY_OP_SIGN)) - return 0; if (!EC_KEY_up_ref(ec)) return 0; EC_KEY_free(ctx->ec); @@ -152,20 +154,29 @@ static int ecdsa_signverify_init(void *vctx, void *ec, ctx->operation = operation; + OSSL_FIPS_IND_SET_APPROVED(ctx) if (!ecdsa_set_ctx_params(ctx, params)) return 0; - +#ifdef FIPS_MODULE + if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE0, ctx->libctx, + EC_KEY_get0_group(ctx->ec), desc, + operation == EVP_PKEY_OP_SIGN)) + return 0; +#endif return 1; } static int ecdsa_sign_init(void *vctx, void *ec, const OSSL_PARAM params[]) { - return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_SIGN); + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_SIGN, + "ECDSA Sign Init"); } static int ecdsa_verify_init(void *vctx, void *ec, const OSSL_PARAM params[]) { - return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_VERIFY); + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_VERIFY, + "ECDSA Verify Init"); } static int ecdsa_sign(void *vctx, unsigned char *sig, size_t *siglen, @@ -223,11 +234,11 @@ static int ecdsa_verify(void *vctx, const unsigned char *sig, size_t siglen, } static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname, - const char *mdprops) + const char *mdprops, const char *desc) { EVP_MD *md = NULL; size_t mdname_len; - int md_nid, sha1_allowed, md_size; + int md_nid, md_size; WPACKET pkt; if (mdname == NULL) @@ -251,25 +262,31 @@ static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname, if (md_size <= 0) { ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "%s has invalid md size %d", mdname, md_size); - EVP_MD_free(md); - return 0; + goto err; } - sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); - md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, - sha1_allowed); + md_nid = ossl_digest_get_approved_nid(md); if (md_nid < 0) { ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, "digest=%s", mdname); - EVP_MD_free(md); - return 0; + goto err; + } + +#ifdef FIPS_MODULE + { + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + + if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE1, ctx->libctx, + md_nid, sha1_allowed, desc)) + goto err; } +#endif if (!ctx->flag_allow_md) { if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, "digest %s != %s", mdname, ctx->mdname); - EVP_MD_free(md); - return 0; + goto err; } EVP_MD_free(md); return 1; @@ -293,19 +310,22 @@ static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname, OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname)); return 1; +err: + EVP_MD_free(md); + return 0; } static int ecdsa_digest_signverify_init(void *vctx, const char *mdname, void *ec, const OSSL_PARAM params[], - int operation) + int operation, const char *desc) { PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx; if (!ossl_prov_is_running()) return 0; - if (!ecdsa_signverify_init(vctx, ec, params, operation) - || !ecdsa_setup_md(ctx, mdname, NULL)) + if (!ecdsa_signverify_init(vctx, ec, params, operation, desc) + || !ecdsa_setup_md(ctx, mdname, NULL, desc)) return 0; ctx->flag_allow_md = 0; @@ -329,14 +349,16 @@ static int ecdsa_digest_sign_init(void *vctx, const char *mdname, void *ec, const OSSL_PARAM params[]) { return ecdsa_digest_signverify_init(vctx, mdname, ec, params, - EVP_PKEY_OP_SIGN); + EVP_PKEY_OP_SIGN, + "ECDSA Digest Sign Init"); } static int ecdsa_digest_verify_init(void *vctx, const char *mdname, void *ec, const OSSL_PARAM params[]) { return ecdsa_digest_signverify_init(vctx, mdname, ec, params, - EVP_PKEY_OP_VERIFY); + EVP_PKEY_OP_VERIFY, + "ECDSA Digest Verify Init"); } int ecdsa_digest_signverify_update(void *vctx, const unsigned char *data, @@ -477,7 +499,8 @@ static int ecdsa_get_ctx_params(void *vctx, OSSL_PARAM *params) p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE); if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->nonce_type)) return 0; - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params)) + return 0; return 1; } @@ -486,6 +509,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -506,6 +530,13 @@ static int ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK)) + return 0; + #if !defined(OPENSSL_NO_ACVP_TESTS) p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_KAT); if (p != NULL && !OSSL_PARAM_get_uint(p, &ctx->kattest)) @@ -525,7 +556,7 @@ static int ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (propsp != NULL && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops))) return 0; - if (!ecdsa_setup_md(ctx, mdname, mdprops)) + if (!ecdsa_setup_md(ctx, mdname, mdprops, "ECDSA Set Ctx")) return 0; } @@ -540,7 +571,6 @@ static int ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (p != NULL && !OSSL_PARAM_get_uint(p, &ctx->nonce_type)) return 0; - return 1; } @@ -550,6 +580,8 @@ static const OSSL_PARAM settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c index cc7353bbcaf27..569c106869f8a 100644 --- a/providers/implementations/signature/rsa_sig.c +++ b/providers/implementations/signature/rsa_sig.c @@ -31,6 +31,7 @@ #include "prov/provider_ctx.h" #include "prov/der_rsa.h" #include "prov/securitycheck.h" +#include "prov/fipsindicator.h" #define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1 @@ -106,6 +107,7 @@ typedef struct { /* Temp buffer */ unsigned char *tbuf; + OSSL_FIPS_IND_DECLARE } PROV_RSA_CTX; @@ -191,6 +193,7 @@ static void *rsa_newctx(void *provctx, const char *propq) return NULL; } + OSSL_FIPS_IND_INIT(prsactx) prsactx->libctx = PROV_LIBCTX_OF(provctx); prsactx->flag_allow_md = 1; prsactx->propq = propq_copy; @@ -300,41 +303,55 @@ static unsigned char *rsa_generate_signature_aid(PROV_RSA_CTX *ctx, } static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname, - const char *mdprops) + const char *mdprops, const char *desc) { + EVP_MD *md = NULL; + if (mdprops == NULL) mdprops = ctx->propq; if (mdname != NULL) { - EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); - int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); - int md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, - sha1_allowed); + int md_nid; size_t mdname_len = strlen(mdname); - if (md == NULL - || md_nid <= 0 - || !rsa_check_padding(ctx, mdname, NULL, md_nid) - || mdname_len >= sizeof(ctx->mdname)) { - if (md == NULL) - ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, - "%s could not be fetched", mdname); - if (md_nid <= 0) - ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, - "digest=%s", mdname); - if (mdname_len >= sizeof(ctx->mdname)) + md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + + if (md == NULL) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "%s could not be fetched", mdname); + goto err; + } + md_nid = ossl_digest_rsa_sign_get_md_nid(md); + if (md_nid <= 0) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "digest=%s", mdname); + goto err; + } +#ifdef FIPS_MODULE + { + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + + if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx), + OSSL_FIPS_IND_SETTABLE1, + ctx->libctx, + md_nid, sha1_allowed, desc)) + goto err; + } +#endif + + if (!rsa_check_padding(ctx, mdname, NULL, md_nid)) + goto err; + if (mdname_len >= sizeof(ctx->mdname)) { ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "%s exceeds name buffer length", mdname); - EVP_MD_free(md); - return 0; + goto err; } if (!ctx->flag_allow_md) { if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, "digest %s != %s", mdname, ctx->mdname); - EVP_MD_free(md); - return 0; + goto err; } EVP_MD_free(md); return 1; @@ -342,8 +359,7 @@ static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname, if (!ctx->mgf1_md_set) { if (!EVP_MD_up_ref(md)) { - EVP_MD_free(md); - return 0; + goto err; } EVP_MD_free(ctx->mgf1_md); ctx->mgf1_md = md; @@ -361,6 +377,9 @@ static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname, } return 1; +err: + EVP_MD_free(md); + return 0; } static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname, @@ -379,7 +398,7 @@ static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname, return 0; } /* The default for mgf1 is SHA1 - so allow SHA1 */ - if ((mdnid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, 1)) <= 0 + if ((mdnid = ossl_digest_rsa_sign_get_md_nid(md)) <= 0 || !rsa_check_padding(ctx, NULL, mdname, mdnid)) { if (mdnid <= 0) ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, @@ -403,9 +422,11 @@ static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname, } static int rsa_signverify_init(void *vprsactx, void *vrsa, - const OSSL_PARAM params[], int operation) + const OSSL_PARAM params[], int operation, + const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; + int protect; if (!ossl_prov_is_running() || prsactx == NULL) return 0; @@ -416,14 +437,13 @@ static int rsa_signverify_init(void *vprsactx, void *vrsa, } if (vrsa != NULL) { - if (!ossl_rsa_check_key(prsactx->libctx, vrsa, operation)) - return 0; - if (!RSA_up_ref(vrsa)) return 0; RSA_free(prsactx->rsa); prsactx->rsa = vrsa; } + if (!ossl_rsa_key_op_get_protect(prsactx->rsa, operation, &protect)) + return 0; prsactx->operation = operation; @@ -481,7 +501,7 @@ static int rsa_signverify_init(void *vprsactx, void *vrsa, /* call rsa_setup_mgf1_md before rsa_setup_md to avoid duplication */ if (!rsa_setup_mgf1_md(prsactx, mgf1mdname, prsactx->propq) - || !rsa_setup_md(prsactx, mdname, prsactx->propq) + || !rsa_setup_md(prsactx, mdname, prsactx->propq, desc) || !rsa_check_parameters(prsactx, min_saltlen)) return 0; } @@ -493,9 +513,15 @@ static int rsa_signverify_init(void *vprsactx, void *vrsa, return 0; } + OSSL_FIPS_IND_SET_APPROVED(prsactx) if (!rsa_set_ctx_params(prsactx, params)) return 0; - +#ifdef FIPS_MODULE + if (!ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND_GET(prsactx), + OSSL_FIPS_IND_SETTABLE0, prsactx->libctx, + prsactx->rsa, desc, protect)) + return 0; +#endif return 1; } @@ -525,7 +551,8 @@ static int rsa_sign_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) { if (!ossl_prov_is_running()) return 0; - return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_SIGN); + return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_SIGN, + "RSA Sign Init"); } static int rsa_sign(void *vprsactx, unsigned char *sig, size_t *siglen, @@ -680,7 +707,7 @@ static int rsa_verify_recover_init(void *vprsactx, void *vrsa, if (!ossl_prov_is_running()) return 0; return rsa_signverify_init(vprsactx, vrsa, params, - EVP_PKEY_OP_VERIFYRECOVER); + EVP_PKEY_OP_VERIFYRECOVER, "RSA VerifyRecover Init"); } static int rsa_verify_recover(void *vprsactx, @@ -772,7 +799,8 @@ static int rsa_verify_init(void *vprsactx, void *vrsa, { if (!ossl_prov_is_running()) return 0; - return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_VERIFY); + return rsa_signverify_init(vprsactx, vrsa, params, EVP_PKEY_OP_VERIFY, + "RSA Verify Init"); } static int rsa_verify(void *vprsactx, const unsigned char *sig, size_t siglen, @@ -861,20 +889,20 @@ static int rsa_verify(void *vprsactx, const unsigned char *sig, size_t siglen, static int rsa_digest_signverify_init(void *vprsactx, const char *mdname, void *vrsa, const OSSL_PARAM params[], - int operation) + int operation, const char *desc) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; if (!ossl_prov_is_running()) return 0; - if (!rsa_signverify_init(vprsactx, vrsa, params, operation)) + if (!rsa_signverify_init(vprsactx, vrsa, params, operation, desc)) return 0; if (mdname != NULL /* was rsa_setup_md already called in rsa_signverify_init()? */ && (mdname[0] == '\0' || OPENSSL_strcasecmp(prsactx->mdname, mdname) != 0) - && !rsa_setup_md(prsactx, mdname, prsactx->propq)) + && !rsa_setup_md(prsactx, mdname, prsactx->propq, desc)) return 0; prsactx->flag_allow_md = 0; @@ -914,7 +942,8 @@ static int rsa_digest_sign_init(void *vprsactx, const char *mdname, if (!ossl_prov_is_running()) return 0; return rsa_digest_signverify_init(vprsactx, mdname, vrsa, - params, EVP_PKEY_OP_SIGN); + params, EVP_PKEY_OP_SIGN, + "RSA Digest Sign Init"); } static int rsa_digest_sign_final(void *vprsactx, unsigned char *sig, @@ -951,7 +980,8 @@ static int rsa_digest_verify_init(void *vprsactx, const char *mdname, if (!ossl_prov_is_running()) return 0; return rsa_digest_signverify_init(vprsactx, mdname, vrsa, - params, EVP_PKEY_OP_VERIFY); + params, EVP_PKEY_OP_VERIFY, + "RSA Digest Verify Init"); } int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig, @@ -1145,7 +1175,8 @@ static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) return 0; } } - + if (!OSSL_FIPS_IND_GET_CTX_PARAM(prsactx, params)) + return 0; return 1; } @@ -1155,6 +1186,7 @@ static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; @@ -1180,6 +1212,14 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK)) + return 0; + + if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK)) + return 0; + pad_mode = prsactx->pad_mode; saltlen = prsactx->saltlen; @@ -1380,7 +1420,7 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) return 0; if (pmdname != NULL) { - if (!rsa_setup_md(prsactx, pmdname, pmdprops)) + if (!rsa_setup_md(prsactx, pmdname, pmdprops, "RSA Sign Set Ctx")) return 0; } else { if (!rsa_check_padding(prsactx, NULL, NULL, prsactx->mdnid)) @@ -1396,6 +1436,8 @@ static const OSSL_PARAM settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; @@ -1404,6 +1446,8 @@ static const OSSL_PARAM settable_ctx_params_no_digest[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 6e5c027a223df..43eb63f1fd780 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -67,6 +67,7 @@ my %params = ( 'ALG_PARAM_ENGINE' => "engine", # utf8_string 'ALG_PARAM_MAC' => "mac", # utf8_string 'ALG_PARAM_PROPERTIES' => "properties", # utf8_string + 'ALG_PARAM_FIPS_APPROVED_INDICATOR' => 'fips-indicator', # int, -1, 0 or 1 # cipher parameters 'CIPHER_PARAM_PADDING' => "padding", # uint @@ -191,6 +192,8 @@ my %params = ( 'KDF_PARAM_ARGON2_LANES' => "lanes", # uint32_t 'KDF_PARAM_ARGON2_MEMCOST' => "memcost", # uint32_t 'KDF_PARAM_ARGON2_VERSION' => "version", # uint32_t + 'KDF_PARAM_FIPS_EMS_CHECK' => "ems_check", # int + 'KDF_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Known RAND names 'RAND_PARAM_STATE' => "state", @@ -216,6 +219,8 @@ my %params = ( 'DRBG_PARAM_CIPHER' => '*ALG_PARAM_CIPHER', 'DRBG_PARAM_MAC' => '*ALG_PARAM_MAC', 'DRBG_PARAM_USE_DF' => "use_derivation_function", + 'DRBG_PARAM_FIPS_DIGEST_CHECK' => '*PKEY_PARAM_FIPS_DIGEST_CHECK', + 'DRBG_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # DRBG call back parameters 'DRBG_PARAM_ENTROPY_REQUIRED' => "entropy_required", @@ -247,6 +252,8 @@ my %params = ( 'PKEY_PARAM_PUB_KEY' => "pub", 'PKEY_PARAM_PRIV_KEY' => "priv", 'PKEY_PARAM_IMPLICIT_REJECTION' => "implicit-rejection", + 'PKEY_PARAM_FIPS_DIGEST_CHECK' => "digest-check", + 'PKEY_PARAM_FIPS_KEY_CHECK' => "key-check", # Diffie-Hellman/DSA Parameters 'PKEY_PARAM_FFC_P' => "p", @@ -374,6 +381,9 @@ my %params = ( 'EXCHANGE_PARAM_KDF_OUTLEN' => "kdf-outlen",# size_t # The following parameter is an octet_string on set and an octet_ptr on get 'EXCHANGE_PARAM_KDF_UKM' => "kdf-ukm", + 'EXCHANGE_PARAM_FIPS_DIGEST_CHECK' => '*PKEY_PARAM_FIPS_DIGEST_CHECK', + 'EXCHANGE_PARAM_FIPS_KEY_CHECK' => '*PKEY_PARAM_FIPS_KEY_CHECK', + 'EXCHANGE_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Signature parameters 'SIGNATURE_PARAM_ALGORITHM_ID' => "algorithm-id", @@ -387,6 +397,9 @@ my %params = ( 'SIGNATURE_PARAM_NONCE_TYPE' => "nonce-type", 'SIGNATURE_PARAM_INSTANCE' => "instance", 'SIGNATURE_PARAM_CONTEXT_STRING' => "context-string", + 'SIGNATURE_PARAM_FIPS_DIGEST_CHECK' => '*PKEY_PARAM_FIPS_DIGEST_CHECK', + 'SIGNATURE_PARAM_FIPS_KEY_CHECK' => '*PKEY_PARAM_FIPS_KEY_CHECK', + 'SIGNATURE_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Asym cipher parameters 'ASYM_CIPHER_PARAM_DIGEST' => '*PKEY_PARAM_DIGEST', @@ -402,6 +415,8 @@ my %params = ( 'ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION' => "tls-client-version", 'ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION' => "tls-negotiated-version", 'ASYM_CIPHER_PARAM_IMPLICIT_REJECTION' => "implicit-rejection", + 'ASYM_CIPHER_PARAM_FIPS_KEY_CHECK' => '*PKEY_PARAM_FIPS_KEY_CHECK', + 'ASYM_CIPHER_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Encoder / decoder parameters @@ -436,6 +451,8 @@ my %params = ( # KEM parameters 'KEM_PARAM_OPERATION' => "operation", 'KEM_PARAM_IKME' => "ikme", + 'KEM_PARAM_FIPS_KEY_CHECK' => '*PKEY_PARAM_FIPS_KEY_CHECK', + 'KEM_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Capabilities From 06da14737369e7c90899aed4bb21cce9a0910d29 Mon Sep 17 00:00:00 2001 From: slontis Date: Wed, 3 Jul 2024 11:12:39 +1000 Subject: [PATCH 138/138] Add FIPS indicators to evp_test evp_test code needed to be modified to defer setting algorithm contexts until the run phase. The parse functions also defer setting into the context until the run phase, which allows the context to initialize in a controlled order. This allows params to be passed into the algorithm init function. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24623) --- test/evp_test.c | 792 ++++++++++++++---- .../30-test_evp_data/evpkdf_tls12_prf.txt | 22 + test/recipes/30-test_evp_data/evppkey_dsa.txt | 45 +- test/recipes/30-test_evp_data/evppkey_ecc.txt | 11 +- .../recipes/30-test_evp_data/evppkey_ecdh.txt | 2 +- .../30-test_evp_data/evppkey_ecdsa.txt | 48 +- .../30-test_evp_data/evppkey_ffdhe.txt | 16 +- test/recipes/30-test_evp_data/evppkey_kas.txt | 2 +- test/recipes/30-test_evp_data/evppkey_rsa.txt | 37 +- .../30-test_evp_data/evppkey_rsa_common.txt | 58 +- test/recipes/30-test_evp_data/evprand.txt | 38 + util/libcrypto.num | 2 + 12 files changed, 895 insertions(+), 178 deletions(-) diff --git a/test/evp_test.c b/test/evp_test.c index 71fea6f47ffa8..9ebcd29e09fa6 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -45,6 +45,7 @@ typedef struct evp_test_st { char *expected_err; /* Expected error value of test */ char *reason; /* Expected error reason string */ void *data; /* test specific data */ + int expect_unapproved; } EVP_TEST; /* Test method structure */ @@ -82,6 +83,7 @@ typedef enum OPTION_choice { static OSSL_PROVIDER *prov_null = NULL; static OSSL_PROVIDER *libprov = NULL; static OSSL_LIB_CTX *libctx = NULL; +static int fips_indicator_callback_unapproved_count = 0; /* List of public and private keys */ static KEY_LIST *private_keys; @@ -97,6 +99,162 @@ static int is_mac_disabled(const char *name); static int is_cipher_disabled(const char *name); static int is_kdf_disabled(const char *name); +/* A callback that is triggered if fips unapproved mode is detected */ +static int fips_indicator_cb(const char *type, const char *desc, + const OSSL_PARAM params[]) +{ + fips_indicator_callback_unapproved_count++; + TEST_info("(Indicator Callback received %s : %s is not approved)", type, desc); + return 1; +} + +static int check_fips_approved(EVP_TEST *t, int approved) +{ + /* + * If the expected result is approved + * then it is expected that approved will be 1 + * and the fips indicator callback has not been triggered, otherwise + * approved should be 0 and the fips indicator callback should be triggered. + */ + if (t->expect_unapproved) { + if (approved == 1 || fips_indicator_callback_unapproved_count == 0) + return 0; + } else { + if (approved == 0 || fips_indicator_callback_unapproved_count > 0) + return 0; + } + return 1; +} + +static int pkey_check_fips_approved(EVP_PKEY_CTX *ctx, EVP_TEST *t) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + /* + * For any getters that do not handle the FIPS indicator assume a default + * value of approved. + */ + int approved = 1; + + params[0] = OSSL_PARAM_construct_int(OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR, + &approved); + if (!EVP_PKEY_CTX_get_params(ctx, params)) + return 0; + return check_fips_approved(t, approved); +} + +static int rand_check_fips_approved(EVP_RAND_CTX *ctx, EVP_TEST *t) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + /* + * For any getters that do not handle the FIPS indicator assume a default + * value of approved. + */ + int approved = 1; + + params[0] = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_FIPS_APPROVED_INDICATOR, + &approved); + if (!EVP_RAND_CTX_get_params(ctx, params)) + return 0; + return check_fips_approved(t, approved); +} + +static int ctrladd(STACK_OF(OPENSSL_STRING) *controls, const char *value) +{ + char *data = OPENSSL_strdup(value); + + if (data == NULL) + return -1; + return sk_OPENSSL_STRING_push(controls, data) > 0; +} + +/* Because OPENSSL_free is a macro, it can't be passed as a function pointer */ +static void openssl_free(char *m) +{ + OPENSSL_free(m); +} + +static void ctrlfree(STACK_OF(OPENSSL_STRING) *controls) +{ + sk_OPENSSL_STRING_pop_free(controls, openssl_free); +} + +/* + * This is used if ctrl2params() passes settables as NULL. + * A default list of settable OSSL_PARAM that may be set during an operations + * init(). + * Using the algorithms settable list is problematic since it requires that the + * init() has already run. + */ +static const OSSL_PARAM settable_ctx_params[] = { + OSSL_PARAM_int("key-check", NULL), + OSSL_PARAM_int("digest-check", NULL), + OSSL_PARAM_int("ems_check", NULL), + OSSL_PARAM_END +}; + +static int ctrl2params(EVP_TEST *t, STACK_OF(OPENSSL_STRING) *controls, + const OSSL_PARAM *settables, + OSSL_PARAM params[], size_t params_sz, size_t *params_n) +{ + int i; + + if (settables == NULL) + settables = settable_ctx_params; + /* check bounds */ + if (*params_n + sk_OPENSSL_STRING_num(controls) >= params_sz) { + t->err = "ERR_TOO_MANY_PARAMETERS"; + goto err; + } + for (i = 0; i < sk_OPENSSL_STRING_num(controls); i++) { + char *tmpkey, *tmpval; + char *value = sk_OPENSSL_STRING_value(controls, i); + + if (!TEST_ptr(tmpkey = OPENSSL_strdup(value))) { + t->err = "ERR_PARAM_ERROR"; + goto err; + } + tmpval = strchr(tmpkey, ':'); + if (tmpval != NULL) + *tmpval++ = '\0'; + + if (tmpval == NULL + || !OSSL_PARAM_allocate_from_text(¶ms[*params_n], + settables, + tmpkey, tmpval, + strlen(tmpval), NULL)) { + OPENSSL_free(tmpkey); + t->err = "ERR_PARAM_ERROR"; + goto err; + } + *params_n += 1; + OPENSSL_free(tmpkey); + } + params[*params_n] = OSSL_PARAM_construct_end(); + return 1; +err: + return 0; +} + +static void ctrl2params_free(OSSL_PARAM params[], + size_t params_n, size_t params_n_allocstart) +{ + while (params_n-- > params_n_allocstart) { + OPENSSL_free(params[params_n].data); + } +} + +static int kdf_check_fips_approved(EVP_KDF_CTX *ctx, EVP_TEST *t) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + int approved = 1; + + params[0] = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR, + &approved); + if (!EVP_KDF_CTX_get_params(ctx, params)) + return 0; + return check_fips_approved(t, approved); +} + /* * Compare two memory regions for equality, returning zero if they differ. * However, if there is expected to be an error and the actual error @@ -1421,12 +1579,6 @@ static int mac_test_init(EVP_TEST *t, const char *alg) return 1; } -/* Because OPENSSL_free is a macro, it can't be passed as a function pointer */ -static void openssl_free(char *m) -{ - OPENSSL_free(m); -} - static void mac_test_cleanup(EVP_TEST *t) { MAC_DATA *mdat = t->data; @@ -1470,13 +1622,8 @@ static int mac_test_parse(EVP_TEST *t, return mdata->xof = 1; if (strcmp(keyword, "NoReinit") == 0) return mdata->no_reinit = 1; - if (strcmp(keyword, "Ctrl") == 0) { - char *data = OPENSSL_strdup(value); - - if (data == NULL) - return -1; - return sk_OPENSSL_STRING_push(mdata->controls, data) != 0; - } + if (strcmp(keyword, "Ctrl") == 0) + return ctrladd(mdata->controls, value); if (strcmp(keyword, "OutputSize") == 0) { mdata->output_size = atoi(value); if (mdata->output_size < 0) @@ -1643,8 +1790,8 @@ static int mac_test_run_mac(EVP_TEST *t) unsigned char *got = NULL; size_t got_len = 0, size = 0; size_t size_before_init = 0, size_after_init, size_val = 0; - int i, block_size = -1, output_size = -1; - OSSL_PARAM params[21], sizes[3], *psizes = sizes; + int block_size = -1, output_size = -1; + OSSL_PARAM params[21], sizes[3], *psizes = sizes, *p; size_t params_n = 0; size_t params_n_allocstart = 0; const OSSL_PARAM *defined_params = @@ -1710,42 +1857,14 @@ static int mac_test_run_mac(EVP_TEST *t) expected->iv, expected->iv_len); - /* Unknown controls. They must match parameters that the MAC recognizes */ - if (params_n + sk_OPENSSL_STRING_num(expected->controls) - >= OSSL_NELEM(params)) { - t->err = "MAC_TOO_MANY_PARAMETERS"; - goto err; - } params_n_allocstart = params_n; - for (i = 0; i < sk_OPENSSL_STRING_num(expected->controls); i++) { - char *tmpkey, *tmpval; - char *value = sk_OPENSSL_STRING_value(expected->controls, i); - - if (!TEST_ptr(tmpkey = OPENSSL_strdup(value))) { - t->err = "MAC_PARAM_ERROR"; - goto err; - } - tmpval = strchr(tmpkey, ':'); - if (tmpval != NULL) - *tmpval++ = '\0'; - - if (tmpval == NULL - || !OSSL_PARAM_allocate_from_text(¶ms[params_n], - defined_params, - tmpkey, tmpval, - strlen(tmpval), NULL)) { - OPENSSL_free(tmpkey); - t->err = "MAC_PARAM_ERROR"; - goto err; - } - params_n++; - - if (strcmp(tmpkey, "size") == 0) - size_val = (size_t)strtoul(tmpval, NULL, 0); + if (!ctrl2params(t, expected->controls, defined_params, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; - OPENSSL_free(tmpkey); - } - params[params_n] = OSSL_PARAM_construct_end(); + p = OSSL_PARAM_locate(params + params_n_allocstart, "size"); + if (p != NULL) + OSSL_PARAM_get_size_t(p, &size_val); if ((ctx = EVP_MAC_CTX_new(expected->mac)) == NULL) { t->err = "MAC_CREATE_ERROR"; @@ -1894,9 +2013,7 @@ static int mac_test_run_mac(EVP_TEST *t) } } err: - while (params_n-- > params_n_allocstart) { - OPENSSL_free(params[params_n].data); - } + ctrl2params_free(params, params_n, params_n_allocstart); EVP_MAC_CTX_free(ctx); OPENSSL_free(got); return 1; @@ -1919,6 +2036,217 @@ static const EVP_TEST_METHOD mac_test_method = { mac_test_run }; +typedef struct kem_data_st { + /* Context for this operation */ + EVP_PKEY_CTX *ctx; + const char *op; + /* Input to decapsulate */ + unsigned char *input; + size_t inputlen; + /* Expected secret */ + unsigned char *output; + size_t outputlen; + STACK_OF(OPENSSL_STRING) *init_ctrls; +} KEM_DATA; + +static int kem_test_init(EVP_TEST *t, const char *name) +{ + KEM_DATA *kdata = NULL; + EVP_PKEY *pkey = NULL; + int rv; + + rv = find_key(&pkey, name, private_keys); + if (rv == 0 || pkey == NULL) { + TEST_info("skipping, key '%s' is disabled", name); + t->skip = 1; + return 1; + } + + if (!TEST_ptr(kdata = OPENSSL_zalloc(sizeof(*kdata)))) + goto err; + if (!TEST_ptr(kdata->ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propquery))) + goto err; + + t->data = kdata; + kdata->init_ctrls = sk_OPENSSL_STRING_new_null(); + return 1; +err: + EVP_PKEY_free(pkey); + OPENSSL_free(kdata); + return 0; +} + +static void kem_test_cleanup(EVP_TEST *t) +{ + KEM_DATA *kdata = t->data; + + ctrlfree(kdata->init_ctrls); + OPENSSL_free(kdata->input); + OPENSSL_free(kdata->output); + EVP_PKEY_CTX_free(kdata->ctx); +} + +static int kem_test_parse(EVP_TEST *t, const char *keyword, const char *value) +{ + KEM_DATA *kdata = t->data; + + if (strcmp(keyword, "Op") == 0) { + kdata->op = value; + return 1; + } + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(kdata->init_ctrls, value); + if (strcmp(keyword, "Input") == 0) + return parse_bin(value, &kdata->input, &kdata->inputlen); + if (strcmp(keyword, "Output") == 0) + return parse_bin(value, &kdata->output, &kdata->outputlen); + return 1; +} + +static int encapsulate(EVP_TEST *t, EVP_PKEY_CTX *ctx, const char *op, + unsigned char **outwrapped, size_t *outwrappedlen, + unsigned char **outsecret, size_t *outsecretlen) +{ + int ret = 1; + KEM_DATA *kdata = t->data; + unsigned char *wrapped = NULL, *secret = NULL; + size_t wrappedlen = 0, secretlen = 0; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t params_n = 0, params_n_allocated = 0; + OSSL_PARAM *p = NULL; + + if (sk_OPENSSL_STRING_num(kdata->init_ctrls) > 0) { + if (ctrl2params(t, kdata->init_ctrls, NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + p = params; + } + if (EVP_PKEY_encapsulate_init(ctx, p) <= 0) { + t->err = "TEST_ENCAPSULATE_INIT_ERROR"; + goto err; + } + + if (EVP_PKEY_CTX_set_kem_op(ctx, op) <= 0) { + t->err = "TEST_SET_KEM_OP_ERROR"; + goto err; + } + if (EVP_PKEY_encapsulate(ctx, NULL, &wrappedlen, NULL, &secretlen) <= 0) { + t->err = "TEST_ENCAPSULATE_LEN_ERROR"; + goto err; + } + wrapped = OPENSSL_malloc(wrappedlen); + secret = OPENSSL_malloc(secretlen); + if (!TEST_ptr(wrapped) || !TEST_ptr(secret)) { + ret = 0; + goto err; + } + if (EVP_PKEY_encapsulate(ctx, wrapped, &wrappedlen, secret, &secretlen) <= 0) { + t->err = "TEST_ENCAPSULATE_ERROR"; + goto err; + } + ret = pkey_check_fips_approved(ctx, t); + if (ret == 0) + goto err; + + t->err = NULL; + *outwrapped = wrapped; + *outsecret = secret; + *outwrappedlen = wrappedlen; + *outsecretlen = secretlen; + ret = 1; + goto end; +err: + OPENSSL_free(wrapped); + OPENSSL_free(secret); +end: + ctrl2params_free(params, params_n, params_n_allocated); + return ret; +} + +static int decapsulate(EVP_TEST *t, EVP_PKEY_CTX *ctx, const char *op, + const unsigned char *in, size_t inlen, + const unsigned char *expected, size_t expectedlen) +{ + int ret = 1; + KEM_DATA *kdata = t->data; + size_t outlen = 0; + unsigned char *out = NULL; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + OSSL_PARAM *p = NULL; + size_t params_n = 0, params_n_allocated = 0; + + if (sk_OPENSSL_STRING_num(kdata->init_ctrls) > 0) { + if (!ctrl2params(t, kdata->init_ctrls, NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + p = params; + } + if (EVP_PKEY_decapsulate_init(ctx, p) <= 0) { + t->err = "TEST_DECAPSULATE_INIT_ERROR"; + goto err; + } + + if (EVP_PKEY_CTX_set_kem_op(ctx, op) <= 0) { + t->err = "TEST_SET_KEM_OP_ERROR"; + goto err; + } + if (EVP_PKEY_decapsulate(ctx, NULL, &outlen, in, inlen) <= 0) { + t->err = "TEST_DECAPSULATE_LEN_ERROR"; + goto err; + } + if (!TEST_ptr(out = OPENSSL_malloc(outlen))) { + ret = 0; + goto err; + } + + if (EVP_PKEY_decapsulate(ctx, out, &outlen, in, inlen) <= 0) { + t->err = "TEST_DECAPSULATE_ERROR"; + goto err; + } + if (!TEST_mem_eq(out, outlen, expected, expectedlen)) { + t->err = "TEST_SECRET_MISMATCH"; + goto err; + } + t->err = NULL; + ret = 1; +err: + OPENSSL_free(out); + ctrl2params_free(params, params_n, params_n_allocated); + return ret; +} + +static int kem_test_run(EVP_TEST *t) +{ + int ret = 0; + KEM_DATA *kdata = t->data; + unsigned char *wrapped = NULL, *secret = NULL; + + if (kdata->input == NULL) { + size_t wrappedlen = 0, secretlen = 0; + + ret = encapsulate(t, kdata->ctx, kdata->op, &wrapped, &wrappedlen, + &secret, &secretlen); + if (ret == 0 || t->err != NULL) + goto err; + ret = decapsulate(t, kdata->ctx, kdata->op, wrapped, wrappedlen, + secret, secretlen); + } else { + ret = decapsulate(t, kdata->ctx, kdata->op, kdata->input, kdata->inputlen, + kdata->output, kdata->outputlen); + } +err: + OPENSSL_free(wrapped); + OPENSSL_free(secret); + return ret; +} + +static const EVP_TEST_METHOD pkey_kem_test_method = { + "Kem", + kem_test_init, + kem_test_cleanup, + kem_test_parse, + kem_test_run +}; /** ** PUBLIC KEY TESTS @@ -1929,6 +2257,7 @@ typedef struct pkey_data_st { /* Context for this operation */ EVP_PKEY_CTX *ctx; /* Key operation to perform */ + int (*keyopinit) (EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]); int (*keyop) (EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); @@ -1938,6 +2267,10 @@ typedef struct pkey_data_st { /* Expected output */ unsigned char *output; size_t output_len; + STACK_OF(OPENSSL_STRING) *init_controls; /* collection of controls */ + STACK_OF(OPENSSL_STRING) *controls; /* collection of controls */ + EVP_PKEY *peer; + int validate; } PKEY_DATA; /* @@ -1946,7 +2279,8 @@ typedef struct pkey_data_st { */ static int pkey_test_init(EVP_TEST *t, const char *name, int use_public, - int (*keyopinit) (EVP_PKEY_CTX *ctx), + int (*keyopinit) (EVP_PKEY_CTX *ctx, + const OSSL_PARAM params[]), int (*keyop)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, @@ -1970,15 +2304,16 @@ static int pkey_test_init(EVP_TEST *t, const char *name, EVP_PKEY_free(pkey); return 0; } + kdata->keyopinit = keyopinit; kdata->keyop = keyop; if (!TEST_ptr(kdata->ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propquery))) { EVP_PKEY_free(pkey); OPENSSL_free(kdata); return 0; } - if (keyopinit(kdata->ctx) <= 0) - t->err = "KEYOP_INIT_ERROR"; t->data = kdata; + kdata->init_controls = sk_OPENSSL_STRING_new_null(); + kdata->controls = sk_OPENSSL_STRING_new_null(); return 1; } @@ -1986,6 +2321,8 @@ static void pkey_test_cleanup(EVP_TEST *t) { PKEY_DATA *kdata = t->data; + ctrlfree(kdata->init_controls); + ctrlfree(kdata->controls); OPENSSL_free(kdata->input); OPENSSL_free(kdata->output); EVP_PKEY_CTX_free(kdata->ctx); @@ -2021,6 +2358,27 @@ static int pkey_test_ctrl(EVP_TEST *t, EVP_PKEY_CTX *pctx, return rv > 0; } +static int pkey_add_control(EVP_TEST *t, STACK_OF(OPENSSL_STRING) *controls, + const char *value) +{ + char *p; + + if (controls == NULL) + return 0; + + p = strchr(value, ':'); + if (p == NULL) + return 0; + p++; + if (is_digest_disabled(p) || is_cipher_disabled(p)) { + TEST_info("skipping, '%s' is disabled", p); + t->skip = 1; + return 1; + } + + return ctrladd(controls, value) > 0; +} + static int pkey_test_parse(EVP_TEST *t, const char *keyword, const char *value) { @@ -2029,11 +2387,45 @@ static int pkey_test_parse(EVP_TEST *t, return parse_bin(value, &kdata->input, &kdata->input_len); if (strcmp(keyword, "Output") == 0) return parse_bin(value, &kdata->output, &kdata->output_len); + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(kdata->init_controls, value); if (strcmp(keyword, "Ctrl") == 0) - return pkey_test_ctrl(t, kdata->ctx, value); + return pkey_add_control(t, kdata->controls, value); return 0; } +static int pkey_test_run_init(EVP_TEST *t) +{ + PKEY_DATA *data = t->data; + int i, ret = 0; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + OSSL_PARAM *p = NULL; + size_t params_n = 0, params_n_allocstart = 0; + + if (sk_OPENSSL_STRING_num(data->init_controls) > 0) { + if (!ctrl2params(t, data->init_controls, + NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + p = params; + } + if (data->keyopinit(data->ctx, p) <= 0) { + t->err = "KEYOP_INIT_ERROR"; + goto err; + } + + for (i = 0; i < sk_OPENSSL_STRING_num(data->controls); i++) { + char *value = sk_OPENSSL_STRING_value(data->controls, i); + + if (!pkey_test_ctrl(t, data->ctx, value) || t->err != NULL) + goto err; + } + ret = 1; +err: + ctrl2params_free(params, params_n, params_n_allocstart); + return ret; +} + static int pkey_test_run(EVP_TEST *t) { PKEY_DATA *expected = t->data; @@ -2041,6 +2433,9 @@ static int pkey_test_run(EVP_TEST *t) size_t got_len; EVP_PKEY_CTX *copy = NULL; + if (!pkey_test_run_init(t)) + goto err; + if (expected->keyop(expected->ctx, NULL, &got_len, expected->input, expected->input_len) <= 0 || !TEST_ptr(got = OPENSSL_malloc(got_len))) { @@ -2090,7 +2485,7 @@ static int pkey_test_run(EVP_TEST *t) static int sign_test_init(EVP_TEST *t, const char *name) { - return pkey_test_init(t, name, 0, EVP_PKEY_sign_init, EVP_PKEY_sign); + return pkey_test_init(t, name, 0, EVP_PKEY_sign_init_ex, EVP_PKEY_sign); } static const EVP_TEST_METHOD psign_test_method = { @@ -2103,7 +2498,7 @@ static const EVP_TEST_METHOD psign_test_method = { static int verify_recover_test_init(EVP_TEST *t, const char *name) { - return pkey_test_init(t, name, 1, EVP_PKEY_verify_recover_init, + return pkey_test_init(t, name, 1, EVP_PKEY_verify_recover_init_ex, EVP_PKEY_verify_recover); } @@ -2117,7 +2512,7 @@ static const EVP_TEST_METHOD pverify_recover_test_method = { static int decrypt_test_init(EVP_TEST *t, const char *name) { - return pkey_test_init(t, name, 0, EVP_PKEY_decrypt_init, + return pkey_test_init(t, name, 0, EVP_PKEY_decrypt_init_ex, EVP_PKEY_decrypt); } @@ -2131,16 +2526,19 @@ static const EVP_TEST_METHOD pdecrypt_test_method = { static int verify_test_init(EVP_TEST *t, const char *name) { - return pkey_test_init(t, name, 1, EVP_PKEY_verify_init, 0); + return pkey_test_init(t, name, 1, EVP_PKEY_verify_init_ex, NULL); } static int verify_test_run(EVP_TEST *t) { PKEY_DATA *kdata = t->data; + if (!pkey_test_run_init(t)) + goto err; if (EVP_PKEY_verify(kdata->ctx, kdata->output, kdata->output_len, kdata->input, kdata->input_len) <= 0) t->err = "VERIFY_ERROR"; +err: return 1; } @@ -2154,7 +2552,7 @@ static const EVP_TEST_METHOD pverify_test_method = { static int pderive_test_init(EVP_TEST *t, const char *name) { - return pkey_test_init(t, name, 0, EVP_PKEY_derive_init, 0); + return pkey_test_init(t, name, 0, EVP_PKEY_derive_init_ex, 0); } static int pderive_test_parse(EVP_TEST *t, @@ -2167,65 +2565,20 @@ static int pderive_test_parse(EVP_TEST *t, validate = 1; if (validate || strcmp(keyword, "PeerKey") == 0) { - EVP_PKEY *peer; + EVP_PKEY *peer = NULL; + + kdata->validate = validate; if (find_key(&peer, value, public_keys) == 0) return -1; - if (EVP_PKEY_derive_set_peer_ex(kdata->ctx, peer, validate) <= 0) { - t->err = "DERIVE_SET_PEER_ERROR"; - return 1; - } - t->err = NULL; + kdata->peer = peer; return 1; } if (strcmp(keyword, "SharedSecret") == 0) return parse_bin(value, &kdata->output, &kdata->output_len); if (strcmp(keyword, "Ctrl") == 0) - return pkey_test_ctrl(t, kdata->ctx, value); - if (strcmp(keyword, "KDFType") == 0) { - OSSL_PARAM params[2]; - - params[0] = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, - (char *)value, 0); - params[1] = OSSL_PARAM_construct_end(); - if (EVP_PKEY_CTX_set_params(kdata->ctx, params) == 0) - return -1; - return 1; - } - if (strcmp(keyword, "KDFDigest") == 0) { - OSSL_PARAM params[2]; - - params[0] = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, - (char *)value, 0); - params[1] = OSSL_PARAM_construct_end(); - if (EVP_PKEY_CTX_set_params(kdata->ctx, params) == 0) - return -1; - return 1; - } - if (strcmp(keyword, "CEKAlg") == 0) { - OSSL_PARAM params[2]; - - params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, - (char *)value, 0); - params[1] = OSSL_PARAM_construct_end(); - if (EVP_PKEY_CTX_set_params(kdata->ctx, params) == 0) - return -1; - return 1; - } - if (strcmp(keyword, "KDFOutlen") == 0) { - OSSL_PARAM params[2]; - char *endptr; - size_t outlen = (size_t)strtoul(value, &endptr, 0); - - if (endptr[0] != '\0') - return -1; - - params[0] = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, - &outlen); - params[1] = OSSL_PARAM_construct_end(); - if (EVP_PKEY_CTX_set_params(kdata->ctx, params) == 0) - return -1; - return 1; - } + return pkey_add_control(t, kdata->controls, value); + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(kdata->init_controls, value); return 0; } @@ -2236,6 +2589,16 @@ static int pderive_test_run(EVP_TEST *t) unsigned char *got = NULL; size_t got_len; + if (!pkey_test_run_init(t)) + goto err; + + t->err = NULL; + if (EVP_PKEY_derive_set_peer_ex(expected->ctx, expected->peer, + expected->validate) <= 0) { + t->err = "DERIVE_SET_PEER_ERROR"; + goto err; + } + if (!TEST_ptr(dctx = EVP_PKEY_CTX_dup(expected->ctx))) { t->err = "DERIVE_ERROR"; goto err; @@ -2274,7 +2637,6 @@ static const EVP_TEST_METHOD pderive_test_method = { pderive_test_run }; - /** ** PBE TESTS **/ @@ -2707,6 +3069,7 @@ typedef struct rand_data_st { unsigned int generate_bits; char *cipher; char *digest; + STACK_OF(OPENSSL_STRING) *init_controls; /* collection of controls */ /* Expected output */ RAND_DATA_PASS data[MAX_RAND_REPEATS]; @@ -2742,6 +3105,7 @@ static int rand_test_init(EVP_TEST *t, const char *name) EVP_RAND_free(rand); if (rdata->ctx == NULL) goto err; + rdata->init_controls = sk_OPENSSL_STRING_new_null(); rdata->n = -1; t->data = rdata; @@ -2757,6 +3121,7 @@ static void rand_test_cleanup(EVP_TEST *t) RAND_DATA *rdata = t->data; int i; + ctrlfree(rdata->init_controls); OPENSSL_free(rdata->cipher); OPENSSL_free(rdata->digest); @@ -2832,6 +3197,8 @@ static int rand_test_parse(EVP_TEST *t, rdata->prediction_resistance = atoi(value) != 0; return 1; } + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(rdata->init_controls, value); } return 0; } @@ -2842,14 +3209,23 @@ static int rand_test_run(EVP_TEST *t) RAND_DATA_PASS *item; unsigned char *got; size_t got_len = expected->generate_bits / 8; - OSSL_PARAM params[5], *p = params; + OSSL_PARAM params[8], *p = params; int i = -1, ret = 0; unsigned int strength; unsigned char *z; + size_t params_n = 0, params_allocated_n = 0; if (!TEST_ptr(got = OPENSSL_malloc(got_len))) return 0; + if (sk_OPENSSL_STRING_num(expected->init_controls) > 0) { + if (!ctrl2params(t, expected->init_controls, + NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + } + p = params + params_n; + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &expected->use_df); if (expected->cipher != NULL) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, @@ -2859,8 +3235,15 @@ static int rand_test_run(EVP_TEST *t) expected->digest, 0); *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, "HMAC", 0); *p = OSSL_PARAM_construct_end(); - if (!TEST_true(EVP_RAND_CTX_set_params(expected->ctx, params))) + if (!EVP_RAND_CTX_set_params(expected->ctx, params)) { + if (t->expect_unapproved == 0) { + t->err = "EVP_RAND_CTX_set_params"; + ret = 1; + } goto err; + } + ctrl2params_free(params, params_n, params_allocated_n); + params_n = 0; strength = EVP_RAND_get_strength(expected->ctx); for (i = 0; i <= expected->n; i++) { @@ -2928,6 +3311,8 @@ static int rand_test_run(EVP_TEST *t) goto err; if (!TEST_mem_eq(got, got_len, item->output, item->output_len)) goto err; + if (!rand_check_fips_approved(expected->ctx, t)) + goto err; if (!TEST_true(EVP_RAND_uninstantiate(expected->ctx)) || !TEST_true(EVP_RAND_uninstantiate(expected->parent)) || !TEST_true(EVP_RAND_verify_zeroization(expected->ctx)) @@ -2942,6 +3327,7 @@ static int rand_test_run(EVP_TEST *t) if (ret == 0 && i >= 0) TEST_info("Error in test case %d of %d\n", i, expected->n + 1); OPENSSL_free(got); + ctrl2params_free(params, params_n, params_allocated_n); return ret; } @@ -2953,7 +3339,6 @@ static const EVP_TEST_METHOD rand_test_method = { rand_test_run }; - /** ** KDF TESTS **/ @@ -2965,6 +3350,7 @@ typedef struct kdf_data_st { size_t output_len; OSSL_PARAM params[20]; OSSL_PARAM *p; + STACK_OF(OPENSSL_STRING) *init_controls; /* collection of controls */ } KDF_DATA; /* @@ -2999,6 +3385,7 @@ static int kdf_test_init(EVP_TEST *t, const char *name) return 0; } t->data = kdata; + kdata->init_controls = sk_OPENSSL_STRING_new_null(); return 1; } @@ -3007,6 +3394,7 @@ static void kdf_test_cleanup(EVP_TEST *t) KDF_DATA *kdata = t->data; OSSL_PARAM *p; + ctrlfree(kdata->init_controls); for (p = kdata->params; p->key != NULL; p++) OPENSSL_free(p->data); OPENSSL_free(kdata->output); @@ -3118,6 +3506,8 @@ static int kdf_test_parse(EVP_TEST *t, if (strcmp(keyword, "Output") == 0) return parse_bin(value, &kdata->output, &kdata->output_len); + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(kdata->init_controls, value); if (HAS_PREFIX(keyword, "Ctrl")) return kdf_test_ctrl(t, kdata->ctx, value); return 0; @@ -3125,14 +3515,28 @@ static int kdf_test_parse(EVP_TEST *t, static int kdf_test_run(EVP_TEST *t) { + int ret = 1; KDF_DATA *expected = t->data; unsigned char *got = NULL; size_t got_len = expected->output_len; EVP_KDF_CTX *ctx; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t params_n = 0, params_allocated_n = 0; + + if (sk_OPENSSL_STRING_num(expected->init_controls) > 0) { + if (!ctrl2params(t, expected->init_controls, + NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + if (!EVP_KDF_CTX_set_params(expected->ctx, params)) { + t->err = "KDF_CTRL_ERROR"; + goto err; + } + } if (!EVP_KDF_CTX_set_params(expected->ctx, expected->params)) { t->err = "KDF_CTRL_ERROR"; - return 1; + goto err; } if (!TEST_ptr(got = OPENSSL_malloc(got_len == 0 ? 1 : got_len))) { t->err = "INTERNAL_ERROR"; @@ -3148,6 +3552,10 @@ static int kdf_test_run(EVP_TEST *t) t->err = "KDF_DERIVE_ERROR"; goto err; } + if (!kdf_check_fips_approved(expected->ctx, t)) { + ret = 0; + goto err; + } if (!memory_err_compare(t, "KDF_MISMATCH", expected->output, expected->output_len, got, got_len)) @@ -3156,8 +3564,9 @@ static int kdf_test_run(EVP_TEST *t) t->err = NULL; err: + ctrl2params_free(params, params_n, params_allocated_n); OPENSSL_free(got); - return 1; + return ret; } static const EVP_TEST_METHOD kdf_test_method = { @@ -3533,7 +3942,10 @@ typedef struct { size_t osin_len; /* Input length data if one shot */ unsigned char *output; /* Expected output */ size_t output_len; /* Expected output length */ - const char *nonce_type; + int deterministic_noncetype; + EVP_PKEY *key; + STACK_OF(OPENSSL_STRING) *init_controls; /* collection of controls */ + STACK_OF(OPENSSL_STRING) *controls; /* Collection of controls */ } DIGESTSIGN_DATA; static int digestsigver_test_init(EVP_TEST *t, const char *alg, int is_verify, @@ -3553,6 +3965,8 @@ static int digestsigver_test_init(EVP_TEST *t, const char *alg, int is_verify, } if (!TEST_ptr(mdat = OPENSSL_zalloc(sizeof(*mdat)))) return 0; + mdat->init_controls = sk_OPENSSL_STRING_new_null(); + mdat->controls = sk_OPENSSL_STRING_new_null(); mdat->md = md; if (!TEST_ptr(mdat->ctx = EVP_MD_CTX_new())) { OPENSSL_free(mdat); @@ -3573,6 +3987,8 @@ static void digestsigver_test_cleanup(EVP_TEST *t) { DIGESTSIGN_DATA *mdata = t->data; + ctrlfree(mdata->init_controls); + ctrlfree(mdata->controls); EVP_MD_CTX_free(mdata->ctx); sk_EVP_TEST_BUFFER_pop_free(mdata->input, evp_test_buffer_free); OPENSSL_free(mdata->osin); @@ -3589,7 +4005,6 @@ static int digestsigver_test_parse(EVP_TEST *t, if (strcmp(keyword, "Key") == 0) { EVP_PKEY *pkey = NULL; int rv = 0; - const char *name = mdata->md == NULL ? NULL : EVP_MD_get0_name(mdata->md); if (mdata->is_verify) rv = find_key(&pkey, value, public_keys); @@ -3599,15 +4014,7 @@ static int digestsigver_test_parse(EVP_TEST *t, t->skip = 1; return 1; } - if (mdata->is_verify) { - if (!EVP_DigestVerifyInit_ex(mdata->ctx, &mdata->pctx, name, libctx, - NULL, pkey, NULL)) - t->err = "DIGESTVERIFYINIT_ERROR"; - return 1; - } - if (!EVP_DigestSignInit_ex(mdata->ctx, &mdata->pctx, name, libctx, NULL, - pkey, NULL)) - t->err = "DIGESTSIGNINIT_ERROR"; + mdata->key = pkey; return 1; } @@ -3625,34 +4032,83 @@ static int digestsigver_test_parse(EVP_TEST *t, if (strcmp(keyword, "Ncopy") == 0) return evp_test_buffer_ncopy(value, mdata->input); } - if (strcmp(keyword, "Ctrl") == 0) { - if (mdata->pctx == NULL) - return -1; - return pkey_test_ctrl(t, mdata->pctx, value); - } + if (strcmp(keyword, "Ctrl") == 0) + return pkey_add_control(t, mdata->controls, value); + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(mdata->init_controls, value); if (strcmp(keyword, "NonceType") == 0) { - if (strcmp(value, "deterministic") == 0) { - OSSL_PARAM params[2]; - unsigned int nonce_type = 1; - - params[0] = - OSSL_PARAM_construct_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, - &nonce_type); - params[1] = OSSL_PARAM_construct_end(); - if (!EVP_PKEY_CTX_set_params(mdata->pctx, params)) - t->err = "EVP_PKEY_CTX_set_params_ERROR"; - else if (!EVP_PKEY_CTX_get_params(mdata->pctx, params)) - t->err = "EVP_PKEY_CTX_get_params_ERROR"; - else if (!OSSL_PARAM_modified(¶ms[0])) - t->err = "nonce_type_not_modified_ERROR"; - else if (nonce_type != 1) - t->err = "nonce_type_value_ERROR"; - } + if (strcmp(value, "deterministic") == 0) + mdata->deterministic_noncetype = 1; return 1; } return 0; } +static int check_deterministic_noncetype(EVP_TEST *t, + DIGESTSIGN_DATA *mdata) +{ + if (mdata->deterministic_noncetype == 1) { + OSSL_PARAM params[2]; + unsigned int nonce_type = 1; + + params[0] = + OSSL_PARAM_construct_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, + &nonce_type); + params[1] = OSSL_PARAM_construct_end(); + if (!EVP_PKEY_CTX_set_params(mdata->pctx, params)) + t->err = "EVP_PKEY_CTX_set_params_ERROR"; + else if (!EVP_PKEY_CTX_get_params(mdata->pctx, params)) + t->err = "EVP_PKEY_CTX_get_params_ERROR"; + else if (!OSSL_PARAM_modified(¶ms[0])) + t->err = "nonce_type_not_modified_ERROR"; + else if (nonce_type != 1) + t->err = "nonce_type_value_ERROR"; + } + return t->err == NULL; +} + +static int signverify_init(EVP_TEST *t, DIGESTSIGN_DATA *data) +{ + const char *name = data->md == NULL ? NULL : EVP_MD_get0_name(data->md); + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + OSSL_PARAM *p = NULL; + int i, ret = 0; + size_t params_n = 0, params_allocated_n = 0; + + if (sk_OPENSSL_STRING_num(data->init_controls) > 0) { + if (!ctrl2params(t, data->init_controls, + NULL, + params, OSSL_NELEM(params), ¶ms_n)) + goto err; + p = params; + } + + if (data->is_verify) { + if (!EVP_DigestVerifyInit_ex(data->ctx, &data->pctx, name, libctx, + NULL, data->key, p)) { + t->err = "DIGESTVERIFYINIT_ERROR"; + goto err; + } + } else { + if (!EVP_DigestSignInit_ex(data->ctx, &data->pctx, name, libctx, NULL, + data->key, p)) { + t->err = "DIGESTSIGNINIT_ERROR"; + goto err; + } + } + + for (i = 0; i < sk_OPENSSL_STRING_num(data->controls); i++) { + char *value = sk_OPENSSL_STRING_value(data->controls, i); + + if (!pkey_test_ctrl(t, data->pctx, value) || t->err != NULL) + goto err; + } + ret = 1; +err: + ctrl2params_free(params, params_n, params_allocated_n); + return ret; +} + static int digestsign_update_fn(void *ctx, const unsigned char *buf, size_t buflen) { @@ -3661,10 +4117,22 @@ static int digestsign_update_fn(void *ctx, const unsigned char *buf, static int digestsign_test_run(EVP_TEST *t) { + int i; DIGESTSIGN_DATA *expected = t->data; unsigned char *got = NULL; size_t got_len; + if (!signverify_init(t, expected)) + goto err; + if (!check_deterministic_noncetype(t, expected)) + goto err; + + for (i = 0; i < sk_OPENSSL_STRING_num(expected->controls); i++) { + char *value = sk_OPENSSL_STRING_value(expected->controls, i); + if (!pkey_test_ctrl(t, expected->pctx, value) || t->err != NULL) + return 0; + } + if (!evp_test_buffer_do(expected->input, digestsign_update_fn, expected->ctx)) { t->err = "DIGESTUPDATE_ERROR"; @@ -3718,6 +4186,9 @@ static int digestverify_test_run(EVP_TEST *t) { DIGESTSIGN_DATA *mdata = t->data; + if (!signverify_init(t, mdata)) + return 1; + if (!evp_test_buffer_do(mdata->input, digestverify_update_fn, mdata->ctx)) { t->err = "DIGESTUPDATE_ERROR"; return 1; @@ -3748,6 +4219,9 @@ static int oneshot_digestsign_test_run(EVP_TEST *t) unsigned char *got = NULL; size_t got_len; + if (!signverify_init(t, expected)) + goto err; + if (!EVP_DigestSign(expected->ctx, NULL, &got_len, expected->osin, expected->osin_len)) { t->err = "DIGESTSIGN_LENGTH_ERROR"; @@ -3791,6 +4265,9 @@ static int oneshot_digestverify_test_run(EVP_TEST *t) { DIGESTSIGN_DATA *mdata = t->data; + if (!signverify_init(t, mdata)) + return 1; + if (EVP_DigestVerify(mdata->ctx, mdata->output, mdata->output_len, mdata->osin, mdata->osin_len) <= 0) t->err = "VERIFY_ERROR"; @@ -3830,6 +4307,7 @@ static const EVP_TEST_METHOD *evp_test_list[] = { &psign_test_method, &pverify_recover_test_method, &pverify_test_method, + &pkey_kem_test_method, NULL }; @@ -3863,6 +4341,7 @@ static void clear_test(EVP_TEST *t) t->err = NULL; t->skip = 0; t->meth = NULL; + t->expect_unapproved = 0; #if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL) OSSL_set_max_threads(libctx, 0); @@ -4085,6 +4564,7 @@ static int parse(EVP_TEST *t) PAIR *pp; int i, j, skipped = 0; + fips_indicator_callback_unapproved_count = 0; top: do { if (BIO_eof(t->s.fp)) @@ -4185,6 +4665,11 @@ static int parse(EVP_TEST *t) t->skip = 1; return 0; } + } else { + TEST_info("skipping, FIPS provider not active: %s:%d", + t->s.test_file, t->s.start); + t->skip = 1; + return 0; } skipped++; pp++; @@ -4258,6 +4743,8 @@ static int parse(EVP_TEST *t) pp->value, t->s.test_file, t->s.start); t->skip = 1; } + } else if (strcmp(pp->key, "Unapproved") == 0) { + t->expect_unapproved = 1; } else { /* Must be test specific line: try to parse it */ int rv = t->meth->parse(t, pp->key, pp->value); @@ -4292,6 +4779,7 @@ static int run_file_tests(int i) return 0; } + OSSL_INDICATOR_set_callback(libctx, fips_indicator_cb); while (!BIO_eof(t->s.fp)) { c = parse(t); if (t->skip) { diff --git a/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt b/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt index 44040ff66b481..09720e7dcaf67 100644 --- a/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt +++ b/test/recipes/30-test_evp_data/evpkdf_tls12_prf.txt @@ -47,3 +47,25 @@ Ctrl.Secret = hexsecret:01 Ctrl.Seed = hexseed:02 Output = 03 Result = KDF_DERIVE_ERROR + +# Test that "master secret" is not not used in FIPS mode +FIPSversion = >=3.4.0 +KDF = TLS1-PRF +Ctrl.digest = digest:SHA256 +Ctrl.Secret = hexsecret:f8938ecc9edebc5030c0c6a441e213cd24e6f770a50dda07876f8d55da062bcadb386b411fd4fe4313a604fce6c17fbc +Ctrl.label = seed:master secret +Ctrl.client_random = hexseed:36c129d01a3200894b9179faac589d9835d58775f9b5ea3587cb8fd0364cae8c +Ctrl.server_random = hexseed:f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce +Result = KDF_DERIVE_ERROR + +# FIPS indicator callback test +FIPSversion = >=3.4.0 +KDF = TLS1-PRF +Unapproved = 1 +CtrlInit = ems_check:0 +Ctrl.digest = digest:SHA256 +Ctrl.Secret = hexsecret:f8938ecc9edebc5030c0c6a441e213cd24e6f770a50dda07876f8d55da062bcadb386b411fd4fe4313a604fce6c17fbc +Ctrl.label = seed:master secret +Ctrl.client_random = hexseed:36c129d01a3200894b9179faac589d9835d58775f9b5ea3587cb8fd0364cae8c +Ctrl.server_random = hexseed:f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce +Output = 202c88c00f84a17a20027079604787461176455539e705be730890602c289a5001e34eeb3a043e5d52a65e66125188bf diff --git a/test/recipes/30-test_evp_data/evppkey_dsa.txt b/test/recipes/30-test_evp_data/evppkey_dsa.txt index debd62bca84cb..5cc5f015e6806 100644 --- a/test/recipes/30-test_evp_data/evppkey_dsa.txt +++ b/test/recipes/30-test_evp_data/evppkey_dsa.txt @@ -334,7 +334,7 @@ Result = DIGESTSIGNINIT_ERROR Availablein = fips DigestSign = SHA1 Securitycheck = 1 -Key = DSA-2048 +Key = DSA-2048-256 Input = "Hello" Result = DIGESTSIGNINIT_ERROR @@ -353,3 +353,46 @@ Securitycheck = 1 Key = DSA-4096-256 Input = "Hello" Result = DIGESTSIGNINIT_ERROR + +Title = Fips Indicator Tests +# Check that the indicator callback is triggered + +# Test sign with a 1024 bit key in fips mode +FIPSversion = >=3.4.0 +DigestSign = SHA256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = DSA-1024-FIPS186-2 +Input = "Hello" +Result = SIGNATURE_MISMATCH + +# Test sign with a 3072 bit key with N == 224 is not allowed in fips mode +FIPSversion = >=3.4.0 +DigestSign = SHA256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = DSA-3072-224 +Input = "Hello" +Result = SIGNATURE_MISMATCH + +# Test sign with a 4096 bit key is not allowed in fips mode +FIPSversion = >=3.4.0 +DigestSign = SHA256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = DSA-4096-256 +Input = "Hello" +Result = SIGNATURE_MISMATCH + +# Test sign with SHA1 is not allowed in fips mode +FIPSversion = >=3.4.0 +DigestSign = SHA1 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = digest-check:0 +Key = DSA-2048-256 +Input = "Hello" +Result = SIGNATURE_MISMATCH diff --git a/test/recipes/30-test_evp_data/evppkey_ecc.txt b/test/recipes/30-test_evp_data/evppkey_ecc.txt index 6ea11db668315..8264496a40706 100644 --- a/test/recipes/30-test_evp_data/evppkey_ecc.txt +++ b/test/recipes/30-test_evp_data/evppkey_ecc.txt @@ -3594,7 +3594,16 @@ Derive=BOB_cf_prime192v1 Securitycheck = 1 PeerKey=ALICE_cf_prime192v1_PUB SharedSecret=e36cad3b0f8d00f60f090440a76df47896713ae61421c354 -Result = DERIVE_SET_PEER_ERROR +Result = KEYOP_INIT_ERROR + +# Check the indicator callback is triggered +FIPSversion = >=3.4.0 +Derive=BOB_cf_prime192v1 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +PeerKey=ALICE_cf_prime192v1_PUB +SharedSecret=e36cad3b0f8d00f60f090440a76df47896713ae61421c354 Title=prime256v1 curve tests diff --git a/test/recipes/30-test_evp_data/evppkey_ecdh.txt b/test/recipes/30-test_evp_data/evppkey_ecdh.txt index d50b2d166eb7a..eae84e4b107f2 100644 --- a/test/recipes/30-test_evp_data/evppkey_ecdh.txt +++ b/test/recipes/30-test_evp_data/evppkey_ecdh.txt @@ -2710,7 +2710,7 @@ Availablein = fips Derive=ALICE_prime192v1 Securitycheck = 1 PeerKey=BOB_prime192v1_PUB -Result = DERIVE_SET_PEER_ERROR +Result = KEYOP_INIT_ERROR # ECDH Bob with Alice peer diff --git a/test/recipes/30-test_evp_data/evppkey_ecdsa.txt b/test/recipes/30-test_evp_data/evppkey_ecdsa.txt index 1543ed9f7534b..cca8c0694547e 100644 --- a/test/recipes/30-test_evp_data/evppkey_ecdsa.txt +++ b/test/recipes/30-test_evp_data/evppkey_ecdsa.txt @@ -37,34 +37,34 @@ PrivPubKeyPair = P-256:P-256-PUBLIC Title = ECDSA tests -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF1234" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8 # Digest too long -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF12345" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8 Result = VERIFY_ERROR # Digest too short -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF123" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8 Result = VERIFY_ERROR # Digest invalid -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF1235" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec8 Result = VERIFY_ERROR # Invalid signature -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF1234" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec7 @@ -72,14 +72,14 @@ Result = VERIFY_ERROR # Garbage after signature Availablein = default -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF1234" Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec800 Result = VERIFY_ERROR # BER signature -Verify = P-256 +Verify = P-256-PUBLIC Ctrl = digest:SHA1 Input = "0123456789ABCDEF1234" Output = 3080022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec80000 @@ -185,7 +185,6 @@ Title = FIPS Negative tests (using different curves and digests) # Test that a explicit curve is not allowed in fips mode Availablein = fips DigestVerify = SHA256 -Securitycheck = 1 Key = EC_EXPLICIT Input = "Hello World" Result = DIGESTVERIFYINIT_ERROR @@ -228,3 +227,36 @@ DigestVerify = MD5 Securitycheck = 1 Key = P-256-PUBLIC Result = DIGESTVERIFYINIT_ERROR + +Title = FIPS Indicator tests +# Check that the indicator callback is triggered +# We check for signature mismatch since the signature is unique + +FIPSversion = >=3.4.0 +DigestSign = SHA3-512 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = B-163 +Input = "Hello World" +Result = SIGNATURE_MISMATCH + +# Test that SHA1 is not allowed in fips mode for signing +FIPSversion = >=3.4.0 +DigestSign = SHA1 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = digest-check:0 +Key = P-256 +Input = "Hello World" +Result = SIGNATURE_MISMATCH + +# Test that SHA1 is not allowed in fips mode for signing +FIPSversion = >=3.4.0 +Sign = P-256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = digest-check:0 +Ctrl = digest:SHA1 +Input = "0123456789ABCDEF1234" +Result = KEYOP_MISMATCH diff --git a/test/recipes/30-test_evp_data/evppkey_ffdhe.txt b/test/recipes/30-test_evp_data/evppkey_ffdhe.txt index b6b1a8e8a090c..2e17571e9e5a5 100644 --- a/test/recipes/30-test_evp_data/evppkey_ffdhe.txt +++ b/test/recipes/30-test_evp_data/evppkey_ffdhe.txt @@ -98,10 +98,10 @@ SharedSecret=00006620DD85B56EE8540C8040CAC46B7385344A164E4DBDF521F7D99F88FA68EDD # The plain shared secret for these keys needs padding as seen above. Derive=ffdhe2048-1 PeerKey=ffdhe2048-2-pub -KDFType=X942KDF-ASN1 -KDFOutlen=32 -KDFDigest=SHA-256 -CEKAlg=id-aes128-wrap +Ctrl = kdf-type:X942KDF-ASN1 +Ctrl = kdf-outlen:32 +Ctrl = kdf-digest:SHA-256 +Ctrl = cekalg:AES-128-WRAP Ctrl = dh_pad:1 SharedSecret=89A249DF4EE9033B89C2B4E52072A736D94F51143A1ED5C8F1E91FCBEBE09654 @@ -109,10 +109,10 @@ SharedSecret=89A249DF4EE9033B89C2B4E52072A736D94F51143A1ED5C8F1E91FCBEBE09654 FIPSversion = >3.0.0 Derive=ffdhe2048-2 PeerKey=ffdhe2048-1-pub -KDFType=X942KDF-ASN1 -KDFOutlen=32 -KDFDigest=SHA-256 -CEKAlg=id-aes128-wrap +Ctrl = kdf-type:X942KDF-ASN1 +Ctrl = kdf-outlen:32 +Ctrl = kdf-digest:SHA-256 +Ctrl = cekalg:AES-128-WRAP Ctrl = dh_pad:0 SharedSecret=89A249DF4EE9033B89C2B4E52072A736D94F51143A1ED5C8F1E91FCBEBE09654 diff --git a/test/recipes/30-test_evp_data/evppkey_kas.txt b/test/recipes/30-test_evp_data/evppkey_kas.txt index ba1049628f94a..8933273a59e64 100644 --- a/test/recipes/30-test_evp_data/evppkey_kas.txt +++ b/test/recipes/30-test_evp_data/evppkey_kas.txt @@ -54,7 +54,7 @@ Availablein = fips Derive=KAS-ECC-CDH_P-192_C0 Securitycheck = 1 PeerKey=KAS-ECC-CDH_P-192_C0-Peer-PUBLIC -Result = DERIVE_SET_PEER_ERROR +Result = KEYOP_INIT_ERROR PrivateKey=KAS-ECC-CDH_P-192_C1 -----BEGIN PRIVATE KEY----- diff --git a/test/recipes/30-test_evp_data/evppkey_rsa.txt b/test/recipes/30-test_evp_data/evppkey_rsa.txt index 78d14d31be10f..b36a19f4fd086 100644 --- a/test/recipes/30-test_evp_data/evppkey_rsa.txt +++ b/test/recipes/30-test_evp_data/evppkey_rsa.txt @@ -599,7 +599,6 @@ Ctrl = rsa_mgf1_md:sha1 Input=65033bc2f67d6aba7d526acb873b8d9241e5e4d9 Output=1ed1d848fb1edb44129bd9b354795af97a069a7a00d0151048593e0c72c3517ff9ff2a41d0cb5a0ac860d736a199704f7cb6a53986a88bbd8abcc0076a2ce847880031525d449da2ac78356374c536e343faa7cba42a5aaa6506087791c06a8e989335aed19bfab2d5e67e27fb0c2875af896c21b6e8e7309d04e4f6727e69463e - Title = RSA DigestSign and DigestVerify DigestSign = SHA1 @@ -613,7 +612,6 @@ Key = RSA-2048 Input = "Hello World" Output = 3da3ca2bdd1b23a231b0e3c49d95d5959f9398c27a1e534c7e6baf1d2682304d3b6b229385b1edf483f5ef6f9b35bf10c519a302bb2f79c564e1a59ba71aa2fa36df96c942c43e8d9bd4702b5f61c12a078ae2b34d0de221fc8f9f936b79a67c89d11ba5da8c63a1370d0e824c6b661123e9b58b143ff533cf362cbdad70e65b419a6d45723bf22db3c76bb8f5337c5c5c93cb6f38b30d0c835b54c23405ca4217dd0b755f3712ebad285d9e0c02655f6ce5ce6fed78f3c81843de325f628055eef57f280dee0c3170050137ee599b9ab7f2b5d3c5f831777ea05a5eb097c70bad1a7214dadae12d7960bb9425390c7d25a79985e1e3c28ad422ff93c808f4b5 - Title = Test RSA keygen # Key generation tests @@ -623,3 +621,38 @@ Ctrl = rsa_keygen_bits:128 KeyName = tmprsa Result = PKEY_CTRL_ERROR Reason = key size too small + +Title = Test RSASVE (KEM) + +# RSA Encapsulate/Decapsulate +Kem = RSA-2048 +Op = RSASVE + +# RSA Decapsulate +Kem = RSA-2048 +Op = RSASVE +Input = 431937b777ae3ddda69da20ea602aeb76f87a7e120f24ff2bf7757de4302413fd875eb740d5ea108d0bce1102d9f0ec1613aa433ab33164afeb06b531334e4a0ea0965a4ef1c06ad783ce5799a35a62c1f8926b878be7400bd39a35a144ddccb1161f9b22891afb84bff8c31028fee69eaeca4c73d9d1dc0db371d52f33c950d7a3d51c2032567d07e1c2af36b4a4e13af04ba165ca3242cafcc2e1778ff205ede37397c1b71aa88ff16927b2ed6e7b04fd980b9a9392ce7ce902c11ac22e0d72633eb6d0b85c766e22a5f80bca7161d7bf544af4790b3d2af0d7631faf6204c3908be1072d52a5be47687cad09a978b856f4d72e659650adccd05b343630d7b +Output = 01fd95c07b4f4888f4efaf6d69d9309f677b4c0cd2179f10572e4576163c25046917340e8c5098f64d580f56614856a4c46e7e14843a62f5c387b0b30f09d456302534bfa2c944af66bb8a172ea3064d59ed9855797436ea70e218ef59181c6497222819cb1903cdf6febc6d484f1cb8a44946ee7be9e734e6423c83d4aaf509d84980292fe996000d34c9727146157a422110047b7441e0ecd81824b96e09a5fe3a1f0a46099625aeb0a3712e991293a7401bc01dca8bb5e72aaee9a9367ff3294ca158b64404a651c2fd3bab21178e54f27dd0ca25f64f3a6f44a284f8687459a7e453e6c3cc8c2f58da214047d7c416167923b6d6c61d5988e96dff15fad9 + +# Test small RSA keys are not allowed for Encapsulation in FIPS mode +FIPSversion = >=3.4.0 +Kem = RSA-512 +Securitycheck = 1 +Op = RSASVE +Result = TEST_ENCAPSULATE_INIT_ERROR + +# Test small RSA keys are not allowed for Decapsulation in FIPS mode +FIPSversion = >=3.4.0 +Kem = RSA-512 +Securitycheck = 1 +Op = RSASVE +Input = 431937b777ae3ddda69da20ea602aeb76f87a7e120f24ff2bf7757de4302413fd875eb740d5ea108d0bce1102d9f0ec1613aa433ab33164afeb06b531334e4a0ea0965a4ef1c06ad783ce5799a35a62c1f8926b878be7400bd39a35a144ddccb1161f9b22891afb84bff8c31028fee69eaeca4c73d9d1dc0db371d52f33c950d +Result = TEST_DECAPSULATE_INIT_ERROR + +# Test FIPS indicator callback is triggered +FIPSversion = >=3.4.0 +Kem = RSA-512 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Op = RSASVE diff --git a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt index 9cc007ad7b195..da0d7cd77b31c 100644 --- a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt +++ b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt @@ -1915,6 +1915,13 @@ Title = RSA FIPS tests # FIPS tests +# Decrypt with small RSA key is not permitted in FIPS mode +Availablein = fips +Decrypt = RSA-512 +Securitycheck = 1 +Input = 550AF55A2904E7B9762352F8FB7FA235A9CB053AACB2D5FCB8CA48453CB2EE3619746C701ABF2D4CC67003471A187900B05AA812BD25ED05C675DFC8C97A24A7BF49BD6214992CAD766D05A9A2B57B74F26A737E0237B8B76C45F1F226A836D7CFBC75BA999BDBE48DBC09227AA46C88F21DCCBA7840141AD5A5D71FD122E6BD6AC3E564780DFE623FC1CA9B995A6037BF0BBD43B205A84AC5444F34202C05CE9113087176432476576DE6FFFF9A52EA57C08BE3EC2F49676CB8E12F762AC71FA3C321E00AC988910C85FF52F93825666CE0D40FFAA0592078919D4493F46D95CCF76364C6D57760DD0B64805F9AFC76A2365A5575CA301D5103F0EA76CB9A78 +Result = KEYOP_INIT_ERROR + # Verifying with SHA1 is permitted in fips mode for older applications DigestVerify = SHA1 Key = RSA-2048 @@ -1928,7 +1935,7 @@ Input = "Hello" Output = 80382819f51b197c42f9fc02a85198683d918059afc013ae155992442563dd2897008297fecb3a8d8cf9421d493a99bd427a628f17cc4a7c76d23dfad0619f4068403fa7351f6d5a92a631d670c04407f305a4b5cb492295754e73e9b7ad41459826d3619a61e90d4744bdaf0f24f2393ea9241e973600c2ed62b1a0a37c504e # Signing with SHA1 is not allowed in fips mode -Availablein = fips +FIPSversion = >=3.4.0 DigestSign = SHA1 Securitycheck = 1 Key = RSA-2048 @@ -1936,7 +1943,7 @@ Input = "Hello" Result = DIGESTSIGNINIT_ERROR # Signing with a 1024 bit key is not allowed in fips mode -Availablein = fips +FIPSversion = >=3.4.0 DigestSign = SHA256 Securitycheck = 1 Key = RSA-1024 @@ -1944,7 +1951,7 @@ Input = "Hello" Result = DIGESTSIGNINIT_ERROR # Verifying with a legacy digest in fips mode is not allowed -Availablein = fips +FIPSversion = >=3.4.0 DigestVerify = MD5 Securitycheck = 1 Key = RSA-2048 @@ -1952,9 +1959,52 @@ Input = "Hello" Result = DIGESTVERIFYINIT_ERROR # Verifying with a key smaller than 1024 bits in fips mode is not allowed -Availablein = fips +FIPSversion = >=3.4.0 DigestVerify = SHA256 Securitycheck = 1 Key = RSA-512 Input = "Hello" Result = DIGESTVERIFYINIT_ERROR + +################################################## +# Check that the indicator callback is triggered + +Title = RSA FIPS Indicator tests + +# Decrypt with small RSA key is not permitted in FIPS mode +FIPSversion = >=3.4.0 +Decrypt = RSA-512 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Input = 550AF55A2904E7B9762352F8FB7FA235 +Result = KEYOP_MISMATCH + +# Signing with SHA1 is not allowed in fips mode +FIPSversion = >=3.4.0 +DigestSign = SHA1 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = digest-check:0 +Key = RSA-2048 +Input = "Hello" +Result = SIGNATURE_MISMATCH + +FIPSversion = >=3.4.0 +DigestSign = SHA256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = RSA-1024 +Input = "Hello" +Result = SIGNATURE_MISMATCH + +# Verifying with a key smaller than 1024 bits in fips mode is not allowed +FIPSversion = >=3.4.0 +DigestVerify = SHA256 +Securitycheck = 1 +Unapproved = 1 +CtrlInit = key-check:0 +Key = RSA-512 +Input = "Hello" +Result = VERIFY_ERROR diff --git a/test/recipes/30-test_evp_data/evprand.txt b/test/recipes/30-test_evp_data/evprand.txt index 0e2ee82c587a0..b4516f5e61127 100644 --- a/test/recipes/30-test_evp_data/evprand.txt +++ b/test/recipes/30-test_evp_data/evprand.txt @@ -79776,3 +79776,41 @@ EntropyPredictionResistanceA.14 = d7842e7ad0cbac6b9404e8e942fabb77974b353a7f9633 AdditionalInputB.14 = 0155dc73a36c160d9e13c023e732798b4fba3a9fd849c0edf899765c5ff7349f EntropyPredictionResistanceB.14 = 96a30d8593cce5febd4f034ff97479eb8808e81bd7b8f7b44ae945fbbf503572 Output.14 = ee191dc6bef025e36302bb8ce0e6a949f7b0d2944b246fc52d68a20c3b2b787595ca9d4bae2f55a13924fabbef8f700abc09d7dac1c1eb3a63c040867519e6724faeb532d01cd38922e4e0973566fc23f5fbc067f496cb97fe3ce97564f0010d6cd2b5d81a3e79fcb85f010191a76b4d796ea8c85b119dd24210f64725c09689 + +Title = Test truncated Digests are not allowed in FIPS + +Availablein = fips +RAND = HASH-DRBG +Digest = SHA2-224 +GenerateBits = 16 +Result = EVP_RAND_CTX_set_params + +Availablein = fips +RAND = HMAC-DRBG +Digest = SHA2-384 +GenerateBits = 16 +Result = EVP_RAND_CTX_set_params + +Title = Test FIPS indicator callbacks for truncated digests + +FIPSversion = >=3.4.0 +RAND = HASH-DRBG +Unapproved = 1 +CtrlInit = digest-check:0 +Digest = SHA2-224 +PredictionResistance = 0 +GenerateBits = 16 +Entropy.0 = c3ef82ce241f02e4298b118ca4f1622515e32abbae6b7433 +Nonce.0 = 15e32abbae6b7433 +Output.0 = 5af6 + +FIPSversion = >=3.4.0 +RAND = HMAC-DRBG +Unapproved = 1 +CtrlInit = digest-check:0 +Digest = SHA2-384 +PredictionResistance = 0 +GenerateBits = 16 +Entropy.0 = 32c1ca125223de8de569697f92a37c6732c1ca125223de8de569697f92a37c67 +Nonce.0 = 15e32abbae6b7433 +Output.0 = ee9f diff --git a/util/libcrypto.num b/util/libcrypto.num index a553a9ae74864..e434b95d46039 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5700,3 +5700,5 @@ i2d_OSSL_USER_NOTICE_SYNTAX ? 3_4_0 EXIST::FUNCTION: OSSL_USER_NOTICE_SYNTAX_free ? 3_4_0 EXIST::FUNCTION: OSSL_USER_NOTICE_SYNTAX_new ? 3_4_0 EXIST::FUNCTION: OSSL_USER_NOTICE_SYNTAX_it ? 3_4_0 EXIST::FUNCTION: +OSSL_INDICATOR_set_callback ? 3_4_0 EXIST::FUNCTION: +OSSL_INDICATOR_get_callback ? 3_4_0 EXIST::FUNCTION: