diff options
Diffstat (limited to 'test/evp_extra_test.c')
| -rw-r--r-- | test/evp_extra_test.c | 591 |
1 files changed, 585 insertions, 6 deletions
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index eec9364f42ba..80a133dd7f1d 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -2228,6 +2228,29 @@ out: return ret; } +#ifndef OPENSSL_NO_POLY1305 +/* Test that EVP_MAC_final fails for Poly1305 when no key was set */ +static int test_evp_mac_poly1305_no_key(void) +{ + int ret = 0; + EVP_MAC *mac = NULL; + EVP_MAC_CTX *ctx = NULL; + unsigned char out[16]; + size_t outl = 0; + + if (!TEST_ptr(mac = EVP_MAC_fetch(testctx, "Poly1305", testpropq)) + || !TEST_ptr(ctx = EVP_MAC_CTX_new(mac)) + || !TEST_int_eq(EVP_MAC_init(ctx, NULL, 0, NULL), 1) + || !TEST_int_eq(EVP_MAC_final(ctx, out, &outl, sizeof(out)), 0)) + goto err; + ret = 1; +err: + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + return ret; +} +#endif + static int test_d2i_AutoPrivateKey(int i) { int ret = 0; @@ -2592,9 +2615,10 @@ static int test_EVP_SM2(void) uint8_t ciphertext[128]; size_t ctext_len = sizeof(ciphertext); - + size_t ctext_len_param = 0; uint8_t plaintext[8]; size_t ptext_len = sizeof(plaintext); + size_t ptext_len_param = 0; uint8_t sm2_id[] = { 1, 2, 3, 4, 'l', 'e', 't', 't', 'e', 'r' }; @@ -2724,7 +2748,8 @@ static int test_EVP_SM2(void) if (!TEST_true(EVP_PKEY_CTX_set_params(cctx, sparams))) goto done; - if (!TEST_true(EVP_PKEY_encrypt(cctx, ciphertext, &ctext_len, kMsg, + ctext_len_param = ctext_len; + if (!TEST_true(EVP_PKEY_encrypt(cctx, ciphertext, &ctext_len_param, kMsg, sizeof(kMsg)))) goto done; @@ -2734,8 +2759,9 @@ static int test_EVP_SM2(void) if (!TEST_true(EVP_PKEY_CTX_set_params(cctx, sparams))) goto done; - if (!TEST_int_gt(EVP_PKEY_decrypt(cctx, plaintext, &ptext_len, ciphertext, - ctext_len), + ptext_len_param = ptext_len; + if (!TEST_int_gt(EVP_PKEY_decrypt(cctx, plaintext, &ptext_len_param, ciphertext, + ctext_len_param), 0)) goto done; @@ -2755,7 +2781,7 @@ static int test_EVP_SM2(void) goto done; } - if (!TEST_true(ptext_len == sizeof(kMsg))) + if (!TEST_true(ptext_len_param == sizeof(kMsg))) goto done; if (!TEST_true(memcmp(plaintext, kMsg, sizeof(kMsg)) == 0)) @@ -3976,6 +4002,85 @@ err: return ret; } +static int test_RSA_verify_recover_rejects_short_buffer(void) +{ + int ret = 0; + int recovered_cap = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *sign_ctx = NULL, *verify_ctx = NULL; + unsigned char *sig = NULL, *recovered = NULL; + size_t sig_len = 0, recovered_len = 0; + unsigned long err = 0; + unsigned char shortbuf[] = { 0xa5, 0x5a }; + const unsigned char shortbuf_expected[] = { 0xa5, 0x5a }; + unsigned char digest[32]; + size_t i; + + for (i = 0; i < sizeof(digest); i++) + digest[i] = (unsigned char)i; + + if (OSSL_PROVIDER_available(testctx, "fips")) + return TEST_skip("Test skipped for FIPS provider"); + + if (!TEST_ptr(pkey = load_example_rsa_key()) + || !TEST_ptr(sign_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, NULL)) + || !TEST_int_gt(EVP_PKEY_sign_init(sign_ctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_padding(sign_ctx, + RSA_PKCS1_PADDING), + 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_signature_md(sign_ctx, EVP_sha256()), + 0) + || !TEST_int_gt(EVP_PKEY_sign(sign_ctx, NULL, &sig_len, digest, + sizeof(digest)), + 0) + || !TEST_ptr(sig = OPENSSL_malloc(sig_len)) + || !TEST_int_gt(EVP_PKEY_sign(sign_ctx, sig, &sig_len, digest, + sizeof(digest)), + 0) + || !TEST_int_gt(recovered_cap = EVP_PKEY_get_size(pkey), 0) + || !TEST_ptr(recovered = OPENSSL_malloc(recovered_cap)) + || !TEST_ptr(verify_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, + NULL)) + || !TEST_int_gt(EVP_PKEY_verify_recover_init(verify_ctx), 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_padding(verify_ctx, + RSA_PKCS1_PADDING), + 0) + || !TEST_int_gt(EVP_PKEY_CTX_set_signature_md(verify_ctx, EVP_sha256()), + 0)) + goto done; + + recovered_len = (size_t)recovered_cap; + if (!TEST_int_gt(EVP_PKEY_verify_recover(verify_ctx, recovered, + &recovered_len, sig, sig_len), + 0) + || !TEST_size_t_eq(recovered_len, sizeof(digest)) + || !TEST_mem_eq(recovered, recovered_len, digest, sizeof(digest))) + goto done; + + ERR_clear_error(); + recovered_len = 1; + if (!TEST_int_le(EVP_PKEY_verify_recover(verify_ctx, shortbuf, + &recovered_len, sig, sig_len), + 0)) + goto done; + + err = ERR_peek_error(); + if (!TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_PROV) + || !TEST_int_eq(ERR_GET_REASON(err), PROV_R_OUTPUT_BUFFER_TOO_SMALL) + || !TEST_mem_eq(shortbuf, sizeof(shortbuf), shortbuf_expected, + sizeof(shortbuf_expected))) + goto done; + + ret = 1; +done: + EVP_PKEY_CTX_free(sign_ctx); + EVP_PKEY_CTX_free(verify_ctx); + EVP_PKEY_free(pkey); + OPENSSL_free(sig); + OPENSSL_free(recovered); + return ret; +} + static int test_RSA_encrypt(void) { int ret = 0; @@ -6528,6 +6633,142 @@ static int test_aes_rc4_keylen_change_cve_2023_5363(void) } #endif +static int test_aes_gcm_siv_empty_data(void) +{ + unsigned char key[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; + unsigned char nonce[12] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, + 0x22, 0x33, 0x44, 0x55 }; + unsigned char aad[33] = "this AAD was never authenticated"; + unsigned char zero_tag[16] = { 0 }; + unsigned char real_tag[16]; + unsigned char out[16]; + int outl, ret = 0; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *c = EVP_CIPHER_fetch(NULL, "AES-128-GCM-SIV", NULL); + + if (c == NULL) { + return TEST_skip("AES-128-GCM-SIV cipher is not available"); + } + + /* Compute the CORRECT tag for (key,nonce,aad,pt="") via encrypt */ + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx) + || !TEST_true(EVP_EncryptInit_ex2(ctx, c, key, nonce, NULL)) + || !TEST_true(EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) /* AAD */ + || !TEST_true(EVP_EncryptUpdate(ctx, out, &outl, aad, 0)) /* empty PT, out!=NULL */ + || !TEST_true(EVP_EncryptFinal_ex(ctx, out, &outl)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, real_tag))) + goto err; + EVP_CIPHER_CTX_free(ctx); + + /* SANITY: decrypt with CORRECT tag and an explicit empty-PT Update */ + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx) + || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, real_tag)) + || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) + || !TEST_true(EVP_DecryptUpdate(ctx, out, &outl, aad, 0)) /* force aes_gcm_siv_decrypt(len=0) */ + || !TEST_true(EVP_DecryptFinal_ex(ctx, out, &outl))) + goto err; + EVP_CIPHER_CTX_free(ctx); + + /* FORGERY A: AAD only, NO ciphertext Update, ALL-ZERO tag */ + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx) + || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, zero_tag)) + || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) /* AAD only, out==NULL */ + || !TEST_false(EVP_DecryptFinal_ex(ctx, out, &outl))) + goto err; + EVP_CIPHER_CTX_free(ctx); + + /* FORGERY B: no AAD, no Update at all, ALL-ZERO tag */ + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx) + || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, zero_tag)) + || !TEST_false(EVP_DecryptFinal_ex(ctx, out, &outl))) + goto err; + EVP_CIPHER_CTX_free(ctx); + + /* CONTROL: AAD only, NO ciphertext Update, CORRECT tag */ + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx) + || !TEST_true(EVP_DecryptInit_ex2(ctx, c, key, nonce, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, real_tag)) + || !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) + || !TEST_true(EVP_DecryptFinal_ex(ctx, out, &outl))) + goto err; + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + + ret = 1; +err: + EVP_CIPHER_CTX_free(ctx); + + EVP_CIPHER_free(c); + return ret; +} + +/* + * AES-SIV reuse-without-rekey: + * msg1: legit non-empty CT, tag verifies, final_ret=0 + * msg2: no reinit (or reinit with key=NULL), set forged tag, + * AAD only, DecryptFinal -> does stale final_ret leak through? + */ +static int test_aes_siv_ctx_reuse(void) +{ + unsigned char key[32] = { 7 }; /* AES-128-SIV => 2*16 */ + unsigned char pt[9] = "payload!"; + unsigned char ct[9], tagbuf[16], out[16], zero16[16] = { 0 }; + unsigned char aad[14] = "forged header"; + int outl, ret = 0; + EVP_CIPHER_CTX *e = NULL, *d = NULL; + EVP_CIPHER *c = EVP_CIPHER_fetch(NULL, "AES-128-SIV", NULL); + + if (c == NULL) { + return TEST_skip("AES-128-SIV cipher is not available"); + } + + /* produce a valid (ct,tag) for msg1 */ + e = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(e) + || !TEST_true(EVP_EncryptInit_ex2(e, c, key, NULL, NULL)) + || !TEST_true(EVP_EncryptUpdate(e, NULL, &outl, (unsigned char *)"hdr1", 4)) + || !TEST_true(EVP_EncryptUpdate(e, ct, &outl, pt, sizeof(pt))) + || !TEST_true(EVP_EncryptFinal_ex(e, out, &outl)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(e, EVP_CTRL_AEAD_GET_TAG, 16, tagbuf))) { + EVP_CIPHER_CTX_free(e); + goto err; + } + EVP_CIPHER_CTX_free(e); + + /* msg1 decrypt */ + d = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(d) + || !TEST_true(EVP_DecryptInit_ex2(d, c, key, NULL, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(d, EVP_CTRL_AEAD_SET_TAG, 16, tagbuf)) + || !TEST_true(EVP_DecryptUpdate(d, NULL, &outl, (unsigned char *)"hdr1", 4)) + || !TEST_true(EVP_DecryptUpdate(d, out, &outl, ct, sizeof(ct))) + || !TEST_true(EVP_DecryptFinal_ex(d, out, &outl))) + goto err; + + /* msg2 on SAME ctx, reinit with key=NULL => initkey skipped, final_ret should be reset */ + if (!TEST_true(EVP_DecryptInit_ex2(d, NULL, NULL, NULL, NULL)) + || !TEST_true(EVP_CIPHER_CTX_ctrl(d, EVP_CTRL_AEAD_SET_TAG, 16, zero16)) + || !TEST_true(EVP_DecryptUpdate(d, NULL, &outl, aad, sizeof(aad))) /* forged AAD */ + || !TEST_false(EVP_DecryptFinal_ex(d, out, &outl))) + goto err; + + ret = 1; + +err: + EVP_CIPHER_CTX_free(d); + EVP_CIPHER_free(c); + return ret; +} + static int test_invalid_ctx_for_digest(void) { int ret; @@ -6586,6 +6827,333 @@ end: return ret; } +/* + * Cross-driver round-trip test for AEAD one-shot vs streaming paths. + * + * The streaming path (EVP_CipherUpdate/Final, dispatched to + * OSSL_FUNC_CIPHER_UPDATE/_FINAL) is treated as the oracle. For each + * AEAD configuration we encrypt and decrypt the same (key, iv, aad, pt), + * driving the body in two combinations: + * + * 1. body encrypt via EVP_Cipher() (one-shot, OSSL_FUNC_CIPHER_CIPHER), + * body decrypt via EVP_CipherUpdate (streaming). + * 2. body encrypt via EVP_CipherUpdate, body decrypt via EVP_Cipher(). + * + * Both combinations must recover the plaintext and verify the tag. AAD + * is always fed via EVP_CipherUpdate(NULL, ...): OCB's one-shot is body + * only and the asymmetric "AAD streaming, body one-shot" call shape is + * the natural pattern a caller reaching for EVP_Cipher() for throughput + * would write anyway. + * + * CVE-2026-45445 (AES-OCB EVP_Cipher() ignored IV) was a silent failure + * in this matrix: the one-shot encrypt path produced ciphertext under + * Offset_0 = 0 regardless of IV, which the streaming decrypt path then + * could not verify. Adding this cross-check catches the same class of + * bug for any future AEAD whose one-shot dispatch diverges from its + * streaming dispatch. + */ +typedef struct { + const char *name; /* EVP_CIPHER fetch name */ + size_t keylen; + size_t ivlen; + size_t taglen; + int is_ccm; /* needs length-up-front + tag-before-body dance */ +} AEAD_ONESHOT_CFG; + +static const AEAD_ONESHOT_CFG aead_oneshot_cfgs[] = { + { "AES-128-GCM", 16, 12, 16, 0 }, + { "AES-256-GCM", 32, 12, 16, 0 }, + { "AES-128-CCM", 16, 12, 16, 1 }, + { "AES-256-CCM", 32, 12, 16, 1 }, + { "AES-128-OCB", 16, 12, 16, 0 }, + { "AES-256-OCB", 32, 12, 16, 0 }, + { "ChaCha20-Poly1305", 32, 12, 16, 0 } +}; + +/* + * Drive an encrypt or decrypt operation. AAD always via EVP_CipherUpdate. + * Body via EVP_Cipher() when oneshot_body is non-zero, EVP_CipherUpdate + * otherwise. On encrypt, fills *out and the caller-provided tag buffer. + * On decrypt, reads from in and verifies tag; returns 0 if verification + * fails (the test asserts the expected outcome). + */ +static int aead_oneshot_op(const AEAD_ONESHOT_CFG *cfg, int enc, + int oneshot_body, const unsigned char *key, + const unsigned char *iv, const unsigned char *aad, + size_t aad_len, const unsigned char *in, size_t in_len, + unsigned char *out, unsigned char *tag, const char **why) +{ + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + int outl = 0, tmpl = 0; + int ok = 0; + int body_rv; + + *why = NULL; + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, cfg->name, testpropq))) { + *why = "CIPHER_FETCH"; + goto end; + } + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())) { + *why = "CTX_NEW"; + goto end; + } + if (!TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc))) { + *why = "INIT_CIPHER"; + goto end; + } + if (!TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, + (int)cfg->ivlen, NULL), + 0)) { + *why = "SET_IVLEN"; + goto end; + } + if (cfg->is_ccm) { + /* Placeholder taglen on encrypt, real tag on decrypt; both before key+iv. */ + if (!TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + (int)cfg->taglen, enc ? NULL : tag), + 0)) { + *why = "CCM_SET_TAG"; + goto end; + } + } + if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc))) { + *why = "INIT_KEY_IV"; + goto end; + } + if (cfg->is_ccm) { + if (!TEST_true(EVP_CipherUpdate(ctx, NULL, &outl, NULL, (int)in_len))) { + *why = "CCM_LEN_DECL"; + goto end; + } + } + if (aad_len > 0 + && !TEST_true(EVP_CipherUpdate(ctx, NULL, &outl, aad, (int)aad_len))) { + *why = "AAD"; + goto end; + } + if (!enc && !cfg->is_ccm + && !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + (int)cfg->taglen, tag), + 0)) { + *why = "SET_TAG"; + goto end; + } + + if (oneshot_body) { + body_rv = EVP_Cipher(ctx, out, in, (unsigned int)in_len); + if (cfg->is_ccm && !enc) { + /* CCM decrypt: 0 means tag verify failed, < 0 means error. */ + if (!TEST_int_gt(body_rv, 0)) { + *why = "ONESHOT_DECRYPT"; + goto end; + } + } else { + if (!TEST_int_ge(body_rv, 0)) { + *why = "ONESHOT_BODY"; + goto end; + } + } + outl = (int)in_len; + } else { + if (!TEST_true(EVP_CipherUpdate(ctx, out, &outl, in, (int)in_len))) { + *why = enc ? "STREAM_BODY_ENC" : "STREAM_BODY_DEC"; + goto end; + } + } + + if (!cfg->is_ccm) { + if (!TEST_true(EVP_CipherFinal_ex(ctx, out + outl, &tmpl))) { + *why = enc ? "FINAL_ENC" : "FINAL_DEC"; + goto end; + } + } + + if (enc) { + if (!TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, + (int)cfg->taglen, tag), + 0)) { + *why = "GET_TAG"; + goto end; + } + } + ok = 1; +end: + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return ok; +} + +/* + * For each AEAD row we run two AAD modes, and within each AAD mode two + * cross-driver round trips: + * + * aad_mode 0: no AAD. Critical for catching the OCB-style bug: any + * EVP_CipherUpdate(NULL, aad, ...) call before the body + * would itself pass through the (correct) streaming + * handler and apply the buffered IV, masking the one-shot + * handler's failure to do so. With aad_len == 0 we make + * EVP_Cipher() the very first cipher operation on the + * context, which is the shape the bug requires. + * + * aad_mode 1: with AAD via streaming. Catches divergence between the + * drivers when AAD is in play. + * + * leg 0: encrypt-oneshot + decrypt-streaming + * leg 1: encrypt-streaming + decrypt-oneshot + * + * The test index encodes (cipher, aad_mode) so a failure points at both. + */ +static int test_aead_oneshot_roundtrip(int idx) +{ + static const unsigned char fixed_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + static const unsigned char fixed_iv[12] = { + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab + }; + static const unsigned char fixed_aad[] = "extra:context"; + static const unsigned char fixed_pt[] = "THE QUICK BROWN FOX JUMPS OVER LAZY!!"; + const AEAD_ONESHOT_CFG *cfg = &aead_oneshot_cfgs[idx / 2]; + int with_aad = idx % 2; + size_t aad_len = with_aad ? sizeof(fixed_aad) - 1 : 0; + size_t pt_len = sizeof(fixed_pt) - 1; + EVP_CIPHER *probe = NULL; + unsigned char ct[64], pt[64]; + unsigned char tag_oneshot[16], tag_stream[16]; + const char *why = NULL; + int leg, ok = 0; + + /* + * Probe for the cipher: a build with no-ocb / no-chacha / etc. will + * not have it, and we treat that as a pass (nothing to test here). + */ + ERR_set_mark(); + probe = EVP_CIPHER_fetch(testctx, cfg->name, testpropq); + ERR_pop_to_mark(); + if (probe == NULL) { + TEST_info("skipping, '%s' is not available", cfg->name); + return 1; + } + EVP_CIPHER_free(probe); + + for (leg = 0; leg <= 1; leg++) { + int enc_oneshot = (leg == 0); + unsigned char *tag = enc_oneshot ? tag_oneshot : tag_stream; + + memset(ct, 0, sizeof(ct)); + memset(pt, 0, sizeof(pt)); + memset(tag, 0, cfg->taglen); + + if (!aead_oneshot_op(cfg, /*enc=*/1, /*oneshot_body=*/enc_oneshot, + fixed_key, fixed_iv, fixed_aad, aad_len, + fixed_pt, pt_len, ct, tag, &why)) { + TEST_error("%s (%s): encrypt leg %d (%s body) failed at %s", + cfg->name, with_aad ? "with AAD" : "no AAD", + leg, enc_oneshot ? "oneshot" : "stream", + why ? why : "?"); + goto end; + } + if (!aead_oneshot_op(cfg, /*enc=*/0, /*oneshot_body=*/!enc_oneshot, + fixed_key, fixed_iv, fixed_aad, aad_len, + ct, pt_len, pt, tag, &why)) { + TEST_error("%s (%s): decrypt leg %d (%s body) failed at %s", + cfg->name, with_aad ? "with AAD" : "no AAD", + leg, enc_oneshot ? "stream" : "oneshot", + why ? why : "?"); + goto end; + } + if (!TEST_mem_eq(pt, pt_len, fixed_pt, pt_len)) { + TEST_error("%s (%s): leg %d: recovered plaintext differs", + cfg->name, with_aad ? "with AAD" : "no AAD", leg); + goto end; + } + } + + /* + * Both legs share the same (key, iv, aad, pt) and must therefore + * agree on the tag bit-for-bit, regardless of which driver computed + * it. This catches the OCB-style failure where the one-shot path + * silently emits a different ciphertext/tag from the streaming path. + */ + if (!TEST_mem_eq(tag_oneshot, cfg->taglen, tag_stream, cfg->taglen)) { + TEST_error("%s (%s): oneshot-encrypt tag != streaming-encrypt tag", + cfg->name, with_aad ? "with AAD" : "no AAD"); + goto end; + } + ok = 1; +end: + return ok; +} + +#ifndef OPENSSL_NO_DES +static int test_EVP_CIPHER_get_type_des_ede3(void) +{ + const EVP_CIPHER *cipher = NULL; + int base_type, variant_type, nid; + int ret = 0; + + /* Get the base type from CFB64 (should be NID_des_ede3_cfb64) */ + cipher = EVP_des_ede3_cfb64(); + base_type = EVP_CIPHER_get_type(cipher); + + /* Test CFB64 - should map to the same base_type */ + variant_type = EVP_CIPHER_get_type(cipher); + nid = EVP_CIPHER_get_nid(cipher); + + /* Verify the returned type */ + if (!TEST_int_eq(variant_type, base_type)) + goto end; + + /* Verify that variant_type and nid are same for 64-bit variants */ + if (!TEST_int_eq(variant_type, nid)) + goto end; + + if (!TEST_int_eq(NID_des_ede3_cfb64, variant_type)) + goto end; + + /* Test CFB8 - should map to the same base_type */ + cipher = EVP_des_ede3_cfb8(); + variant_type = EVP_CIPHER_get_type(cipher); + nid = EVP_CIPHER_get_nid(cipher); + + /* Verify the returned type */ + if (!TEST_int_eq(variant_type, base_type)) + goto end; + + /* Verify that variant_type and nid are different for variants */ + if (!TEST_int_ne(variant_type, nid)) + goto end; + + if (!TEST_int_eq(NID_des_ede3_cfb64, variant_type)) + goto end; + + /* Test CFB1 - should map to the same base_type */ + cipher = EVP_des_ede3_cfb1(); + variant_type = EVP_CIPHER_get_type(cipher); + nid = EVP_CIPHER_get_nid(cipher); + + /* Verify the returned type */ + if (!TEST_int_eq(variant_type, base_type)) + goto end; + + /* Verify that variant_type and nid are different for variants */ + if (!TEST_int_ne(variant_type, nid)) + goto end; + + if (!TEST_int_eq(NID_des_ede3_cfb64, variant_type)) + goto end; + + ret = 1; +end: + return ret; +} +#endif /*OPENSSL_NO_DES */ + static int test_evp_cipher_pipeline(void) { OSSL_PROVIDER *fake_pipeline = NULL; @@ -6854,6 +7422,9 @@ int setup_tests(void) #endif ADD_TEST(test_EVP_Digest); ADD_TEST(test_EVP_md_null); +#ifndef OPENSSL_NO_POLY1305 + ADD_TEST(test_evp_mac_poly1305_no_key); +#endif ADD_ALL_TESTS(test_EVP_PKEY_sign, 3); #ifndef OPENSSL_NO_DEPRECATED_3_0 ADD_ALL_TESTS(test_EVP_PKEY_sign_with_app_method, 2); @@ -6904,6 +7475,7 @@ int setup_tests(void) ADD_TEST(test_RSA_get_set_params); ADD_TEST(test_RSA_OAEP_set_get_params); ADD_TEST(test_RSA_OAEP_set_null_label); + ADD_TEST(test_RSA_verify_recover_rejects_short_buffer); ADD_TEST(test_RSA_encrypt); #ifndef OPENSSL_NO_DEPRECATED_3_0 ADD_TEST(test_RSA_legacy); @@ -6932,7 +7504,8 @@ int setup_tests(void) ADD_ALL_TESTS(test_evp_iv_aes, 12); #ifndef OPENSSL_NO_DES ADD_ALL_TESTS(test_evp_iv_des, 6); -#endif + ADD_TEST(test_EVP_CIPHER_get_type_des_ede3); +#endif /* OPENSSL_NO_DES */ #ifndef OPENSSL_NO_BF ADD_ALL_TESTS(test_evp_bf_default_keylen, 4); #endif @@ -6987,6 +7560,12 @@ int setup_tests(void) ADD_TEST(test_aes_rc4_keylen_change_cve_2023_5363); #endif + ADD_ALL_TESTS(test_aead_oneshot_roundtrip, 2 * OSSL_NELEM(aead_oneshot_cfgs)); + + /* Test cases for CVE-2026-45446 */ + ADD_TEST(test_aes_gcm_siv_empty_data); + ADD_TEST(test_aes_siv_ctx_reuse); + ADD_TEST(test_invalid_ctx_for_digest); ADD_TEST(test_evp_cipher_negative_length); |
