From 77bde2b32b4563f1fe4248eafdcd2bd6dfb29dc3 Mon Sep 17 00:00:00 2001 From: Trust-Worthy Date: Wed, 30 Sep 2026 18:22:45 -0400 Subject: Add test for an update with no input An update with no input and a nonzero length must fail, except for the CCM message length. test_evp_aead_update_null_input checks this for every AEAD, and that a rejected update writes no output. Assisted-by: Claude:claude-opus-5-5 Reviewed-by: Paul Dale Reviewed-by: Neil Horman Merge-date: Wed Oct 21 16:59:57 2026 Merged-from: https://github.com/openssl/openssl/pull/33157 --- test/evp_aead_test.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/evp_aead_test.c b/test/evp_aead_test.c index d0ec6876b49..48c217ffc60 100644 --- a/test/evp_aead_test.c +++ b/test/evp_aead_test.c @@ -858,6 +858,95 @@ err: return ret; } +/* + * An update with no input and a nonzero length must fail, except for the + * CCM message length, which is passed with no input and no output. This is + * checked for both encryption and decryption. + */ +static int test_evp_aead_update_null_input(int idx) +{ + const AEAD_DATA *info = &aead_list[idx]; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[EVP_MAX_KEY_LENGTH] = { 0 }; + unsigned char iv[EVP_MAX_IV_LENGTH] = { 0 }; + unsigned char out[16] = { 0xAB }, untouched[16] = { 0xAB }; + int outl = 0, testresult = 0; + + /* encrypt: no input, no output -- valid only as the CCM message length */ + ERR_clear_error(); + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_EncryptInit_ex2(ctx, info->ciph, key, iv, NULL))) + goto err; + if (info->mode == EVP_CIPH_CCM_MODE) { + if (!TEST_true(EVP_EncryptUpdate(ctx, NULL, &outl, NULL, 16))) { + TEST_info("encrypt CCM length rejected: idx=%d cipher=%s", + idx, info->name); + goto err; + } + } else if (!TEST_false(EVP_EncryptUpdate(ctx, NULL, &outl, NULL, 16)) + || !TEST_err_r(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER)) { + TEST_info("encrypt no input, no output: idx=%d cipher=%s", + idx, info->name); + goto err; + } + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + + /* encrypt: no input with an output buffer -- always fails, writes nothing */ + ERR_clear_error(); + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_EncryptInit_ex2(ctx, info->ciph, key, iv, NULL)) + || !TEST_false(EVP_EncryptUpdate(ctx, out, &outl, NULL, 16)) + || !TEST_err_r(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER) + || !TEST_int_eq(outl, 0) + || !TEST_mem_eq(out, sizeof(out), untouched, sizeof(untouched))) { + TEST_info("encrypt no input, with output: idx=%d cipher=%s", + idx, info->name); + goto err; + } + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + + /* decrypt: no input, no output -- valid only as the CCM message length */ + ERR_clear_error(); + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_DecryptInit_ex2(ctx, info->ciph, key, iv, NULL))) + goto err; + if (info->mode == EVP_CIPH_CCM_MODE) { + if (!TEST_true(EVP_DecryptUpdate(ctx, NULL, &outl, NULL, 16))) { + TEST_info("decrypt CCM length rejected: idx=%d cipher=%s", + idx, info->name); + goto err; + } + } else if (!TEST_false(EVP_DecryptUpdate(ctx, NULL, &outl, NULL, 16)) + || !TEST_err_r(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER)) { + TEST_info("decrypt no input, no output: idx=%d cipher=%s", + idx, info->name); + goto err; + } + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + + /* decrypt: no input with an output buffer -- always fails, writes nothing */ + ERR_clear_error(); + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_DecryptInit_ex2(ctx, info->ciph, key, iv, NULL)) + || !TEST_false(EVP_DecryptUpdate(ctx, out, &outl, NULL, 16)) + || !TEST_err_r(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER) + || !TEST_int_eq(outl, 0) + || !TEST_mem_eq(out, sizeof(out), untouched, sizeof(untouched))) { + TEST_info("decrypt no input, with output: idx=%d cipher=%s", + idx, info->name); + goto err; + } + + testresult = 1; +err: + ERR_clear_error(); + EVP_CIPHER_CTX_free(ctx); + return testresult; +} + int setup_tests(void) { size_t i = 0; @@ -879,6 +968,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_evp_aead_get_tag_pairwise, OSSL_NELEM(aead_list)); ADD_ALL_TESTS(test_evp_final_no_tag, OSSL_NELEM(aead_list)); ADD_ALL_TESTS(test_evp_aead_enc_retval, OSSL_NELEM(aead_list)); + ADD_ALL_TESTS(test_evp_aead_update_null_input, OSSL_NELEM(aead_list)); return 1; } -- cgit