From 66dddb942c099ca52b8140f5e3dd9aded64f6a3c Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 25 Oct 2023 12:06:55 +0200 Subject: [PATCH] Fix incorrect cipher key and IV length processing (CVE-2023-5363) Resolves: RHEL-13251 --- 0128-CVE-2023-5363.patch | 318 +++++++++++++++++++++++++++++++++++++++ openssl.spec | 3 + 2 files changed, 321 insertions(+) create mode 100644 0128-CVE-2023-5363.patch diff --git a/0128-CVE-2023-5363.patch b/0128-CVE-2023-5363.patch new file mode 100644 index 0000000..8610da0 --- /dev/null +++ b/0128-CVE-2023-5363.patch @@ -0,0 +1,318 @@ +diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c +index d2ed3fd378..6a819590e6 100644 +--- a/crypto/evp/evp_enc.c ++++ b/crypto/evp/evp_enc.c +@@ -223,6 +223,42 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + return 0; + } + ++#ifndef FIPS_MODULE ++ /* ++ * Fix for CVE-2023-5363 ++ * Passing in a size as part of the init call takes effect late ++ * so, force such to occur before the initialisation. ++ * ++ * The FIPS provider's internal library context is used in a manner ++ * such that this is not an issue. ++ */ ++ if (params != NULL) { ++ OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, ++ OSSL_PARAM_END }; ++ OSSL_PARAM *q = param_lens; ++ const OSSL_PARAM *p; ++ ++ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); ++ if (p != NULL) ++ memcpy(q++, p, sizeof(*q)); ++ ++ /* ++ * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for ++ * OSSL_CIPHER_PARAM_IVLEN so both are covered here. ++ */ ++ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); ++ if (p != NULL) ++ memcpy(q++, p, sizeof(*q)); ++ ++ if (q != param_lens) { ++ if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); ++ return 0; ++ } ++ } ++ } ++#endif ++ + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c +index cfffa21350..2318bf6a68 100644 +--- a/test/evp_extra_test.c ++++ b/test/evp_extra_test.c +@@ -4851,6 +4851,253 @@ static int test_ecx_not_private_key(int tst) + return options; + } + ++static int aes_gcm_encrypt(const unsigned char *gcm_key, size_t gcm_key_s, ++ const unsigned char *gcm_iv, size_t gcm_ivlen, ++ const unsigned char *gcm_pt, size_t gcm_pt_s, ++ const unsigned char *gcm_aad, size_t gcm_aad_s, ++ const unsigned char *gcm_ct, size_t gcm_ct_s, ++ const unsigned char *gcm_tag, size_t gcm_tag_s) ++{ ++ int ret = 0; ++ EVP_CIPHER_CTX *ctx; ++ EVP_CIPHER *cipher = NULL; ++ int outlen, tmplen; ++ unsigned char outbuf[1024]; ++ unsigned char outtag[16]; ++ OSSL_PARAM params[2] = { ++ OSSL_PARAM_END, OSSL_PARAM_END ++ }; ++ ++ if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) ++ || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", ""))) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, ++ &gcm_ivlen); ++ ++ if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) ++ || (gcm_aad != NULL ++ && !TEST_true(EVP_EncryptUpdate(ctx, NULL, &outlen, ++ gcm_aad, gcm_aad_s))) ++ || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, ++ gcm_pt, gcm_pt_s)) ++ || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, ++ outtag, sizeof(outtag)); ++ ++ if (!TEST_true(EVP_CIPHER_CTX_get_params(ctx, params)) ++ || !TEST_mem_eq(outbuf, outlen, gcm_ct, gcm_ct_s) ++ || !TEST_mem_eq(outtag, gcm_tag_s, gcm_tag, gcm_tag_s)) ++ goto err; ++ ++ ret = 1; ++err: ++ EVP_CIPHER_free(cipher); ++ EVP_CIPHER_CTX_free(ctx); ++ ++ return ret; ++} ++ ++static int aes_gcm_decrypt(const unsigned char *gcm_key, size_t gcm_key_s, ++ const unsigned char *gcm_iv, size_t gcm_ivlen, ++ const unsigned char *gcm_pt, size_t gcm_pt_s, ++ const unsigned char *gcm_aad, size_t gcm_aad_s, ++ const unsigned char *gcm_ct, size_t gcm_ct_s, ++ const unsigned char *gcm_tag, size_t gcm_tag_s) ++{ ++ int ret = 0; ++ EVP_CIPHER_CTX *ctx; ++ EVP_CIPHER *cipher = NULL; ++ int outlen; ++ unsigned char outbuf[1024]; ++ OSSL_PARAM params[2] = { ++ OSSL_PARAM_END, OSSL_PARAM_END ++ }; ++ ++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL) ++ goto err; ++ ++ if ((cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", "")) == NULL) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, ++ &gcm_ivlen); ++ ++ if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) ++ || (gcm_aad != NULL ++ && !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outlen, ++ gcm_aad, gcm_aad_s))) ++ || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, ++ gcm_ct, gcm_ct_s)) ++ || !TEST_mem_eq(outbuf, outlen, gcm_pt, gcm_pt_s)) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, ++ (void*)gcm_tag, gcm_tag_s); ++ ++ if (!TEST_true(EVP_CIPHER_CTX_set_params(ctx, params)) ++ ||!TEST_true(EVP_DecryptFinal_ex(ctx, outbuf, &outlen))) ++ goto err; ++ ++ ret = 1; ++err: ++ EVP_CIPHER_free(cipher); ++ EVP_CIPHER_CTX_free(ctx); ++ ++ return ret; ++} ++ ++static int test_aes_gcm_ivlen_change_cve_2023_5363(void) ++{ ++ /* AES-GCM test data obtained from NIST public test vectors */ ++ static const unsigned char gcm_key[] = { ++ 0xd0, 0xc2, 0x67, 0xc1, 0x9f, 0x30, 0xd8, 0x0b, 0x89, 0x14, 0xbb, 0xbf, ++ 0xb7, 0x2f, 0x73, 0xb8, 0xd3, 0xcd, 0x5f, 0x6a, 0x78, 0x70, 0x15, 0x84, ++ 0x8a, 0x7b, 0x30, 0xe3, 0x8f, 0x16, 0xf1, 0x8b, ++ }; ++ static const unsigned char gcm_iv[] = { ++ 0xb6, 0xdc, 0xda, 0x95, 0xac, 0x99, 0x77, 0x76, 0x25, 0xae, 0x87, 0xf8, ++ 0xa3, 0xa9, 0xdd, 0x64, 0xd7, 0x9b, 0xbd, 0x5f, 0x4a, 0x0e, 0x54, 0xca, ++ 0x1a, 0x9f, 0xa2, 0xe3, 0xf4, 0x5f, 0x5f, 0xc2, 0xce, 0xa7, 0xb6, 0x14, ++ 0x12, 0x6f, 0xf0, 0xaf, 0xfd, 0x3e, 0x17, 0x35, 0x6e, 0xa0, 0x16, 0x09, ++ 0xdd, 0xa1, 0x3f, 0xd8, 0xdd, 0xf3, 0xdf, 0x4f, 0xcb, 0x18, 0x49, 0xb8, ++ 0xb3, 0x69, 0x2c, 0x5d, 0x4f, 0xad, 0x30, 0x91, 0x08, 0xbc, 0xbe, 0x24, ++ 0x01, 0x0f, 0xbe, 0x9c, 0xfb, 0x4f, 0x5d, 0x19, 0x7f, 0x4c, 0x53, 0xb0, ++ 0x95, 0x90, 0xac, 0x7b, 0x1f, 0x7b, 0xa0, 0x99, 0xe1, 0xf3, 0x48, 0x54, ++ 0xd0, 0xfc, 0xa9, 0xcc, 0x91, 0xf8, 0x1f, 0x9b, 0x6c, 0x9a, 0xe0, 0xdc, ++ 0x63, 0xea, 0x7d, 0x2a, 0x4a, 0x7d, 0xa5, 0xed, 0x68, 0x57, 0x27, 0x6b, ++ 0x68, 0xe0, 0xf2, 0xb8, 0x51, 0x50, 0x8d, 0x3d, ++ }; ++ static const unsigned char gcm_pt[] = { ++ 0xb8, 0xb6, 0x88, 0x36, 0x44, 0xe2, 0x34, 0xdf, 0x24, 0x32, 0x91, 0x07, ++ 0x4f, 0xe3, 0x6f, 0x81, ++ }; ++ static const unsigned char gcm_ct[] = { ++ 0xff, 0x4f, 0xb3, 0xf3, 0xf9, 0xa2, 0x51, 0xd4, 0x82, 0xc2, 0xbe, 0xf3, ++ 0xe2, 0xd0, 0xec, 0xed, ++ }; ++ static const unsigned char gcm_tag[] = { ++ 0xbd, 0x06, 0x38, 0x09, 0xf7, 0xe1, 0xc4, 0x72, 0x0e, 0xf2, 0xea, 0x63, ++ 0xdb, 0x99, 0x6c, 0x21, ++ }; ++ ++ return aes_gcm_encrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), ++ gcm_pt, sizeof(gcm_pt), NULL, 0, ++ gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)) ++ && aes_gcm_decrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), ++ gcm_pt, sizeof(gcm_pt), NULL, 0, ++ gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)); ++} ++ ++#ifndef OPENSSL_NO_RC4 ++static int rc4_encrypt(const unsigned char *rc4_key, size_t rc4_key_s, ++ const unsigned char *rc4_pt, size_t rc4_pt_s, ++ const unsigned char *rc4_ct, size_t rc4_ct_s) ++{ ++ int ret = 0; ++ EVP_CIPHER_CTX *ctx; ++ EVP_CIPHER *cipher = NULL; ++ int outlen, tmplen; ++ unsigned char outbuf[1024]; ++ OSSL_PARAM params[2] = { ++ OSSL_PARAM_END, OSSL_PARAM_END ++ }; ++ ++ if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) ++ || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "RC4", ""))) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, ++ &rc4_key_s); ++ ++ if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) ++ || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, ++ rc4_pt, rc4_pt_s)) ++ || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) ++ goto err; ++ ++ if (!TEST_mem_eq(outbuf, outlen, rc4_ct, rc4_ct_s)) ++ goto err; ++ ++ ret = 1; ++err: ++ EVP_CIPHER_free(cipher); ++ EVP_CIPHER_CTX_free(ctx); ++ ++ return ret; ++} ++ ++static int rc4_decrypt(const unsigned char *rc4_key, size_t rc4_key_s, ++ const unsigned char *rc4_pt, size_t rc4_pt_s, ++ const unsigned char *rc4_ct, size_t rc4_ct_s) ++{ ++ int ret = 0; ++ EVP_CIPHER_CTX *ctx; ++ EVP_CIPHER *cipher = NULL; ++ int outlen; ++ unsigned char outbuf[1024]; ++ OSSL_PARAM params[2] = { ++ OSSL_PARAM_END, OSSL_PARAM_END ++ }; ++ ++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL) ++ goto err; ++ ++ if ((cipher = EVP_CIPHER_fetch(testctx, "RC4", "")) == NULL) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, ++ &rc4_key_s); ++ ++ if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) ++ || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, ++ rc4_ct, rc4_ct_s)) ++ || !TEST_mem_eq(outbuf, outlen, rc4_pt, rc4_pt_s)) ++ goto err; ++ ++ ret = 1; ++err: ++ EVP_CIPHER_free(cipher); ++ EVP_CIPHER_CTX_free(ctx); ++ ++ return ret; ++} ++ ++static int test_aes_rc4_keylen_change_cve_2023_5363(void) ++{ ++ /* RC4 test data obtained from RFC 6229 */ ++ static const struct { ++ unsigned char key[5]; ++ unsigned char padding[11]; ++ } rc4_key = { ++ { /* Five bytes of key material */ ++ 0x83, 0x32, 0x22, 0x77, 0x2a, ++ }, ++ { /* Random padding to 16 bytes */ ++ 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, 0xaa, 0x32, 0x91 ++ } ++ }; ++ static const unsigned char rc4_pt[] = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++ }; ++ static const unsigned char rc4_ct[] = { ++ 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, ++ 0x2e, 0x87, 0x9e, 0x92, 0xa4, 0x97, 0xef, 0xda ++ }; ++ ++ if (lgcyprov == NULL) ++ return TEST_skip("Test requires legacy provider to be loaded"); ++ ++ return rc4_encrypt(rc4_key.key, sizeof(rc4_key.key), ++ rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)) ++ && rc4_decrypt(rc4_key.key, sizeof(rc4_key.key), ++ rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)); ++} ++#endif ++ + int setup_tests(void) + { + OPTION_CHOICE o; +@@ -4994,6 +5241,12 @@ int setup_tests(void) + + ADD_ALL_TESTS(test_ecx_short_keys, OSSL_NELEM(ecxnids)); + ++ /* Test cases for CVE-2023-5363 */ ++ ADD_TEST(test_aes_gcm_ivlen_change_cve_2023_5363); ++#ifndef OPENSSL_NO_RC4 ++ ADD_TEST(test_aes_rc4_keylen_change_cve_2023_5363); ++#endif ++ + return 1; + } + diff --git a/openssl.spec b/openssl.spec index a59230a..92655b4 100644 --- a/openssl.spec +++ b/openssl.spec @@ -200,6 +200,7 @@ Patch123: 0123-ibmca-atexit-crash.patch Patch125: 0125-CVE-2023-2975.patch Patch126: 0126-CVE-2023-3446.patch Patch127: 0127-CVE-2023-3817.patch +Patch128: 0128-CVE-2023-5363.patch License: ASL 2.0 URL: http://www.openssl.org/ @@ -543,6 +544,8 @@ ln -s /etc/crypto-policies/back-ends/openssl_fips.config $RPM_BUILD_ROOT%{_sysco Resolves: RHEL-5306 - Excessive time spent checking DH q parameter value (CVE-2023-3817) Resolves: RHEL-5308 +- Fix incorrect cipher key and IV length processing (CVE-2023-5363) + Resolves: RHEL-13251 * Wed Jul 12 2023 Dmitry Belyavskiy - 1:3.0.7-24 - Make FIPS module configuration more crypto-policies friendly