Skip to content

Commit bdeb0cd

Browse files
bbbrumleyidrassi
authored andcommitted
Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs
For the affected OpenSSL built-in provider AEAD implementations, EVP_Cipher(ctx, out, NULL, 0) reaches the ccipher callback as a NULL-input terminal call. OCB and ChaCha20-Poly1305 took an early exit on an empty message, with or without AAD, and returned success without comparing an explicitly supplied tag. Consequently a corrupted tag was accepted before this change. Make these built-in callbacks perform their terminal tag operation, aligning their explicit-tag handling with the streaming Final path without defining NULL input as part of the generic EVP_Cipher() contract. AES-GCM-SIV also failed to generate a tag when Final was its first empty-message operation. Generate the tag in that case and propagate failures from the matching empty-message decrypt operation. The stable ChaCha20-Poly1305 implementation aliases Update to the one-shot cipher callback, so this backport introduces a dedicated Update callback to preserve zero-length Update as a no-op. Follow-up to #31555 Fixes #32258 Fixes CVE-2026-75803 Assisted-by: Claude:claude-opus-4-8 Assisted-by: Codex:gpt-5.6-sol (cherry picked from commit 5741d29) Co-authored-by: Mounir IDRASSI <mounir.idrassi@amcrypto.jp> Reviewed-by: Bob Beck <beck@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.foundation> Merge-date: Wed Aug 19 17:41:16 2026 Merged-from: #32416
1 parent 1fff780 commit bdeb0cd

3 files changed

Lines changed: 34 additions & 11 deletions

File tree

‎providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,17 @@ static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx)
267267
{
268268
int ret = 0;
269269

270-
if (ctx->enc)
270+
if (ctx->enc) {
271+
/* Generate the tag when Final is the first empty-message operation. */
272+
if (ctx->generated_tag == 0
273+
&& aes_gcm_siv_encrypt(ctx, NULL, NULL, 0) == 0)
274+
return 0;
271275
return ctx->generated_tag;
272-
if (!ctx->generated_tag)
273-
aes_gcm_siv_decrypt(ctx, NULL, NULL, 0);
274-
ret = !CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag));
276+
}
277+
if (ctx->generated_tag == 0
278+
&& aes_gcm_siv_decrypt(ctx, NULL, NULL, 0) == 0)
279+
return 0;
280+
ret = CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)) == 0;
275281
ret &= ctx->have_user_tag;
276282
return ret;
277283
}

‎providers/implementations/ciphers/cipher_aes_ocb.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl,
509509
if (!ossl_prov_is_running())
510510
return 0;
511511

512+
/* NULL input indicates Final, which must generate or check the tag. */
513+
if (in == NULL)
514+
return aes_ocb_block_final(vctx, out, outl, outsize);
515+
512516
if (outsize < inl) {
513517
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
514518
return 0;

‎providers/implementations/ciphers/cipher_chacha20_poly1305.c‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
2+
* Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.
33
*
44
* Licensed under the Apache License 2.0 (the "License"). You may not use
55
* this file except in compliance with the License. You can obtain a copy
@@ -30,11 +30,11 @@ static OSSL_FUNC_cipher_get_params_fn chacha20_poly1305_get_params;
3030
static OSSL_FUNC_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params;
3131
static OSSL_FUNC_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params;
3232
static OSSL_FUNC_cipher_cipher_fn chacha20_poly1305_cipher;
33+
static OSSL_FUNC_cipher_update_fn chacha20_poly1305_update;
3334
static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final;
3435
static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params;
3536
static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_poly1305_settable_ctx_params;
3637
#define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params
37-
#define chacha20_poly1305_update chacha20_poly1305_cipher
3838

3939
static void *chacha20_poly1305_newctx(void *provctx)
4040
{
@@ -301,11 +301,6 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out,
301301
if (!ossl_prov_is_running())
302302
return 0;
303303

304-
if (inl == 0) {
305-
*outl = 0;
306-
return 1;
307-
}
308-
309304
if (outsize < inl) {
310305
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
311306
return 0;
@@ -317,6 +312,24 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out,
317312
return 1;
318313
}
319314

315+
static int chacha20_poly1305_update(void *vctx, unsigned char *out,
316+
size_t *outl, size_t outsize,
317+
const unsigned char *in, size_t inl)
318+
{
319+
/*
320+
* A zero-length update is a no-op. Only EVP_Cipher() and Final produce or
321+
* check the authentication tag.
322+
*/
323+
if (inl == 0) {
324+
if (!ossl_prov_is_running())
325+
return 0;
326+
*outl = 0;
327+
return 1;
328+
}
329+
330+
return chacha20_poly1305_cipher(vctx, out, outl, outsize, in, inl);
331+
}
332+
320333
static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl,
321334
size_t outsize)
322335
{

0 commit comments

Comments
 (0)