/* Provenance: openssl/openssl aes_ocb_cipher (fixed). * repo: openssl/openssl * commit: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 * parent: 5f489043b662fed32fbf7eb7442c479568eb43fd * commit_url: https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 * cve: CVE-2026-45445 * license: Apache-2.0 * function: aes_ocb_cipher * relpath: providers/implementations/ciphers/cipher_aes_ocb.c */ static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, size_t outsize, const unsigned char *in, size_t inl) { PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; if (!ossl_prov_is_running()) return 0; if (outsize < inl) { ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); return 0; } /* * Mirror the streaming handler: refuse if the key has not been set, * and push the buffered IV into the OCB context before any data is * processed. Without this, CRYPTO_ocb128_encrypt/decrypt runs with * Offset_0 = 0 regardless of the caller's IV -- catastrophic * (key, nonce) reuse, and a subsequent EVP_*Final_ex() emits a tag * that is a function of (key, iv) only. */ if (!ctx->key_set || !update_iv(ctx)) { ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); return 0; } if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); return 0; } *outl = inl; return 1; }