From: Milan Broz Date: Mon, 4 May 2026 14:11:32 +0000 (+0200) Subject: chacha_poly: Use IV_STATE guard to prevent IV reuse X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=78f60e095d0dbcd0438cb360eeedd73d7d10c3ac;p=thirdparty%2Fopenssl.git chacha_poly: Use IV_STATE guard to prevent IV reuse If IV was set for Chacha20-Poly1305, code should not allow reusing IV after calling CipherFinal. Use iv_state (as used in GCM or OCB mode) to prevent that. Thanks to Alex Gaynor for reporting the issue. Reviewed-by: Eugene Syromiatnikov Reviewed-by: Paul Dale MergeDate: Tue May 12 05:14:09 2026 (Merged from https://github.com/openssl/openssl/pull/31104) --- diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.c b/providers/implementations/ciphers/cipher_chacha20_poly1305.c index e95289598a1..a48b9c37251 100644 --- a/providers/implementations/ciphers/cipher_chacha20_poly1305.c +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.c @@ -36,7 +36,6 @@ static OSSL_FUNC_cipher_final_fn chacha20_poly1305_final; static OSSL_FUNC_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params; static OSSL_FUNC_cipher_settable_ctx_params_fn chacha20_poly1305_settable_ctx_params; #define chacha20_poly1305_gettable_params ossl_cipher_generic_gettable_params -#define chacha20_poly1305_update chacha20_poly1305_cipher static void *chacha20_poly1305_newctx(void *provctx) { @@ -190,6 +189,7 @@ static int chacha20_poly1305_set_ctx_params(void *vctx, ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); return 0; } + ctx->iv_state = IV_STATE_UNINITIALISED; } if (p.tag != NULL) { @@ -249,9 +249,11 @@ static int chacha20_poly1305_einit(void *vctx, const unsigned char *key, ret = ossl_cipher_generic_einit(vctx, key, keylen, iv, ivlen, NULL); if (ret && iv != NULL) { PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CHACHA20_POLY1305_CTX *cctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; hw->initiv(ctx); + cctx->iv_state = IV_STATE_BUFFERED; } if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) ret = 0; @@ -268,9 +270,11 @@ static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key, ret = ossl_cipher_generic_dinit(vctx, key, keylen, iv, ivlen, NULL); if (ret && iv != NULL) { PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CHACHA20_POLY1305_CTX *cctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; hw->initiv(ctx); + cctx->iv_state = IV_STATE_BUFFERED; } if (ret && !chacha20_poly1305_set_ctx_params(vctx, params)) ret = 0; @@ -303,6 +307,18 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, return 1; } +static int chacha20_poly1305_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx; + + if (ctx->iv_state == IV_STATE_FINISHED) + return 0; + + return chacha20_poly1305_cipher(vctx, out, outl, outsize, in, inl); +} + static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) { @@ -322,6 +338,9 @@ static int chacha20_poly1305_final(void *vctx, unsigned char *out, size_t *outl, return 0; *outl = 0; + + /* Don't reuse the IV */ + ctx->iv_state = IV_STATE_FINISHED; return 1; } diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.h b/providers/implementations/ciphers/cipher_chacha20_poly1305.h index 7a4575fa2e8..6914966f6e6 100644 --- a/providers/implementations/ciphers/cipher_chacha20_poly1305.h +++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.h @@ -33,6 +33,7 @@ typedef struct { size_t tag_len; size_t tls_payload_length; size_t tls_aad_pad_sz; + unsigned int iv_state; /* set to one of IV_STATE_XXX */ } PROV_CHACHA20_POLY1305_CTX; typedef struct prov_cipher_hw_chacha_aead_st {