From d2e004e4016af192f4debab762d59b8559c974cd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 18 Sep 2023 14:05:55 +0200 Subject: [PATCH] Test mbedtls_ssl_decrypt_buf(): stream cipher, negative cases Test mbedtls_ssl_decrypt_buf() with a null cipher (the only type of stream cipher we support). Test the good case (to make sure the test code constructs the input correctly), test with an invalid MAC, and test with a shortened input. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_ssl_decrypt.function | 107 ++++++++++++++++++ tests/suites/test_suite_ssl_decrypt.misc.data | 16 +++ 2 files changed, 123 insertions(+) diff --git a/tests/suites/test_suite_ssl_decrypt.function b/tests/suites/test_suite_ssl_decrypt.function index 048093fa91..ad94a58394 100644 --- a/tests/suites/test_suite_ssl_decrypt.function +++ b/tests/suites/test_suite_ssl_decrypt.function @@ -13,6 +13,113 @@ * END_DEPENDENCIES */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_CIPHER_NULL_CIPHER */ +void ssl_decrypt_null(int hash_id) +{ + mbedtls_ssl_transform transform_in, transform_out; + mbedtls_ssl_transform_init(&transform_in); + mbedtls_ssl_transform_init(&transform_out); + const mbedtls_ssl_protocol_version version = MBEDTLS_SSL_VERSION_TLS1_2; + const mbedtls_cipher_type_t cipher_type = MBEDTLS_CIPHER_NULL; + mbedtls_record rec_good = { + .ctr = { 0 }, + .type = MBEDTLS_SSL_MSG_APPLICATION_DATA, + .ver = { 0, 0 }, /* Will be set by a function call below */ + .buf = NULL, + .buf_len = 0, + .data_offset = 0, + .data_len = 0, +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + .cid_len = 0, + .cid = { 0 }, +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + }; + mbedtls_ssl_write_version(rec_good.ver, + MBEDTLS_SSL_TRANSPORT_STREAM, + version); + const char sample_plaintext[3] = "ABC"; + mbedtls_ssl_context ssl; + mbedtls_ssl_init(&ssl); + uint8_t *buf = NULL; + + MD_OR_USE_PSA_INIT(); + + TEST_EQUAL(mbedtls_test_ssl_build_transforms(&transform_in, &transform_out, + cipher_type, hash_id, 0, 0, + version, + 0, 0), 0); + + const size_t plaintext_length = sizeof(sample_plaintext); + rec_good.buf_len = plaintext_length + transform_in.maclen; + rec_good.data_len = plaintext_length; + TEST_CALLOC(rec_good.buf, rec_good.buf_len); + memcpy(rec_good.buf, sample_plaintext, plaintext_length); + TEST_EQUAL(mbedtls_test_ssl_prepare_record_mac(&rec_good, + &transform_out), 0); + + /* Good case */ + mbedtls_record rec = rec_good; + TEST_EQUAL(mbedtls_ssl_decrypt_buf(&ssl, &transform_in, &rec), 0); + + /* Change any one byte of the plaintext or MAC. The MAC will be wrong. */ + TEST_CALLOC(buf, rec.buf_len); + for (size_t i = 0; i < rec.buf_len; i++) { + mbedtls_test_set_step(i); + rec = rec_good; + rec.buf = buf; + memcpy(buf, rec_good.buf, rec.buf_len); + buf[i] ^= 1; + TEST_EQUAL(mbedtls_ssl_decrypt_buf(&ssl, &transform_in, &rec), + MBEDTLS_ERR_SSL_INVALID_MAC); + } + mbedtls_free(buf); + buf = NULL; + + /* Shorter input buffer. Either the MAC will be wrong, or there isn't + * enough room for a MAC. */ + for (size_t n = 1; n < rec.buf_len; n++) { + mbedtls_test_set_step(n); + rec = rec_good; + TEST_CALLOC(buf, n); + rec.buf = buf; + rec.buf_len = n; + rec.data_len = n; + memcpy(buf, rec_good.buf, n); + TEST_EQUAL(mbedtls_ssl_decrypt_buf(&ssl, &transform_in, &rec), + MBEDTLS_ERR_SSL_INVALID_MAC); + mbedtls_free(buf); + buf = NULL; + } + + /* For robustness, check a 0-length buffer (non-null, then null). + * This should not reach mbedtls_ssl_decrypt_buf() as used in the library, + * so the exact error doesn't matter, but we don't want a crash. */ + { + const uint8_t buf1[1] = { 'a' }; + rec = rec_good; + /* We won't write to buf1[0] since it's out of range, so we can cast + * the const away. */ + rec.buf = (uint8_t *) buf1; + rec.buf_len = 0; + TEST_EQUAL(mbedtls_ssl_decrypt_buf(&ssl, &transform_in, &rec), + MBEDTLS_ERR_SSL_INTERNAL_ERROR); + } + rec = rec_good; + rec.buf = NULL; + rec.buf_len = 0; + TEST_EQUAL(mbedtls_ssl_decrypt_buf(&ssl, &transform_in, &rec), + MBEDTLS_ERR_SSL_INTERNAL_ERROR); + +exit: + mbedtls_ssl_transform_free(&transform_in); + mbedtls_ssl_transform_free(&transform_out); + mbedtls_free(rec_good.buf); + mbedtls_ssl_free(&ssl); + mbedtls_free(buf); + MD_OR_USE_PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_SSL_PROTO_TLS1_2 */ void ssl_decrypt_non_etm_cbc(int cipher_type, int hash_id, int trunc_hmac, int length_selector) diff --git a/tests/suites/test_suite_ssl_decrypt.misc.data b/tests/suites/test_suite_ssl_decrypt.misc.data index 6a75dd5c44..f663b262d1 100644 --- a/tests/suites/test_suite_ssl_decrypt.misc.data +++ b/tests/suites/test_suite_ssl_decrypt.misc.data @@ -1,3 +1,19 @@ +Decrypt null cipher, MD5 +depends_on:MBEDTLS_MD_CAN_MD5 +ssl_decrypt_null:MBEDTLS_MD_MD5 + +Decrypt null cipher, SHA-1 +depends_on:MBEDTLS_MD_CAN_SHA1 +ssl_decrypt_null:MBEDTLS_MD_SHA1 + +Decrypt null cipher, SHA-256 +depends_on:MBEDTLS_MD_CAN_SHA256 +ssl_decrypt_null:MBEDTLS_MD_SHA256 + +Decrypt null cipher, SHA-384 +depends_on:MBEDTLS_MD_CAN_SHA384 +ssl_decrypt_null:MBEDTLS_MD_SHA384 + Decrypt CBC !EtM, AES MD5 !trunc, empty plaintext, minpad depends_on:MBEDTLS_AES_C:MBEDTLS_MD_CAN_MD5 ssl_decrypt_non_etm_cbc:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_MD_MD5:0:-1