TLS: Add negative tests for non-EtM CBC decryption

Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 5cf6e8b..7f64f29 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -3452,6 +3452,116 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2 */
+void ssl_decrypt_non_etm_cbc( int cipher_type, int hash_id, int trunc_hmac,
+                              int plaintext_len, int badmac, data_t *padding,
+                              int exp_ret )
+{
+    /*
+     * Test record decryption for CBC without EtM with possibly incorrect
+     * padding (provided as input) or MAC (generated by this function).
+     *
+     * Actually depends on TLS >= 1.0 (SSL 3.0 computes the MAC differently),
+     * but since the test framework doesn't support alternation in dependency
+     * statements, just depend on TLS 1.2.
+     */
+    mbedtls_ssl_context ssl; /* ONLY for debugging */
+    mbedtls_ssl_transform t0, t1;
+    mbedtls_record rec;
+    unsigned char *buf = NULL;
+    size_t buflen, olen = 0;
+    const size_t rec_data_offset = 16; /* IV size */
+    unsigned char add_data[13];
+    unsigned char mac[MBEDTLS_MD_MAX_SIZE];
+
+    mbedtls_ssl_init( &ssl );
+    mbedtls_ssl_transform_init( &t0 );
+    mbedtls_ssl_transform_init( &t1 );
+
+    /* Set up transforms with dummy keys */
+    TEST_ASSERT( build_transforms( &t0, &t1, cipher_type, hash_id,
+                                   0, trunc_hmac,
+                                   MBEDTLS_SSL_MINOR_VERSION_3,
+                                   0 , 0 ) == 0 );
+
+    /* Prepare a buffer for record data */
+    buflen = rec_data_offset
+           + plaintext_len
+           + t0.maclen
+           + padding->len;
+    ASSERT_ALLOC( buf, buflen );
+
+    /* Prepare a dummy record header */
+    memset( rec.ctr, 0, sizeof( rec.ctr ) );
+    rec.type    = MBEDTLS_SSL_MSG_APPLICATION_DATA;
+    rec.ver[0]  = MBEDTLS_SSL_MAJOR_VERSION_3;
+    rec.ver[1]  = MBEDTLS_SSL_MINOR_VERSION_3;
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    rec.cid_len = 0;
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+    /* Prepare dummy record content */
+    rec.buf     = buf;
+    rec.buf_len = buflen;
+    rec.data_offset = rec_data_offset;
+    rec.data_len = plaintext_len;
+    memset( rec.buf + rec.data_offset, 42, rec.data_len );
+
+    /*
+     * MAC, "pad" and encrypt - this near-duplicates the TLS 1.x non-EtM CBC
+     * code path of mbedtls_ssl_encrypt_buf(), but with user-provided padding,
+     * and possibly wrong HMAC. Also, without safety checks or CID support.
+     */
+
+    /* MAC with additional data */
+    memcpy( add_data, rec.ctr, 8 );
+    add_data[8] = rec.type;
+    add_data[9] = rec.ver[0];
+    add_data[10] = rec.ver[1];
+    add_data[11] = ( rec.data_len >> 8 ) & 0xff;
+    add_data[12] = ( rec.data_len >> 0 ) & 0xff;
+
+    TEST_EQUAL( 0, mbedtls_md_hmac_update( &t0.md_ctx_enc, add_data, 13 ) );
+    TEST_EQUAL( 0, mbedtls_md_hmac_update( &t0.md_ctx_enc,
+                                           rec.buf + rec.data_offset,
+                                           rec.data_len ) );
+    TEST_EQUAL( 0, mbedtls_md_hmac_finish( &t0.md_ctx_enc, mac ) );
+
+    memcpy( rec.buf + rec.data_offset + rec.data_len, mac, t0.maclen );
+    rec.data_len += t0.maclen;
+
+    /* Possibly falsify the MAC */
+    rec.buf[rec.data_offset + rec.data_len - 1] ^= badmac;
+
+    /* Append the user-provided padding */
+    memcpy( rec.buf + rec.data_offset + rec.data_len, padding->x, padding->len );
+    rec.data_len += padding->len;
+
+    /* Set dummy IV and encrypt */
+    memset( t0.iv_enc, 0x55, t0.ivlen );
+    TEST_ASSERT( t0.ivlen == rec_data_offset );
+    memcpy( rec.buf, t0.iv_enc, rec_data_offset );
+
+    TEST_EQUAL( 0, mbedtls_cipher_crypt( &t0.cipher_ctx_enc,
+                                  t0.iv_enc, t0.ivlen,
+                                  rec.buf + rec.data_offset, rec.data_len,
+                                  rec.buf + rec.data_offset, &olen ) );
+    rec.data_offset -= t0.ivlen;
+    rec.data_len    += t0.ivlen;
+
+    /*
+     * Try to decrypt and check that we get the expected result
+     */
+    TEST_EQUAL( exp_ret, mbedtls_ssl_decrypt_buf( &ssl, &t1, &rec ) );
+
+exit:
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_transform_free( &t0 );
+    mbedtls_ssl_transform_free( &t1 );
+    mbedtls_free( buf );
+}
+/* END_CASE */
+
 /* BEGIN_CASE */
 void ssl_tls_prf( int type, data_t * secret, data_t * random,
                   char *label, data_t *result_hex_str, int exp_ret )