@@ -6676,6 +6676,142 @@ static int test_aes_rc4_keylen_change_cve_2023_5363(void)
66766676}
66776677#endif
66786678
6679+ static int test_aes_gcm_siv_empty_data (void )
6680+ {
6681+ unsigned char key [16 ] = { 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 ,
6682+ 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f , 0x10 };
6683+ unsigned char nonce [12 ] = { 0xaa , 0xbb , 0xcc , 0xdd , 0xee , 0xff , 0x00 , 0x11 ,
6684+ 0x22 , 0x33 , 0x44 , 0x55 };
6685+ unsigned char aad [33 ] = "this AAD was never authenticated" ;
6686+ unsigned char zero_tag [16 ] = { 0 };
6687+ unsigned char real_tag [16 ];
6688+ unsigned char out [16 ];
6689+ int outl , ret = 0 ;
6690+ EVP_CIPHER_CTX * ctx = NULL ;
6691+ EVP_CIPHER * c = EVP_CIPHER_fetch (NULL , "AES-128-GCM-SIV" , NULL );
6692+
6693+ if (c == NULL ) {
6694+ return TEST_skip ("AES-128-GCM-SIV cipher is not available" );
6695+ }
6696+
6697+ /* Compute the CORRECT tag for (key,nonce,aad,pt="") via encrypt */
6698+ ctx = EVP_CIPHER_CTX_new ();
6699+ if (!TEST_ptr (ctx )
6700+ || !TEST_true (EVP_EncryptInit_ex2 (ctx , c , key , nonce , NULL ))
6701+ || !TEST_true (EVP_EncryptUpdate (ctx , NULL , & outl , aad , sizeof (aad ))) /* AAD */
6702+ || !TEST_true (EVP_EncryptUpdate (ctx , out , & outl , aad , 0 )) /* empty PT, out!=NULL */
6703+ || !TEST_true (EVP_EncryptFinal_ex (ctx , out , & outl ))
6704+ || !TEST_true (EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_GET_TAG , 16 , real_tag )))
6705+ goto err ;
6706+ EVP_CIPHER_CTX_free (ctx );
6707+
6708+ /* SANITY: decrypt with CORRECT tag and an explicit empty-PT Update */
6709+ ctx = EVP_CIPHER_CTX_new ();
6710+ if (!TEST_ptr (ctx )
6711+ || !TEST_true (EVP_DecryptInit_ex2 (ctx , c , key , nonce , NULL ))
6712+ || !TEST_true (EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_SET_TAG , 16 , real_tag ))
6713+ || !TEST_true (EVP_DecryptUpdate (ctx , NULL , & outl , aad , sizeof (aad )))
6714+ || !TEST_true (EVP_DecryptUpdate (ctx , out , & outl , aad , 0 )) /* force aes_gcm_siv_decrypt(len=0) */
6715+ || !TEST_true (EVP_DecryptFinal_ex (ctx , out , & outl )))
6716+ goto err ;
6717+ EVP_CIPHER_CTX_free (ctx );
6718+
6719+ /* FORGERY A: AAD only, NO ciphertext Update, ALL-ZERO tag */
6720+ ctx = EVP_CIPHER_CTX_new ();
6721+ if (!TEST_ptr (ctx )
6722+ || !TEST_true (EVP_DecryptInit_ex2 (ctx , c , key , nonce , NULL ))
6723+ || !TEST_true (EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_SET_TAG , 16 , zero_tag ))
6724+ || !TEST_true (EVP_DecryptUpdate (ctx , NULL , & outl , aad , sizeof (aad ))) /* AAD only, out==NULL */
6725+ || !TEST_false (EVP_DecryptFinal_ex (ctx , out , & outl )))
6726+ goto err ;
6727+ EVP_CIPHER_CTX_free (ctx );
6728+
6729+ /* FORGERY B: no AAD, no Update at all, ALL-ZERO tag */
6730+ ctx = EVP_CIPHER_CTX_new ();
6731+ if (!TEST_ptr (ctx )
6732+ || !TEST_true (EVP_DecryptInit_ex2 (ctx , c , key , nonce , NULL ))
6733+ || !TEST_true (EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_SET_TAG , 16 , zero_tag ))
6734+ || !TEST_false (EVP_DecryptFinal_ex (ctx , out , & outl )))
6735+ goto err ;
6736+ EVP_CIPHER_CTX_free (ctx );
6737+
6738+ /* CONTROL: AAD only, NO ciphertext Update, CORRECT tag */
6739+ ctx = EVP_CIPHER_CTX_new ();
6740+ if (!TEST_ptr (ctx )
6741+ || !TEST_true (EVP_DecryptInit_ex2 (ctx , c , key , nonce , NULL ))
6742+ || !TEST_true (EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_SET_TAG , 16 , real_tag ))
6743+ || !TEST_true (EVP_DecryptUpdate (ctx , NULL , & outl , aad , sizeof (aad )))
6744+ || !TEST_true (EVP_DecryptFinal_ex (ctx , out , & outl )))
6745+ goto err ;
6746+ EVP_CIPHER_CTX_free (ctx );
6747+ ctx = NULL ;
6748+
6749+ ret = 1 ;
6750+ err :
6751+ EVP_CIPHER_CTX_free (ctx );
6752+
6753+ EVP_CIPHER_free (c );
6754+ return ret ;
6755+ }
6756+
6757+ /*
6758+ * AES-SIV reuse-without-rekey:
6759+ * msg1: legit non-empty CT, tag verifies, final_ret=0
6760+ * msg2: no reinit (or reinit with key=NULL), set forged tag,
6761+ * AAD only, DecryptFinal -> does stale final_ret leak through?
6762+ */
6763+ static int test_aes_siv_ctx_reuse (void )
6764+ {
6765+ unsigned char key [32 ] = { 7 }; /* AES-128-SIV => 2*16 */
6766+ unsigned char pt [9 ] = "payload!" ;
6767+ unsigned char ct [9 ], tagbuf [16 ], out [16 ], zero16 [16 ] = { 0 };
6768+ unsigned char aad [14 ] = "forged header" ;
6769+ int outl , ret = 0 ;
6770+ EVP_CIPHER_CTX * e = NULL , * d = NULL ;
6771+ EVP_CIPHER * c = EVP_CIPHER_fetch (NULL , "AES-128-SIV" , NULL );
6772+
6773+ if (c == NULL ) {
6774+ return TEST_skip ("AES-128-SIV cipher is not available" );
6775+ }
6776+
6777+ /* produce a valid (ct,tag) for msg1 */
6778+ e = EVP_CIPHER_CTX_new ();
6779+ if (!TEST_ptr (e )
6780+ || !TEST_true (EVP_EncryptInit_ex2 (e , c , key , NULL , NULL ))
6781+ || !TEST_true (EVP_EncryptUpdate (e , NULL , & outl , (unsigned char * )"hdr1" , 4 ))
6782+ || !TEST_true (EVP_EncryptUpdate (e , ct , & outl , pt , sizeof (pt )))
6783+ || !TEST_true (EVP_EncryptFinal_ex (e , out , & outl ))
6784+ || !TEST_true (EVP_CIPHER_CTX_ctrl (e , EVP_CTRL_AEAD_GET_TAG , 16 , tagbuf ))) {
6785+ EVP_CIPHER_CTX_free (e );
6786+ goto err ;
6787+ }
6788+ EVP_CIPHER_CTX_free (e );
6789+
6790+ /* msg1 decrypt */
6791+ d = EVP_CIPHER_CTX_new ();
6792+ if (!TEST_ptr (d )
6793+ || !TEST_true (EVP_DecryptInit_ex2 (d , c , key , NULL , NULL ))
6794+ || !TEST_true (EVP_CIPHER_CTX_ctrl (d , EVP_CTRL_AEAD_SET_TAG , 16 , tagbuf ))
6795+ || !TEST_true (EVP_DecryptUpdate (d , NULL , & outl , (unsigned char * )"hdr1" , 4 ))
6796+ || !TEST_true (EVP_DecryptUpdate (d , out , & outl , ct , sizeof (ct )))
6797+ || !TEST_true (EVP_DecryptFinal_ex (d , out , & outl )))
6798+ goto err ;
6799+
6800+ /* msg2 on SAME ctx, reinit with key=NULL => initkey skipped, final_ret should be reset */
6801+ if (!TEST_true (EVP_DecryptInit_ex2 (d , NULL , NULL , NULL , NULL ))
6802+ || !TEST_true (EVP_CIPHER_CTX_ctrl (d , EVP_CTRL_AEAD_SET_TAG , 16 , zero16 ))
6803+ || !TEST_true (EVP_DecryptUpdate (d , NULL , & outl , aad , sizeof (aad ))) /* forged AAD */
6804+ || !TEST_false (EVP_DecryptFinal_ex (d , out , & outl )))
6805+ goto err ;
6806+
6807+ ret = 1 ;
6808+
6809+ err :
6810+ EVP_CIPHER_CTX_free (d );
6811+ EVP_CIPHER_free (c );
6812+ return ret ;
6813+ }
6814+
66796815static int test_invalid_ctx_for_digest (void )
66806816{
66816817 int ret ;
@@ -7469,6 +7605,10 @@ int setup_tests(void)
74697605
74707606 ADD_ALL_TESTS (test_aead_oneshot_roundtrip , 2 * OSSL_NELEM (aead_oneshot_cfgs ));
74717607
7608+ /* Test cases for CVE-2026-45446 */
7609+ ADD_TEST (test_aes_gcm_siv_empty_data );
7610+ ADD_TEST (test_aes_siv_ctx_reuse );
7611+
74727612 ADD_TEST (test_invalid_ctx_for_digest );
74737613
74747614 ADD_TEST (test_evp_cipher_negative_length );
0 commit comments