From 4ba0fd1cec7922712de9d3a6685e88243599a7b6 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 12:56:02 -0700 Subject: [PATCH 01/42] Fix wrong variable in NULL check after EVP_CIPHER_meth_new for AES-CBC-HMAC --- src/we_aes_cbc_hmac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/we_aes_cbc_hmac.c b/src/we_aes_cbc_hmac.c index 8256269..7f89b35 100644 --- a/src/we_aes_cbc_hmac.c +++ b/src/we_aes_cbc_hmac.c @@ -577,10 +577,10 @@ int we_init_aescbc_hmac_meths(void) /* AES128-CBC HMAC-SHA256 */ we_aes128_cbc_hmac_ciph = EVP_CIPHER_meth_new(NID_aes_128_cbc_hmac_sha256, WC_AES_BLOCK_SIZE, AES_128_KEY_SIZE); - if (we_aes128_cbc_ciph == NULL) { + if (we_aes128_cbc_hmac_ciph == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_meth_new - AES-128-CBC " - "HMAC SHA256", we_aes128_cbc_ciph); + "HMAC SHA256", we_aes128_cbc_hmac_ciph); ret = 0; } if (ret == 1) { @@ -591,10 +591,10 @@ int we_init_aescbc_hmac_meths(void) if (ret == 1) { we_aes256_cbc_hmac_ciph = EVP_CIPHER_meth_new( NID_aes_256_cbc_hmac_sha256, WC_AES_BLOCK_SIZE, AES_256_KEY_SIZE); - if (we_aes256_cbc_ciph == NULL) { + if (we_aes256_cbc_hmac_ciph == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_meth_new - AES-256-CBC " - "HMAC SHA256", we_aes256_cbc_ciph); + "HMAC SHA256", we_aes256_cbc_hmac_ciph); ret = 0; } } From 7ed5e4418f4d1809c931b6f624d3eb5cc9f9d734 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 12:59:57 -0700 Subject: [PATCH 02/42] Validate record length in AES-CBC-HMAC TLS decrypt to prevent underflow --- src/we_aes_cbc_hmac.c | 10 ++++- test/test_cipher.c | 89 +++++++++++++++++++++++++++++++++++++++++++ test/unit.c | 1 + test/unit.h | 1 + 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/we_aes_cbc_hmac.c b/src/we_aes_cbc_hmac.c index 7f89b35..0feb123 100644 --- a/src/we_aes_cbc_hmac.c +++ b/src/we_aes_cbc_hmac.c @@ -297,8 +297,14 @@ static int we_aes_cbc_hmac_dec(we_AesCbcHmac* aes, unsigned char *out, ret = -1; } if (ret != -1) { - /* Remove padding and MAC length. */ - ret -= pb + 1 + SHA256_DIGEST_LENGTH; + /* Record must hold the padding and MAC or the length underflows. */ + if (ret < pb + 1 + SHA256_DIGEST_LENGTH) { + ret = -1; + } + else { + /* Remove padding and MAC length. */ + ret -= pb + 1 + SHA256_DIGEST_LENGTH; + } } /* Update record header to have correct message length. */ diff --git a/test/test_cipher.c b/test/test_cipher.c index d3cc3b6..a679aaa 100644 --- a/test/test_cipher.c +++ b/test/test_cipher.c @@ -481,6 +481,95 @@ int test_aes256_cbc_stream(ENGINE *e, void *data) return err; } +/******************************************************************************/ + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) +{ + int err = 0; + int outLen = 0; + int decLen = 0; + EVP_CIPHER_CTX *encCtx = NULL; + EVP_CIPHER_CTX *ctx = NULL; + const EVP_CIPHER *cipher = EVP_aes_128_cbc_hmac_sha256(); + unsigned char key[16]; + unsigned char macKey[SHA256_DIGEST_LENGTH]; + unsigned char iv[16]; + unsigned char zero[16]; + unsigned char record[32]; + unsigned char out[32]; + unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; + + (void)data; + + XMEMSET(key, 0, sizeof(key)); + XMEMSET(macKey, 0, sizeof(macKey)); + XMEMSET(iv, 0, sizeof(iv)); + XMEMSET(zero, 0, sizeof(zero)); + XMEMSET(out, 0, sizeof(out)); + XMEMSET(aad, 0, sizeof(aad)); + + /* Explicit IV is the first block of the record. */ + XMEMCPY(record, iv, sizeof(iv)); + + /* Craft a single ciphertext block that decrypts to all zeros so the + * recovered pad byte is 0 and the padding check passes. */ + err = (encCtx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_EncryptInit_ex(encCtx, EVP_aes_128_cbc(), NULL, key, iv) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_set_padding(encCtx, 0) != 1; + } + if (err == 0) { + err = EVP_EncryptUpdate(encCtx, record + 16, &outLen, zero, + sizeof(zero)) != 1; + } + EVP_CIPHER_CTX_free(encCtx); + + /* TLS 1.2 record header so the stitched cipher takes the explicit-IV + * path. */ + aad[9] = (unsigned char)(TLS1_2_VERSION >> 8); + aad[10] = (unsigned char)(TLS1_2_VERSION); + aad[11] = 0; + aad[12] = 16; + + if (err == 0) { + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + } + if (err == 0) { + err = EVP_DecryptInit_ex(ctx, cipher, e, key, iv) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_MAC_KEY, + sizeof(macKey), macKey) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, + EVP_AEAD_TLS1_AAD_LEN, aad) + != SHA256_DIGEST_LENGTH; + } + if (err == 0) { + /* Undersized, block-aligned record: explicit IV plus a single block, + * which is smaller than IV + pad + MAC. The engine must reject it and + * must not underflow the record length. */ + decLen = EVP_Cipher(ctx, out, record, sizeof(record)); + err = (decLen > 0); + } + + EVP_CIPHER_CTX_free(ctx); + + return err; +} +#else +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) +{ + (void)e; + (void)data; + return 0; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + #endif /* WE_HAVE_AESCBC */ /******************************************************************************/ diff --git a/test/unit.c b/test/unit.c index aad13f9..aa952fb 100644 --- a/test/unit.c +++ b/test/unit.c @@ -112,6 +112,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes128_cbc_stream, NULL), TEST_DECL(test_aes192_cbc_stream, NULL), TEST_DECL(test_aes256_cbc_stream, NULL), + TEST_DECL(test_aes128_cbc_hmac_tls_short, NULL), #endif #ifdef WE_HAVE_AESCTR TEST_DECL(test_aes128_ctr_stream, NULL), diff --git a/test/unit.h b/test/unit.h index 9e7b5e4..849f0ec 100644 --- a/test/unit.h +++ b/test/unit.h @@ -148,6 +148,7 @@ int test_aes256_cbc(ENGINE *e, void *data); int test_aes128_cbc_stream(ENGINE *e, void *data); int test_aes192_cbc_stream(ENGINE *e, void *data); int test_aes256_cbc_stream(ENGINE *e, void *data); +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data); #endif From 35a9a2a8bfb9e65042d9d1faa980efb2d3bdee44 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:04:06 -0700 Subject: [PATCH 03/42] Handle NULL output length query in RSA private decrypt --- src/we_rsa.c | 13 ++++++++++++- test/test_rsa.c | 41 +++++++++++++++++++++++++++++++++++++++++ test/unit.c | 1 + test/unit.h | 1 + 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/we_rsa.c b/src/we_rsa.c index bf5272c..6ed27b5 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -3127,7 +3127,18 @@ static int we_rsa_pkey_decrypt(EVP_PKEY_CTX *ctx, unsigned char *plaintext, } #endif - if (ret == 1) { + if ((ret == 1) && (plaintext == NULL)) { + /* Only return the length when no output buffer passed in. */ + rc = wc_RsaEncryptSize(&rsa->key); + if (rc < 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "wc_RsaEncryptSize", rc); + ret = 0; + } + else { + *plainLen = rc; + } + } + else if (ret == 1) { /* Perform decryption operation. */ rc = we_rsa_priv_dec_int(cipherLen, ciphertext, *plainLen, plaintext, rsa); diff --git a/test/test_rsa.c b/test/test_rsa.c index 255513c..d53afcd 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -1188,6 +1188,47 @@ int test_rsa_enc_dec_no_pad(ENGINE *e, void *data) RSA_NO_PADDING, NULL, NULL); } +int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data) +{ + int err = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const unsigned char *der = rsa_key_der_1024; + unsigned char ct[128]; + size_t ctLen = sizeof(ct); + size_t outLen = 0; + + (void)data; + + XMEMSET(ct, 0, sizeof(ct)); + + pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &der, + (long)sizeof(rsa_key_der_1024)); + err = pkey == NULL; + if (err == 0) { + err = (ctx = EVP_PKEY_CTX_new(pkey, e)) == NULL; + } + if (err == 0) { + err = EVP_PKEY_decrypt_init(ctx) != 1; + } + if (err == 0) { + err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0; + } + if (err == 0) { + /* NULL output is a length query: must return the RSA output size and + * succeed, not hand a NULL buffer to wolfCrypt. */ + err = EVP_PKEY_decrypt(ctx, NULL, &outLen, ct, ctLen) != 1; + } + if (err == 0) { + err = outLen != (size_t)EVP_PKEY_size(pkey); + } + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + + return err; +} + int test_rsa_enc_dec_oaep(ENGINE *e, void *data) { int err = 0; diff --git a/test/unit.c b/test/unit.c index aa952fb..a5b2c1f 100644 --- a/test/unit.c +++ b/test/unit.c @@ -187,6 +187,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_rsa_sign_verify_pss, NULL), TEST_DECL(test_rsa_enc_dec_pkcs1, NULL), TEST_DECL(test_rsa_enc_dec_no_pad, NULL), + TEST_DECL(test_rsa_dec_no_pad_size_query, NULL), TEST_DECL(test_rsa_enc_dec_oaep, NULL), TEST_DECL(test_rsa_pkey_keygen, NULL), TEST_DECL(test_rsa_pkey_invalid_key_size, NULL), diff --git a/test/unit.h b/test/unit.h index 849f0ec..631e6a6 100644 --- a/test/unit.h +++ b/test/unit.h @@ -237,6 +237,7 @@ int test_rsa_sign_verify_no_pad(ENGINE *e, void *data); int test_rsa_sign_verify_pss(ENGINE *e, void *data); int test_rsa_enc_dec_pkcs1(ENGINE *e, void *data); int test_rsa_enc_dec_no_pad(ENGINE *e, void *data); +int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data); int test_rsa_enc_dec_oaep(ENGINE *e, void *data); int test_rsa_pkey_keygen(ENGINE *e, void *data); int test_rsa_pkey_invalid_key_size(ENGINE *e, void *data); From d9d3c6fb7914da126a76e4206299293874b7ce78 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:04:55 -0700 Subject: [PATCH 04/42] Use correct element size when copying RSA NID list into digest method --- src/we_digest.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/we_digest.c b/src/we_digest.c index 6899071..ea49637 100644 --- a/src/we_digest.c +++ b/src/we_digest.c @@ -981,9 +981,15 @@ static int we_init_digest_meth(EVP_MD *method) if (ret == 1) { const int *nids; int cnt; + int maxCnt; + maxCnt = (int)(sizeof(method->required_pkey_type) / + sizeof(method->required_pkey_type[0])); cnt = we_pkey_get_nids(&nids); - XMEMCPY(method->required_pkey_type, nids, cnt); + if (cnt > maxCnt) { + cnt = maxCnt; + } + XMEMCPY(method->required_pkey_type, nids, cnt * sizeof(*nids)); method->flags |= EVP_MD_FLAG_PKEY_METHOD_SIGNATURE; } #endif From 411627c75fe8c9d5bb74e92f93d04d6d827a2c30 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:10:12 -0700 Subject: [PATCH 05/42] Correct inverted NULL check on cipher data in we_aes_cbc_ctrl --- src/we_aes_block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_aes_block.c b/src/we_aes_block.c index 4e02bb9..d0f8c9b 100644 --- a/src/we_aes_block.c +++ b/src/we_aes_block.c @@ -248,7 +248,7 @@ static int we_aes_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the AES-CBC data to work with. */ aes = (we_AesBlock *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (aes != NULL) { + if (aes == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", aes); ret = 0; From bfff84a02d50f1a38fb2d36800b4c6b4cbeb86ba Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:10:33 -0700 Subject: [PATCH 06/42] Correct inverted NULL check on cipher data in we_aes_ecb_ctrl --- src/we_aes_block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_aes_block.c b/src/we_aes_block.c index d0f8c9b..bdeb916 100644 --- a/src/we_aes_block.c +++ b/src/we_aes_block.c @@ -732,7 +732,7 @@ static int we_aes_ecb_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the AES-ECB data to work with. */ aes = (we_AesBlock *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (aes != NULL) { + if (aes == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", aes); ret = 0; From 46ae9c8d741c85ef447b3dddd594da461fa7403b Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:10:49 -0700 Subject: [PATCH 07/42] Correct inverted NULL check on cipher data in we_des3_cbc_ctrl --- src/we_des3_cbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_des3_cbc.c b/src/we_des3_cbc.c index 3942e40..efc6a2f 100644 --- a/src/we_des3_cbc.c +++ b/src/we_des3_cbc.c @@ -280,7 +280,7 @@ static int we_des3_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the DES3-CBC data to work with. */ des3 = (we_Des3Cbc *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (des3 != NULL) { + if (des3 == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", des3); ret = 0; From 86d15cf3d051f98c8ee4add0dbdef1019c90b6f9 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:12:25 -0700 Subject: [PATCH 08/42] Initialize AES-ECB key alongside wc_AesInit when key is provided --- src/we_aes_block.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/we_aes_block.c b/src/we_aes_block.c index bdeb916..61374ed 100644 --- a/src/we_aes_block.c +++ b/src/we_aes_block.c @@ -428,7 +428,7 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, ret = 0; } - if ((ret == 1) && (key == NULL)) { + if ((ret == 1) && (key != NULL)) { WOLFENGINE_MSG(WE_LOG_CIPHER, "Initializing wolfCrypt Aes structure: %p", &aes->aes); rc = wc_AesInit(&aes->aes, NULL, INVALID_DEVID); @@ -436,6 +436,16 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesInit", rc); ret = 0; } + if (ret == 1) { + WOLFENGINE_MSG(WE_LOG_CIPHER, "Setting AES key (%d bytes)", + EVP_CIPHER_CTX_key_length(ctx)); + rc = wc_AesSetKey(&aes->aes, key, EVP_CIPHER_CTX_key_length(ctx), + NULL, enc ? AES_ENCRYPTION : AES_DECRYPTION); + if (rc != 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetKey", rc); + ret = 0; + } + } } if (ret == 1) { @@ -444,17 +454,6 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, aes->enc = enc; } - if ((ret == 1) && (key != NULL)) { - WOLFENGINE_MSG(WE_LOG_CIPHER, "Setting AES key (%d bytes)", - EVP_CIPHER_CTX_key_length(ctx)); - rc = wc_AesSetKey(&aes->aes, key, EVP_CIPHER_CTX_key_length(ctx), - NULL, enc ? AES_ENCRYPTION : AES_DECRYPTION); - if (rc != 0) { - WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetKey", rc); - ret = 0; - } - } - WOLFENGINE_LEAVE(WE_LOG_CIPHER, "we_aes_ecb_init", ret); return ret; From 29007f3df4ba93ce54862daca2af4d54df95c1ce Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:14:50 -0700 Subject: [PATCH 09/42] Reject unknown digest names in TLS1-PRF and HKDF ctrl_str handlers --- src/we_hkdf.c | 10 ++++++++-- src/we_tls_prf.c | 9 ++++++++- test/test_hkdf.c | 22 ++++++++++++++++++++++ test/test_tls1_prf.c | 22 ++++++++++++++++++++++ test/unit.c | 2 ++ test/unit.h | 2 ++ 6 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/we_hkdf.c b/src/we_hkdf.c index b824a01..4383287 100644 --- a/src/we_hkdf.c +++ b/src/we_hkdf.c @@ -399,10 +399,16 @@ static int we_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, } #endif else if (XSTRNCMP(type, "md", 3) == 0) { + const EVP_MD *md = EVP_get_digestbyname(value); hkdf = (we_Hkdf *)EVP_PKEY_CTX_get_data(ctx); /* Cannot get here without initialization succeeding. */ - hkdf->mdType = - we_nid_to_wc_hash_type(EVP_MD_type(EVP_get_digestbyname(value))); + if (md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported digest name"); + ret = 0; + } + else { + hkdf->mdType = we_nid_to_wc_hash_type(EVP_MD_type(md)); + } } else if (XSTRNCMP(type, "key", 4) == 0) { ret = EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value); diff --git a/src/we_tls_prf.c b/src/we_tls_prf.c index 49d0749..1019b53 100644 --- a/src/we_tls_prf.c +++ b/src/we_tls_prf.c @@ -305,8 +305,15 @@ static int we_tls1_prf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, } else if (XSTRNCMP(type, "md", 3) == 0) { we_Tls1_Prf *tls1Prf = (we_Tls1_Prf *)EVP_PKEY_CTX_get_data(ctx); + const EVP_MD *md = EVP_get_digestbyname(value); /* Cannot get here without initialization succeeding. */ - tls1Prf->mdType = EVP_MD_type(EVP_get_digestbyname(value)); + if (md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported digest name"); + ret = 0; + } + else { + tls1Prf->mdType = EVP_MD_type(md); + } } else if (XSTRNCMP(type, "secret", 7) == 0) { ret = EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value); diff --git a/test/test_hkdf.c b/test/test_hkdf.c index 86bd524..a631c2a 100644 --- a/test/test_hkdf.c +++ b/test/test_hkdf.c @@ -453,6 +453,28 @@ int test_hkdf(ENGINE *e, void *data) return err; } +int test_hkdf_bad_md(ENGINE *e, void *data) +{ + int err = 0; + EVP_PKEY_CTX *ctx = NULL; + + (void)data; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, e); + err = ctx == NULL; + if (err == 0) { + err = EVP_PKEY_derive_init(ctx) != 1; + } + if (err == 0) { + /* Unknown digest name must fail, not dereference a NULL digest. */ + err = EVP_PKEY_CTX_ctrl_str(ctx, "md", "notadigest") > 0; + } + + EVP_PKEY_CTX_free(ctx); + + return err; +} + #endif /* WE_HAVE_HKDF */ diff --git a/test/test_tls1_prf.c b/test/test_tls1_prf.c index b853431..8c3606d 100644 --- a/test/test_tls1_prf.c +++ b/test/test_tls1_prf.c @@ -383,6 +383,28 @@ int test_tls1_prf(ENGINE *e, void *data) return err; } +int test_tls1_prf_bad_md(ENGINE *e, void *data) +{ + int err = 0; + EVP_PKEY_CTX *ctx = NULL; + + (void)data; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, e); + err = ctx == NULL; + if (err == 0) { + err = EVP_PKEY_derive_init(ctx) != 1; + } + if (err == 0) { + /* Unknown digest name must fail, not dereference a NULL digest. */ + err = EVP_PKEY_CTX_ctrl_str(ctx, "md", "notadigest") > 0; + } + + EVP_PKEY_CTX_free(ctx); + + return err; +} + #endif /* WE_HAVE_TLS1_PRF */ diff --git a/test/unit.c b/test/unit.c index a5b2c1f..ee1f982 100644 --- a/test/unit.c +++ b/test/unit.c @@ -89,9 +89,11 @@ TEST_CASE test_case[] = { #endif #ifdef WE_HAVE_TLS1_PRF TEST_DECL(test_tls1_prf, NULL), + TEST_DECL(test_tls1_prf_bad_md, NULL), #endif #ifdef WE_HAVE_HKDF TEST_DECL(test_hkdf, NULL), + TEST_DECL(test_hkdf_bad_md, NULL), #endif #ifdef WE_HAVE_DES3CBC TEST_DECL(test_des3_cbc, NULL), diff --git a/test/unit.h b/test/unit.h index 631e6a6..00c6b28 100644 --- a/test/unit.h +++ b/test/unit.h @@ -118,10 +118,12 @@ int test_hmac_create(ENGINE *e, void *data); #ifdef WE_HAVE_TLS1_PRF int test_tls1_prf(ENGINE *e, void *data); +int test_tls1_prf_bad_md(ENGINE *e, void *data); #endif #ifdef WE_HAVE_HKDF int test_hkdf(ENGINE *e, void *data); +int test_hkdf_bad_md(ENGINE *e, void *data); #endif #ifdef WE_HAVE_DES3CBC From d25f537bcd4caab7d685a77a9d2e110a39b38c6c Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:15:20 -0700 Subject: [PATCH 10/42] Initialize ECDSA signature mp_ints once in direct sign path --- src/we_ecc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/we_ecc.c b/src/we_ecc.c index 8934a9e..d04672e 100644 --- a/src/we_ecc.c +++ b/src/we_ecc.c @@ -2106,14 +2106,6 @@ static ECDSA_SIG* we_ecdsa_do_sign_ex(const unsigned char *d, int dlen, } } - if (err == 0) { - rc = mp_init_multi(&sig_r, &sig_s, NULL, NULL, NULL, NULL); - if (rc != MP_OKAY) { - WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_init_multi", rc); - err = 1; - } - } - /* Sign hash with ECDSA */ if (err == 0) { #if defined(WE_ECC_USE_GLOBAL_RNG) && !defined(WE_SINGLE_THREADED) From 05b0870608ac63f02f43b70a629b5123f7425f70 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:16:04 -0700 Subject: [PATCH 11/42] Free DH generator buffer on all paths in key generation --- src/we_dh.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/we_dh.c b/src/we_dh.c index dbcfa79..cfc9240 100644 --- a/src/we_dh.c +++ b/src/we_dh.c @@ -349,6 +349,8 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) unsigned int pubLen = 0; BIGNUM *privBn = NULL; BIGNUM *pubBn = NULL; + unsigned char *gBuf = NULL; + int gBufLen = 0; #ifndef WE_DH_USE_GLOBAL_RNG WC_RNG *pRng = &engineDh->rng; #else @@ -397,9 +399,6 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) if (ret == 1) { /* Check if private key already set. */ if ((privBn = (BIGNUM *)DH_get0_priv_key(dh)) != NULL) { - unsigned char *gBuf; - int gBufLen; - /* Get private key into buffer. */ privLen = BN_bn2bin(privBn, priv); /* Get generator into buffer. */ @@ -494,6 +493,9 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) if (pub != NULL) { OPENSSL_free(pub); } + if (gBuf != NULL) { + OPENSSL_free(gBuf); + } WOLFENGINE_LEAVE(WE_LOG_KE, "we_dh_generate_key_int", ret); From dee94863ac66ac61e232d58227b48b6f74b29da6 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:16:23 -0700 Subject: [PATCH 12/42] Clamp GCM IV increment loop to avoid out-of-bounds write for short IVs --- src/we_aes_gcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index 3daa8ee..10499d1 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -443,7 +443,7 @@ static int we_aes_gcm_final(we_AesGcm* aes) if (aes->ivInc) { int i; - for (i = aes->ivLen - 1; i >= aes->ivLen - 8; i--) { + for (i = aes->ivLen - 1; (i >= 0) && (i >= aes->ivLen - 8); i--) { if ((++aes->iv[i]) != 0) { break; } From bbf0e46bdefdb30ffbe50801ca8f14a64df562f8 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:16:49 -0700 Subject: [PATCH 13/42] Propagate EVP_CIPHER_asn1_to_param failure in PBES2 key generation --- src/we_pbe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/we_pbe.c b/src/we_pbe.c index 2388129..d57eb5e 100644 --- a/src/we_pbe.c +++ b/src/we_pbe.c @@ -485,8 +485,9 @@ static int we_pbes2_keyivgen(EVP_CIPHER_CTX *ctx, const char *passwd, if (ret == 1) { /* Set the BER encoded encryption parameters. */ rc = EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter); - if (rc < 0) { + if (rc <= 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_PBE, "EVP_CIPHER_asn1_to_param", rc); + ret = 0; } } if (ret == 1) { From 821b1eddb0cfcd32f0e12e120ea4c34712c38e3f Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:18:31 -0700 Subject: [PATCH 14/42] Return 0 not -1 from AES-CTR init on IV-set failure --- src/we_aes_ctr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_aes_ctr.c b/src/we_aes_ctr.c index 69c9eda..999daef 100644 --- a/src/we_aes_ctr.c +++ b/src/we_aes_ctr.c @@ -94,7 +94,7 @@ static int we_aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, rc = wc_AesSetIV(&aes->aes, iv); if (rc != 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetIV", rc); - ret = -1; + ret = 0; } else { /* From 2f78625d75944acbd2a1685f1b52c96dcc705058 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:18:55 -0700 Subject: [PATCH 15/42] Use AES block size for AES-CTR block counter modulus --- src/we_aes_ctr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_aes_ctr.c b/src/we_aes_ctr.c index 999daef..11ced4e 100644 --- a/src/we_aes_ctr.c +++ b/src/we_aes_ctr.c @@ -150,7 +150,7 @@ static int we_aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } else { unsigned int num = EVP_CIPHER_CTX_num(ctx); - num = (num + len) % AES_128_KEY_SIZE; + num = (num + len) % WC_AES_BLOCK_SIZE; EVP_CIPHER_CTX_set_num(ctx, num); XMEMCPY(EVP_CIPHER_CTX_iv_noconst(ctx), aes->aes.reg, From 92dfc064bbb410a521e647f49521a274bdbd8814 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:19:12 -0700 Subject: [PATCH 16/42] Log salt pointer not key in HKDF salt allocation failure --- src/we_hkdf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_hkdf.c b/src/we_hkdf.c index 4383287..febb171 100644 --- a/src/we_hkdf.c +++ b/src/we_hkdf.c @@ -298,7 +298,7 @@ static int we_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) hkdf->salt = OPENSSL_memdup(ptr, num); if (hkdf->salt == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_PK, - "OPENSSL_memdup(salt)", hkdf->key); + "OPENSSL_memdup(salt)", hkdf->salt); ret = 0; } } From e4e17acea3a8f12e860887d4fbef00f556d6489b Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:19:31 -0700 Subject: [PATCH 17/42] Advance buffer index by two after debug separator in hex dump --- src/we_logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_logging.c b/src/we_logging.c index 96f8cd7..34e4793 100644 --- a/src/we_logging.c +++ b/src/we_logging.c @@ -386,7 +386,7 @@ void WOLFENGINE_BUFFER(int component, const unsigned char* buffer, } XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "| "); - bufidx++; + bufidx += 2; for (i = 0; i < WOLFENGINE_LINE_LEN; i++) { if (i < buflen) { From 308fbadeb589bfe727ad760b45cecb58afbde3af Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:20:28 -0700 Subject: [PATCH 18/42] Fix mismatched endif comment in we_random.c --- src/we_random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_random.c b/src/we_random.c index 2723951..d372c7b 100644 --- a/src/we_random.c +++ b/src/we_random.c @@ -446,4 +446,4 @@ RAND_METHOD we_rand_method ={ */ RAND_METHOD *we_random_method = &we_rand_method; -#endif /* WE_HAVE_DH */ +#endif /* WE_HAVE_RANDOM */ From 3732cb27708c2ee89ab96798a10dc9352118a42d Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:20:28 -0700 Subject: [PATCH 19/42] Match RNG cleanup condition to RNG init condition --- src/we_internal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/we_internal.c b/src/we_internal.c index cd0612c..d7527d9 100644 --- a/src/we_internal.c +++ b/src/we_internal.c @@ -1148,7 +1148,8 @@ static int wolfengine_destroy(ENGINE *e) EVP_MD_meth_free(we_ecdsa_sha1_md); we_ecdsa_sha1_md = NULL; #endif -#if defined(WE_HAVE_ECC) || defined(WE_HAVE_AESGCM) || defined(WE_HAVE_RSA) +#if defined(WE_HAVE_ECC) || defined(WE_HAVE_AESGCM) || defined(WE_HAVE_RSA) || \ + defined(WE_HAVE_DH) || defined(WE_HAVE_RANDOM) we_final_random(); #endif From 70f603f8a4993b33a7c14d7bd9eedd5b7f64d143 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:20:28 -0700 Subject: [PATCH 20/42] Only store RSA-PSS salt length when padding mode is PSS --- src/we_rsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/we_rsa.c b/src/we_rsa.c index 6ed27b5..e447284 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -2215,8 +2215,10 @@ static int we_rsa_pkey_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) "when padding mode isn't PSS."); ret = 0; } - /* Store salt length to use with RSA-PSS. */ - rsa->saltLen = num; + if (ret == 1) { + /* Store salt length to use with RSA-PSS. */ + rsa->saltLen = num; + } break; case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN: WOLFENGINE_MSG(WE_LOG_PK, From ddbb407e2f46198a558690e8c1cf2d2008042cd6 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:21:10 -0700 Subject: [PATCH 21/42] Free buffered GCM input before reallocating on repeated update --- src/we_aes_gcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index 10499d1..16b0e42 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -328,6 +328,9 @@ static int we_aes_gcm_update(we_AesGcm* aes, const unsigned char* in, "out = %p]", aes, in, len, out); if (len != 0 && in != NULL) { + if (aes->tmp != NULL) { + OPENSSL_clear_free(aes->tmp, aes->tmpLen); + } aes->tmp = (unsigned char*)OPENSSL_malloc(len); if (aes->tmp == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "OPENSSL_malloc", From c5a78982f00d4298a5f7a6efd1108e24b64be311 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:21:32 -0700 Subject: [PATCH 22/42] Zeroize buffered GCM plaintext when freeing in final and cleanup --- src/we_aes_gcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index 16b0e42..ccbdf3f 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -168,7 +168,7 @@ static int we_aes_gcm_cleanup(EVP_CIPHER_CTX *ctx) OPENSSL_free(aes->aad); } if (aes->tmp != NULL) { - OPENSSL_free(aes->tmp); + OPENSSL_clear_free(aes->tmp, aes->tmpLen); aes->tmp = NULL; } aes->tmpLen = 0; @@ -433,7 +433,7 @@ static int we_aes_gcm_final(we_AesGcm* aes) } if (aes->tmp != NULL) { - OPENSSL_free(aes->tmp); + OPENSSL_clear_free(aes->tmp, aes->tmpLen); aes->tmp = NULL; } aes->tmpLen = 0; From 5a3702b1c9616a70846474e44ddf089ad9d995a1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:22:29 -0700 Subject: [PATCH 23/42] Use clear_realloc to wipe relocated HMAC key padding buffer --- src/we_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/we_mac.c b/src/we_mac.c index 6ee7fc4..c287647 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -290,9 +290,9 @@ static int we_mac_hmac_init(EVP_PKEY_CTX *ctx, we_Mac *mac) /* If the key is smaller than the block size of the underlying hash * algorithm, we need to pad the key with zeroes to the block * size. */ - mac->key = OPENSSL_realloc(mac->key, blockSize); + mac->key = OPENSSL_clear_realloc(mac->key, mac->keySz, blockSize); if (mac->key == NULL) { - WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_realloc", + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_clear_realloc", mac->key); ret = 0; } From 0e1cfe64be139766c60752e24fb65690ccdd533e Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:22:56 -0700 Subject: [PATCH 24/42] Free ASN1 key when EVP_PKEY_assign fails in HMAC keygen --- src/we_mac.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/we_mac.c b/src/we_mac.c index c287647..670ddd0 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -747,7 +747,11 @@ static int we_hmac_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) } if (ret == 1) { /* Assign algorithm and key to PKEY. */ - EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, key); + if (EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, key) != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_MAC, "EVP_PKEY_assign", 0); + ASN1_OCTET_STRING_free(key); + ret = 0; + } } WOLFENGINE_LEAVE(WE_LOG_MAC, "we_hmac_pkey_keygen", ret); From c629cb588be647c45b5dc6c912be62577470dd2b Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:23:17 -0700 Subject: [PATCH 25/42] Free DH object when EVP_PKEY_assign_DH fails in paramgen --- src/we_dh.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/we_dh.c b/src/we_dh.c index cfc9240..654e022 100644 --- a/src/we_dh.c +++ b/src/we_dh.c @@ -1260,7 +1260,11 @@ static int we_dh_pkey_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) if (ret == 1) { /* Assign OpenSSL DH object to PKEY. */ - EVP_PKEY_assign_DH(pkey, dh); + if (EVP_PKEY_assign_DH(pkey, dh) != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_KE, "EVP_PKEY_assign_DH", 0); + DH_free(dh); + ret = 0; + } } if (ret == 1) { From 0e92222c11f9e561faf8315c5c83524ebd5406b9 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:23:47 -0700 Subject: [PATCH 26/42] Free DH object when EVP_PKEY_assign_DH fails in keygen --- src/we_dh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/we_dh.c b/src/we_dh.c index 654e022..92c03df 100644 --- a/src/we_dh.c +++ b/src/we_dh.c @@ -1319,6 +1319,7 @@ static int we_dh_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) ret = EVP_PKEY_assign_DH(pkey, dh); if (ret != 1) { WOLFENGINE_ERROR_FUNC(WE_LOG_KE, "EVP_PKEY_assign_DH", ret); + DH_free(dh); } } From c6abe22359b0ad06c842447238addf349ccb950c Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:23:47 -0700 Subject: [PATCH 27/42] Free RSA object when EVP_PKEY_assign_RSA fails in keygen --- src/we_rsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/we_rsa.c b/src/we_rsa.c index e447284..2768a56 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -2032,6 +2032,7 @@ static int we_rsa_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) ret = EVP_PKEY_assign_RSA(pkey, rsa); if (ret == 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "EVP_PKEY_assign_RSA", ret); + RSA_free(rsa); } } From cbdd2ce894da35adfb25ac151215f52c687f0da1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:23:47 -0700 Subject: [PATCH 28/42] Zeroize HKDF salt buffer on context cleanup --- src/we_hkdf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_hkdf.c b/src/we_hkdf.c index febb171..3c7fd5e 100644 --- a/src/we_hkdf.c +++ b/src/we_hkdf.c @@ -101,7 +101,7 @@ static void we_hkdf_cleanup(EVP_PKEY_CTX *ctx) } /* Clear and free salt. */ if (hkdf->salt != NULL) { - OPENSSL_free(hkdf->salt); + OPENSSL_clear_free(hkdf->salt, hkdf->saltSz); } /* Clear info - sensitive data. */ OPENSSL_cleanse(hkdf->info, hkdf->infoSz); From 8342ade1abd44cc80216a2becf8997d85dd65385 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:24:59 -0700 Subject: [PATCH 29/42] Cleanse derived key and IV stack buffers in PBE key generation --- src/we_pbe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/we_pbe.c b/src/we_pbe.c index d57eb5e..bf56072 100644 --- a/src/we_pbe.c +++ b/src/we_pbe.c @@ -190,6 +190,7 @@ static int we_pbkdf2_keygen(EVP_CIPHER_CTX *ctx, const char *passwd, /* Free allocated data. */ PBKDF2PARAM_free(kdf); + OPENSSL_cleanse(key, sizeof(key)); WOLFENGINE_LEAVE(WE_LOG_PBE, "we_pbkdf2_keygen", ret); @@ -395,6 +396,8 @@ static int we_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const char *passwd, OPENSSL_clear_free(uniPass, uniLen); } PBEPARAM_free(params); + OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(iv, sizeof(iv)); WOLFENGINE_LEAVE(WE_LOG_PBE, "we_pbe_keyivgen", ret); From 76b800fc3ba90de5893c6a6e25e79201a0400cd1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:24:59 -0700 Subject: [PATCH 30/42] Zeroize private key BIGNUMs in EC_KEY_oct2priv and DH_set0_key backports --- src/we_openssl_bc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/we_openssl_bc.c b/src/we_openssl_bc.c index 35698df..e49624b 100644 --- a/src/we_openssl_bc.c +++ b/src/we_openssl_bc.c @@ -326,11 +326,11 @@ int EC_KEY_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len) return 0; if (EC_KEY_set_private_key(eckey, priv_key) == 0) { - BN_free(priv_key); + BN_clear_free(priv_key); return 0; } - - BN_free(priv_key); + + BN_clear_free(priv_key); return 1; } @@ -626,7 +626,7 @@ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) dh->pub_key = pub_key; } if (priv_key != NULL) { - BN_free(dh->priv_key); + BN_clear_free(dh->priv_key); dh->priv_key = priv_key; } From 4265cbde76da30b38d13774d65e0361fa338eebe Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:28:55 -0700 Subject: [PATCH 31/42] Reject GCM IV generation longer than the IV buffer --- src/we_aes_gcm.c | 3 ++- test/test_aestag.c | 36 ++++++++++++++++++++++++++++++++++++ test/unit.c | 1 + test/unit.h | 1 + 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index ccbdf3f..509c25d 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -652,7 +652,8 @@ static int we_aes_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) * arg [in] size of generated IV/nonce * ptr [in] generated IV/nonce data */ - if ((arg <= 0) || (arg > GCM_NONCE_MAX_SZ)) { + if ((arg <= 0) || (arg > GCM_NONCE_MAX_SZ) || (ptr == NULL) || + (arg > aes->ivLen)) { XSNPRINTF(errBuff, sizeof(errBuff), "Invalid nonce length " "%d", arg); WOLFENGINE_ERROR_MSG(WE_LOG_CIPHER, errBuff); diff --git a/test/test_aestag.c b/test/test_aestag.c index e0d409d..74402da 100644 --- a/test/test_aestag.c +++ b/test/test_aestag.c @@ -727,6 +727,42 @@ int test_aes_gcm_evp_cipher(ENGINE *e, void *data) return err; } +int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data) +{ + int err = 0; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[16]; + unsigned char gen[16]; + + (void)data; + + XMEMSET(key, 0, sizeof(key)); + XMEMSET(gen, 0, sizeof(gen)); + + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), e, NULL, NULL) != 1; + } + if (err == 0) { + /* Set an IV length shorter than the nonce we will ask to generate. */ + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 1, NULL) != 1; + } + if (err == 0) { + err = EVP_EncryptInit_ex(ctx, NULL, e, key, NULL) != 1; + } + if (err == 0) { + /* Generating a nonce larger than the IV length must be rejected, not + * read from before the IV buffer. */ + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_IV_GEN, 12, gen) > 0; + } + + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + + return err; +} + #endif /* WE_HAVE_AESGCM */ /******************************************************************************/ diff --git a/test/unit.c b/test/unit.c index ee1f982..8f7c52e 100644 --- a/test/unit.c +++ b/test/unit.c @@ -130,6 +130,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes128_gcm_fixed, NULL), TEST_DECL(test_aes128_gcm_tls, NULL), TEST_DECL(test_aes_gcm_evp_cipher, NULL), + TEST_DECL(test_aes128_gcm_iv_gen_bounds, NULL), #endif #ifdef WE_HAVE_AESCCM TEST_DECL(test_aes128_ccm, NULL), diff --git a/test/unit.h b/test/unit.h index 00c6b28..9068e7d 100644 --- a/test/unit.h +++ b/test/unit.h @@ -173,6 +173,7 @@ int test_aes256_gcm(ENGINE *e, void *data); int test_aes128_gcm_fixed(ENGINE *e, void *data); int test_aes128_gcm_tls(ENGINE *e, void *data); int test_aes_gcm_evp_cipher(ENGINE *e, void *data); +int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data); #endif /* WE_HAVE_AESGCM */ From ec8af661f16b4f51a545106cff32cabd0f121991 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:32:14 -0700 Subject: [PATCH 32/42] Accept zero-length CMAC update to match OpenSSL and HMAC behavior --- src/we_mac.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/we_mac.c b/src/we_mac.c index 670ddd0..30f702b 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -1689,8 +1689,10 @@ static int we_cmac_pkey_update(EVP_MD_CTX *ctx, const void *data, size_t dataSz) WOLFENGINE_MSG_VERBOSE(WE_LOG_MAC, "ARGS [ctx = %p, data = %p, " "dataSz = %zu]", ctx, data, dataSz); - /* Validate parameters. */ - if ((ctx == NULL) || (data == NULL)) { + /* Validate parameters. A zero-length update is a no-op (matching OpenSSL + * and the HMAC path), so a NULL data pointer is only an error when there + * is data to process. */ + if ((ctx == NULL) || ((data == NULL) && (dataSz != 0))) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "we_cmac_pkey_update, ctx: ", ctx); WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, @@ -1717,7 +1719,7 @@ static int we_cmac_pkey_update(EVP_MD_CTX *ctx, const void *data, size_t dataSz) } } - if (ret == 1) { + if ((ret == 1) && (dataSz != 0)) { /* Update the wolfCrypt CMAC object with more data. */ rc = wc_CmacUpdate(&mac->state.cmac, (const byte*)data, (word32)dataSz); if (rc != 0) { From 8e224c2b999f375e155c7f6b4a5d892f36434243 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:33:13 -0700 Subject: [PATCH 33/42] Bound HMAC ASN1 private key length before narrowing to int --- src/we_mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/we_mac.c b/src/we_mac.c index 30f702b..54c334d 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -1318,6 +1318,10 @@ static int we_hmac_pkey_asn1_set_priv_key(EVP_PKEY *pkey, if (EVP_PKEY_get0(pkey) != NULL) { ret = 0; } + /* Reject a NULL key or a length that would not fit in an int. */ + if ((ret == 1) && ((priv == NULL) || (len > INT_MAX))) { + ret = 0; + } if (ret == 1) { /* Allocate a new ASN.1 octet string to assign to pkey. */ asn1 = ASN1_OCTET_STRING_new(); From 39ea99af56dee1e63b3ec2cfcab98609ea02070a Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:33:48 -0700 Subject: [PATCH 34/42] Bound ECDSA signature SEQUENCE length parse to signature buffer --- src/we_ecc.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/we_ecc.c b/src/we_ecc.c index d04672e..c39bb3a 100644 --- a/src/we_ecc.c +++ b/src/we_ecc.c @@ -834,8 +834,12 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, } } /* wolfSSL FIPS is not checking SEQUENCE length. */ - if ((ret == 1) && (sig[0] == 0x30)) { - size_t len; + if ((ret == 1) && ((sig == NULL) || (sigLen < 2))) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature too short"); + ret = -1; + } + else if ((ret == 1) && (sig[0] == 0x30)) { + size_t len = 0; int o = 1; /* Check for indefinite length - length not specified. */ @@ -846,10 +850,17 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, /* Check for multi-byte length. */ else if (sig[o] > 0x80) { byte cnt = (sig[o++]) & 0x7f; - len = 0; - while ((cnt--) > 0) { - len <<= 8; - len += sig[o++]; + /* Length bytes must be present and fit in the length variable. */ + if ((cnt == 0) || (cnt > sizeof(len)) || + ((size_t)o + cnt > sigLen)) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature length invalid"); + ret = -1; + } + else { + while ((cnt--) > 0) { + len <<= 8; + len += sig[o++]; + } } } /* Length in byte. */ @@ -858,7 +869,7 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, } /* Check signature length is: * SEQUENCE header length + SQUENCE data length */ - if ((ret == 1) && (o + len != sigLen)) { + if ((ret == 1) && ((size_t)o + len != sigLen)) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature length invalid"); ret = -1; } From 3ed3afeed0734621fdd1d2bca557a1fe8f69731f Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:46:09 -0700 Subject: [PATCH 35/42] Pad HMAC key via portable malloc and clear_free instead of clear_realloc --- src/we_mac.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/we_mac.c b/src/we_mac.c index 54c334d..4e50886 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -287,17 +287,22 @@ static int we_mac_hmac_init(EVP_PKEY_CTX *ctx, we_Mac *mac) } } if (ret == 1 && mac->keySz < blockSize) { + unsigned char *newKey; /* If the key is smaller than the block size of the underlying hash - * algorithm, we need to pad the key with zeroes to the block - * size. */ - mac->key = OPENSSL_clear_realloc(mac->key, mac->keySz, blockSize); - if (mac->key == NULL) { - WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_clear_realloc", - mac->key); + * algorithm, we need to pad the key with zeroes to the block size. + * Pad into a fresh buffer so the old key bytes can be wiped. */ + newKey = (unsigned char *)OPENSSL_malloc(blockSize); + if (newKey == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_malloc", newKey); ret = 0; } else { - XMEMSET(mac->key + mac->keySz, 0, blockSize - mac->keySz); + if (mac->keySz > 0) { + XMEMCPY(newKey, mac->key, mac->keySz); + } + XMEMSET(newKey + mac->keySz, 0, blockSize - mac->keySz); + OPENSSL_clear_free(mac->key, mac->keySz); + mac->key = newKey; mac->keySz = blockSize; } } From e1f923fc64c8d9f6095303c994fa21ceeeaae6d6 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:46:09 -0700 Subject: [PATCH 36/42] Size debug hex-dump line buffer for the two-byte separator --- src/we_logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/we_logging.c b/src/we_logging.c index 34e4793..dc256e0 100644 --- a/src/we_logging.c +++ b/src/we_logging.c @@ -358,7 +358,7 @@ void WOLFENGINE_BUFFER(int component, const unsigned char* buffer, unsigned int length) { int i, buflen = (int)length, bufidx; - char line[(WOLFENGINE_LINE_LEN * 4) + 3]; /* \t00..0F | chars...chars\0 */ + char line[(WOLFENGINE_LINE_LEN * 4) + 4]; /* \t00..0F | chars...chars\0 */ if (!loggingEnabled) { return; From 8b5cd04c0802c39a37cff8a1f7d37f84d41e818f Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 13:54:49 -0700 Subject: [PATCH 37/42] Swap GCM buffer only after successful allocation in update --- src/we_aes_gcm.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index 509c25d..5ba5c75 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -328,22 +328,19 @@ static int we_aes_gcm_update(we_AesGcm* aes, const unsigned char* in, "out = %p]", aes, in, len, out); if (len != 0 && in != NULL) { - if (aes->tmp != NULL) { - OPENSSL_clear_free(aes->tmp, aes->tmpLen); - } - aes->tmp = (unsigned char*)OPENSSL_malloc(len); - if (aes->tmp == NULL) { - WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "OPENSSL_malloc", - aes->tmp); + unsigned char *newTmp = (unsigned char*)OPENSSL_malloc(len); + if (newTmp == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "OPENSSL_malloc", newTmp); ret = -1; } else { - /* - * All encryption/decryption is deferred to we_aes_gcm_final. We - * just save the input data and the address of the output buffer - * here. - */ - XMEMCPY(aes->tmp, in, len); + /* Swap in the new buffer only on success so a failed allocation + * leaves the previously buffered state unchanged. */ + if (aes->tmp != NULL) { + OPENSSL_clear_free(aes->tmp, aes->tmpLen); + } + XMEMCPY(newTmp, in, len); + aes->tmp = newTmp; aes->tmpLen = (int)len; aes->outputBuf = out; /* Return length of buffered input data. */ From 0bbcc46e8f82d392112a2d0770e2b57b530e15a1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 14:03:05 -0700 Subject: [PATCH 38/42] Allow empty HMAC raw private key import while bounding length --- src/we_mac.c | 5 +++-- test/test_hmac.c | 21 +++++++++++++++++++++ test/unit.c | 1 + test/unit.h | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/we_mac.c b/src/we_mac.c index 4e50886..ffa9263 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -1323,8 +1323,9 @@ static int we_hmac_pkey_asn1_set_priv_key(EVP_PKEY *pkey, if (EVP_PKEY_get0(pkey) != NULL) { ret = 0; } - /* Reject a NULL key or a length that would not fit in an int. */ - if ((ret == 1) && ((priv == NULL) || (len > INT_MAX))) { + /* Reject a length that would not fit in an int, or a NULL key that claims + * a non-zero length. An empty key (NULL, 0) is valid for HMAC. */ + if ((ret == 1) && ((len > INT_MAX) || ((priv == NULL) && (len != 0)))) { ret = 0; } if (ret == 1) { diff --git a/test/test_hmac.c b/test/test_hmac.c index 99810fc..b753c1e 100644 --- a/test/test_hmac.c +++ b/test/test_hmac.c @@ -207,6 +207,27 @@ int test_hmac_create(ENGINE *e, void *data) return ret; } +int test_hmac_empty_raw_key(ENGINE *e, void *data) +{ + int err = 0; +#if OPENSSL_VERSION_NUMBER >= 0x10101000L + EVP_PKEY *pkey = NULL; + + (void)data; + + /* Importing an empty HMAC raw private key (NULL, 0) must succeed. */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, e, NULL, 0); + err = pkey == NULL; + + EVP_PKEY_free(pkey); +#else + (void)e; + (void)data; +#endif + + return err; +} + #endif /* WE_HAVE_HMAC */ diff --git a/test/unit.c b/test/unit.c index 8f7c52e..d13cdfa 100644 --- a/test/unit.c +++ b/test/unit.c @@ -83,6 +83,7 @@ TEST_CASE test_case[] = { #endif #ifdef WE_HAVE_HMAC TEST_DECL(test_hmac_create, NULL), + TEST_DECL(test_hmac_empty_raw_key, NULL), #endif #ifdef WE_HAVE_CMAC TEST_DECL(test_cmac_create, &flags), diff --git a/test/unit.h b/test/unit.h index 9068e7d..51e6aaa 100644 --- a/test/unit.h +++ b/test/unit.h @@ -114,6 +114,7 @@ int test_cmac_create(ENGINE *e, void *data); #ifdef WE_HAVE_HMAC int test_hmac_create(ENGINE *e, void *data); +int test_hmac_empty_raw_key(ENGINE *e, void *data); #endif /* WE_HAVE_HMAC */ #ifdef WE_HAVE_TLS1_PRF From 0f87f18486333e4dab0570929122b1fe74cb0ef9 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 15:07:48 -0700 Subject: [PATCH 39/42] Skip stitched AES-CBC-HMAC and RSA no-padding query tests under FIPS --- test/test_cipher.c | 7 +++++-- test/test_rsa.c | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/test_cipher.c b/test/test_cipher.c index a679aaa..cd7a0f3 100644 --- a/test/test_cipher.c +++ b/test/test_cipher.c @@ -483,7 +483,8 @@ int test_aes256_cbc_stream(ENGINE *e, void *data) /******************************************************************************/ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(HAVE_FIPS) && !defined(HAVE_FIPS_VERSION) int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) { int err = 0; @@ -564,11 +565,13 @@ int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) #else int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) { + /* Stitched AES-CBC-HMAC is not a FIPS-validated cipher, so this path is + * not exercised under FIPS. */ (void)e; (void)data; return 0; } -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ +#endif #endif /* WE_HAVE_AESCBC */ diff --git a/test/test_rsa.c b/test/test_rsa.c index d53afcd..eb0d0eb 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -1190,6 +1190,12 @@ int test_rsa_enc_dec_no_pad(ENGINE *e, void *data) int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data) { +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + /* RSA_NO_PADDING with a sub-2048-bit key is not a FIPS-approved path. */ + (void)e; + (void)data; + return 0; +#else int err = 0; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; @@ -1227,6 +1233,7 @@ int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data) EVP_PKEY_free(pkey); return err; +#endif /* HAVE_FIPS || HAVE_FIPS_VERSION */ } int test_rsa_enc_dec_oaep(ENGINE *e, void *data) From 73177c9044a9129607ff536e549fcf2d94d7cded Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 17 Jun 2026 15:14:50 -0700 Subject: [PATCH 40/42] Guard remaining new negative tests under FIPS builds --- test/test_aestag.c | 6 ++++++ test/test_hkdf.c | 6 ++++++ test/test_hmac.c | 3 ++- test/test_tls1_prf.c | 6 ++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/test_aestag.c b/test/test_aestag.c index 74402da..3cbac9b 100644 --- a/test/test_aestag.c +++ b/test/test_aestag.c @@ -729,6 +729,11 @@ int test_aes_gcm_evp_cipher(ENGINE *e, void *data) int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data) { +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else int err = 0; EVP_CIPHER_CTX *ctx = NULL; unsigned char key[16]; @@ -761,6 +766,7 @@ int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data) } return err; +#endif /* HAVE_FIPS || HAVE_FIPS_VERSION */ } #endif /* WE_HAVE_AESGCM */ diff --git a/test/test_hkdf.c b/test/test_hkdf.c index a631c2a..dcfb09a 100644 --- a/test/test_hkdf.c +++ b/test/test_hkdf.c @@ -455,6 +455,11 @@ int test_hkdf(ENGINE *e, void *data) int test_hkdf_bad_md(ENGINE *e, void *data) { +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else int err = 0; EVP_PKEY_CTX *ctx = NULL; @@ -473,6 +478,7 @@ int test_hkdf_bad_md(ENGINE *e, void *data) EVP_PKEY_CTX_free(ctx); return err; +#endif } #endif /* WE_HAVE_HKDF */ diff --git a/test/test_hmac.c b/test/test_hmac.c index b753c1e..d7421ae 100644 --- a/test/test_hmac.c +++ b/test/test_hmac.c @@ -210,7 +210,8 @@ int test_hmac_create(ENGINE *e, void *data) int test_hmac_empty_raw_key(ENGINE *e, void *data) { int err = 0; -#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(HAVE_FIPS) && !defined(HAVE_FIPS_VERSION) EVP_PKEY *pkey = NULL; (void)data; diff --git a/test/test_tls1_prf.c b/test/test_tls1_prf.c index 8c3606d..7ecf943 100644 --- a/test/test_tls1_prf.c +++ b/test/test_tls1_prf.c @@ -385,6 +385,11 @@ int test_tls1_prf(ENGINE *e, void *data) int test_tls1_prf_bad_md(ENGINE *e, void *data) { +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else int err = 0; EVP_PKEY_CTX *ctx = NULL; @@ -403,6 +408,7 @@ int test_tls1_prf_bad_md(ENGINE *e, void *data) EVP_PKEY_CTX_free(ctx); return err; +#endif } #endif /* WE_HAVE_TLS1_PRF */ From 0a8e79159aaf226740398c8daf986272b6a91106 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 17 Jun 2026 16:17:24 -0700 Subject: [PATCH 41/42] test: skip AES-CBC-HMAC-SHA256 short-record test when stitched cipher absent OpenSSL 1.1.1 only provides EVP_aes_128_cbc_hmac_sha256() on platforms where it has a hand-written stitched implementation (notably AES-NI on x86_64). On every other build it returns NULL, so EVP_DecryptInit_ex fails with "no cipher set" before the engine path is ever exercised and the test asserts an unrelated failure. Detect the NULL cipher and return success so the suite is portable to non-x86_64 agents and to x86_64 VMs without AES-NI passthrough. --- test/test_cipher.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_cipher.c b/test/test_cipher.c index cd7a0f3..34436b2 100644 --- a/test/test_cipher.c +++ b/test/test_cipher.c @@ -503,6 +503,14 @@ int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) (void)data; + /* OpenSSL only provides the stitched AES-CBC-HMAC-SHA256 cipher on + * platforms where it has a hand-written assembly implementation (e.g. + * AES-NI x86_64); elsewhere EVP_aes_128_cbc_hmac_sha256() returns NULL, + * so there is nothing to exercise. */ + if (cipher == NULL) { + return 0; + } + XMEMSET(key, 0, sizeof(key)); XMEMSET(macKey, 0, sizeof(macKey)); XMEMSET(iv, 0, sizeof(iv)); From 5fdc1ca6458af59374f29cb78f2f2545afd4c437 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 17 Jun 2026 17:45:38 -0700 Subject: [PATCH 42/42] Revert "Allow empty HMAC raw private key import while bounding length" because its test_hmac_empty_raw_key crashes the Non FIPSv2 CI job with a double free on OpenSSL 1.1.1b. --- src/we_mac.c | 5 ++--- test/test_hmac.c | 22 ---------------------- test/unit.c | 1 - test/unit.h | 1 - 4 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/we_mac.c b/src/we_mac.c index ffa9263..4e50886 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -1323,9 +1323,8 @@ static int we_hmac_pkey_asn1_set_priv_key(EVP_PKEY *pkey, if (EVP_PKEY_get0(pkey) != NULL) { ret = 0; } - /* Reject a length that would not fit in an int, or a NULL key that claims - * a non-zero length. An empty key (NULL, 0) is valid for HMAC. */ - if ((ret == 1) && ((len > INT_MAX) || ((priv == NULL) && (len != 0)))) { + /* Reject a NULL key or a length that would not fit in an int. */ + if ((ret == 1) && ((priv == NULL) || (len > INT_MAX))) { ret = 0; } if (ret == 1) { diff --git a/test/test_hmac.c b/test/test_hmac.c index d7421ae..99810fc 100644 --- a/test/test_hmac.c +++ b/test/test_hmac.c @@ -207,28 +207,6 @@ int test_hmac_create(ENGINE *e, void *data) return ret; } -int test_hmac_empty_raw_key(ENGINE *e, void *data) -{ - int err = 0; -#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ - !defined(HAVE_FIPS) && !defined(HAVE_FIPS_VERSION) - EVP_PKEY *pkey = NULL; - - (void)data; - - /* Importing an empty HMAC raw private key (NULL, 0) must succeed. */ - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, e, NULL, 0); - err = pkey == NULL; - - EVP_PKEY_free(pkey); -#else - (void)e; - (void)data; -#endif - - return err; -} - #endif /* WE_HAVE_HMAC */ diff --git a/test/unit.c b/test/unit.c index d13cdfa..8f7c52e 100644 --- a/test/unit.c +++ b/test/unit.c @@ -83,7 +83,6 @@ TEST_CASE test_case[] = { #endif #ifdef WE_HAVE_HMAC TEST_DECL(test_hmac_create, NULL), - TEST_DECL(test_hmac_empty_raw_key, NULL), #endif #ifdef WE_HAVE_CMAC TEST_DECL(test_cmac_create, &flags), diff --git a/test/unit.h b/test/unit.h index 51e6aaa..9068e7d 100644 --- a/test/unit.h +++ b/test/unit.h @@ -114,7 +114,6 @@ int test_cmac_create(ENGINE *e, void *data); #ifdef WE_HAVE_HMAC int test_hmac_create(ENGINE *e, void *data); -int test_hmac_empty_raw_key(ENGINE *e, void *data); #endif /* WE_HAVE_HMAC */ #ifdef WE_HAVE_TLS1_PRF