Commit 8f1d63707d for openssl.org
commit 8f1d63707de15cdcc5d1b773076393cd5e561b70
Author: Billy Brumley <bbb@iki.fi>
Date: Fri Sep 18 10:43:14 2026 -0400
Allow the CCM tag to be fetched more than once after AEAD encryption
Reading the tag out of a CCM context currently resets the context, so a
second fetch of the same tag failed. The reset now happens when the
encryption completes rather than when the tag is read, so the tag
remains available, matching the other AEAD modes.
Assisted-by: Claude:claude-fable-5-1
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
Merge-date: Mon Oct 5 10:24:03 2026
Merged-from: https://github.com/openssl/openssl/pull/32885
diff --git a/providers/implementations/ciphers/ciphercommon_ccm.c b/providers/implementations/ciphers/ciphercommon_ccm.c
index 70e16aee0a..30ec95daad 100644
--- a/providers/implementations/ciphers/ciphercommon_ccm.c
+++ b/providers/implementations/ciphers/ciphercommon_ccm.c
@@ -212,9 +212,6 @@ int ossl_ccm_get_ctx_params(void *vctx, OSSL_PARAM params[])
}
if (!ctx->hw->gettag(ctx, p.tag->data, p.tag->data_size))
return 0;
- ctx->tag_set = 0;
- ctx->iv_set = 0;
- ctx->len_set = 0;
}
return 1;
@@ -427,7 +424,10 @@ static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out,
if (ctx->enc) {
if (!hw->auth_encrypt(ctx, in, out, len, NULL, 0))
goto err;
+ /* Finished - tag stays readable, but reset other flags */
ctx->tag_set = 1;
+ ctx->iv_set = 0;
+ ctx->len_set = 0;
} else {
/* The tag must be set before actually decrypting data */
if (!ctx->tag_set) {
diff --git a/test/evp_libctx_test.c b/test/evp_libctx_test.c
index e95a756c97..c4be6bf27c 100644
--- a/test/evp_libctx_test.c
+++ b/test/evp_libctx_test.c
@@ -347,7 +347,7 @@ err:
static int test_cipher_reinit(int test_id)
{
- int ret = 0, diff, ccm, siv, no_null_key;
+ int ret = 0, diff, siv, no_null_key;
int out1_len = 0, out2_len = 0, out3_len = 0;
EVP_CIPHER *cipher = NULL;
EVP_CIPHER_CTX *ctx = NULL;
@@ -384,9 +384,6 @@ static int test_cipher_reinit(int test_id)
if (!TEST_ptr(cipher = EVP_CIPHER_fetch(libctx, name, NULL)))
goto err;
- /* ccm fails on the second update - this matches OpenSSL 1_1_1 behaviour */
- ccm = (EVP_CIPHER_get_mode(cipher) == EVP_CIPH_CCM_MODE);
-
/* siv cannot be called with NULL key as the iv is irrelevant */
siv = (EVP_CIPHER_get_mode(cipher) == EVP_CIPH_SIV_MODE);
@@ -403,25 +400,22 @@ static int test_cipher_reinit(int test_id)
if (!TEST_true(EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
|| !TEST_true(EVP_EncryptUpdate(ctx, out1, &out1_len, in, sizeof(in)))
|| !TEST_true(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
- || !TEST_int_eq(EVP_EncryptUpdate(ctx, out2, &out2_len, in, sizeof(in)),
- ccm ? 0 : 1)
+ || !TEST_true(EVP_EncryptUpdate(ctx, out2, &out2_len, in, sizeof(in)))
|| (!no_null_key
&& (!TEST_true(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv))
|| !TEST_int_eq(EVP_EncryptUpdate(ctx, out3, &out3_len, in, sizeof(in)),
- ccm || siv ? 0 : 1))))
+ siv ? 0 : 1))))
goto err;
- if (ccm == 0) {
- if (diff) {
- if (!TEST_mem_ne(out1, out1_len, out2, out2_len)
- || !TEST_mem_ne(out1, out1_len, out3, out3_len)
- || !TEST_mem_ne(out2, out2_len, out3, out3_len))
- goto err;
- } else {
- if (!TEST_mem_eq(out1, out1_len, out2, out2_len)
- || (!siv && !no_null_key && !TEST_mem_eq(out1, out1_len, out3, out3_len)))
- goto err;
- }
+ if (diff) {
+ if (!TEST_mem_ne(out1, out1_len, out2, out2_len)
+ || !TEST_mem_ne(out1, out1_len, out3, out3_len)
+ || !TEST_mem_ne(out2, out2_len, out3, out3_len))
+ goto err;
+ } else {
+ if (!TEST_mem_eq(out1, out1_len, out2, out2_len)
+ || (!siv && !no_null_key && !TEST_mem_eq(out1, out1_len, out3, out3_len)))
+ goto err;
}
ret = 1;
err: