git: 64811651aa7c - main - ktls: Add tests for software AES-CBC decryption for TLS 1.1+.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 15 Nov 2022 20:04:18 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=64811651aa7c401e5b520877ccd04e9eeab425e1

commit 64811651aa7c401e5b520877ccd04e9eeab425e1
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-11-15 20:02:28 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-11-15 20:02:28 +0000

    ktls: Add tests for software AES-CBC decryption for TLS 1.1+.
    
    Reviewed by:    markj
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D37371
---
 tests/sys/kern/ktls_test.c | 233 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 204 insertions(+), 29 deletions(-)

diff --git a/tests/sys/kern/ktls_test.c b/tests/sys/kern/ktls_test.c
index 488b98725d09..3ad733e73f75 100644
--- a/tests/sys/kern/ktls_test.c
+++ b/tests/sys/kern/ktls_test.c
@@ -270,8 +270,8 @@ fd_set_blocking(int fd)
 }
 
 static bool
-cbc_decrypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
-    const char *input, char *output, size_t size)
+cbc_crypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
+    const char *input, char *output, size_t size, int enc)
 {
 	EVP_CIPHER_CTX *ctx;
 	int outl, total;
@@ -283,7 +283,7 @@ cbc_decrypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
 		return (false);
 	}
 	if (EVP_CipherInit_ex(ctx, cipher, NULL, (const u_char *)key,
-	    (const u_char *)iv, 0) != 1) {
+	    (const u_char *)iv, enc) != 1) {
 		warnx("EVP_CipherInit_ex failed: %s",
 		    ERR_error_string(ERR_get_error(), NULL));
 		EVP_CIPHER_CTX_free(ctx);
@@ -315,12 +315,25 @@ cbc_decrypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
 }
 
 static bool
-verify_hash(const EVP_MD *md, const void *key, size_t key_len, const void *aad,
-    size_t aad_len, const void *buffer, size_t len, const void *digest)
+cbc_encrypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
+    const char *input, char *output, size_t size)
+{
+	return (cbc_crypt(cipher, key, iv, input, output, size, 1));
+}
+
+static bool
+cbc_decrypt(const EVP_CIPHER *cipher, const char *key, const char *iv,
+    const char *input, char *output, size_t size)
+{
+	return (cbc_crypt(cipher, key, iv, input, output, size, 0));
+}
+
+static bool
+compute_hash(const EVP_MD *md, const void *key, size_t key_len, const void *aad,
+    size_t aad_len, const void *buffer, size_t len, void *digest,
+    u_int *digest_len)
 {
 	HMAC_CTX *ctx;
-	unsigned char digest2[EVP_MAX_MD_SIZE];
-	u_int digest_len;
 
 	ctx = HMAC_CTX_new();
 	if (ctx == NULL) {
@@ -346,13 +359,26 @@ verify_hash(const EVP_MD *md, const void *key, size_t key_len, const void *aad,
 		HMAC_CTX_free(ctx);
 		return (false);
 	}
-	if (HMAC_Final(ctx, digest2, &digest_len) != 1) {
+	if (HMAC_Final(ctx, digest, digest_len) != 1) {
 		warnx("HMAC_Final failed: %s",
 		    ERR_error_string(ERR_get_error(), NULL));
 		HMAC_CTX_free(ctx);
 		return (false);
 	}
 	HMAC_CTX_free(ctx);
+	return (true);
+}
+
+static bool
+verify_hash(const EVP_MD *md, const void *key, size_t key_len, const void *aad,
+    size_t aad_len, const void *buffer, size_t len, const void *digest)
+{
+	unsigned char digest2[EVP_MAX_MD_SIZE];
+	u_int digest_len;
+
+	if (!compute_hash(md, key, key_len, aad, aad_len, buffer, len, digest2,
+	    &digest_len))
+		return (false);
 	if (memcmp(digest, digest2, digest_len) != 0) {
 		warnx("HMAC mismatch");
 		return (false);
@@ -877,8 +903,62 @@ decrypt_tls_record(struct tls_enable *en, uint64_t seqno, const void *src,
 /*
  * Encrypt a TLS record of type 'record_type' with payload 'len' bytes
  * long at 'src' and store the result at 'dst'.  If 'dst' doesn't have
- * sufficient room ('avail'), fail the test.
+ * sufficient room ('avail'), fail the test.  'padding' is the amount
+ * of additional padding to include beyond any amount mandated by the
+ * cipher suite.
  */
+static size_t
+encrypt_tls_aes_cbc_mte(struct tls_enable *en, uint8_t record_type,
+    uint64_t seqno, const void *src, size_t len, void *dst, size_t avail,
+    size_t padding)
+{
+	struct tls_record_layer *hdr;
+	struct tls_mac_data aad;
+	char *buf, *iv;
+	size_t hdr_len, mac_len, record_len;
+	u_int digest_len, i;
+
+	ATF_REQUIRE(padding % 16 == 0);
+
+	hdr = dst;
+	buf = dst;
+
+	hdr_len = tls_header_len(en);
+	mac_len = tls_mac_len(en);
+	padding += (AES_BLOCK_LEN - (len + mac_len) % AES_BLOCK_LEN);
+	ATF_REQUIRE(padding > 0 && padding <= 255);
+
+	record_len = hdr_len + len + mac_len + padding;
+	ATF_REQUIRE(record_len <= avail);
+
+	hdr->tls_type = record_type;
+	hdr->tls_vmajor = TLS_MAJOR_VER_ONE;
+	hdr->tls_vminor = en->tls_vminor;
+	hdr->tls_length = htons(record_len - sizeof(*hdr));
+	iv = (char *)(hdr + 1);
+	for (i = 0; i < AES_BLOCK_LEN; i++)
+		iv[i] = rdigit();
+
+	/* Copy plaintext to ciphertext region. */
+	memcpy(buf + hdr_len, src, len);
+
+	/* Compute HMAC. */
+	tls_mte_aad(en, len, hdr, seqno, &aad);
+	ATF_REQUIRE(compute_hash(tls_EVP_MD(en), en->auth_key, en->auth_key_len,
+	    &aad, sizeof(aad), src, len, buf + hdr_len + len, &digest_len));
+	ATF_REQUIRE(digest_len == mac_len);
+
+	/* Store padding. */
+	for (i = 0; i < padding; i++)
+		buf[hdr_len + len + mac_len + i] = padding - 1;
+
+	/* Encrypt the record. */
+	ATF_REQUIRE(cbc_encrypt(tls_EVP_CIPHER(en), en->cipher_key, iv,
+	    buf + hdr_len, buf + hdr_len, len + mac_len + padding));
+
+	return (record_len);
+}
+
 static size_t
 encrypt_tls_12_aead(struct tls_enable *en, uint8_t record_type, uint64_t seqno,
     const void *src, size_t len, void *dst)
@@ -980,8 +1060,12 @@ static size_t
 encrypt_tls_record(struct tls_enable *en, uint8_t record_type, uint64_t seqno,
     const void *src, size_t len, void *dst, size_t avail, size_t padding)
 {
-	return (encrypt_tls_aead(en, record_type, seqno, src, len, dst, avail,
-	    padding));
+	if (en->cipher_algorithm == CRYPTO_AES_CBC)
+		return (encrypt_tls_aes_cbc_mte(en, record_type, seqno, src,
+		    len, dst, avail, padding));
+	else
+		return (encrypt_tls_aead(en, record_type, seqno, src, len,
+		    dst, avail, padding));
 }
 
 static void
@@ -1389,9 +1473,9 @@ test_ktls_receive_app_data(const atf_tc_t *tc, struct tls_enable *en,
 
 #define	TLS_10_TESTS(M)							\
 	M(aes128_cbc_1_0_sha1, CRYPTO_AES_CBC, 128 / 8,			\
-	    CRYPTO_SHA1_HMAC)						\
+	    CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO)			\
 	M(aes256_cbc_1_0_sha1, CRYPTO_AES_CBC, 256 / 8,			\
-	    CRYPTO_SHA1_HMAC)
+	    CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO)
 
 #define	TLS_13_TESTS(M)							\
 	M(aes128_gcm_1_3, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,		\
@@ -1401,11 +1485,7 @@ test_ktls_receive_app_data(const atf_tc_t *tc, struct tls_enable *en,
 	M(chacha20_poly1305_1_3, CRYPTO_CHACHA20_POLY1305, 256 / 8, 0,	\
 	    TLS_MINOR_VER_THREE)
 
-#define	AES_CBC_TESTS(M)						\
-	M(aes128_cbc_1_0_sha1, CRYPTO_AES_CBC, 128 / 8,			\
-	    CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO)			\
-	M(aes256_cbc_1_0_sha1, CRYPTO_AES_CBC, 256 / 8,			\
-	    CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO)			\
+#define	AES_CBC_NONZERO_TESTS(M)					\
 	M(aes128_cbc_1_1_sha1, CRYPTO_AES_CBC, 128 / 8,			\
 	    CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ONE)			\
 	M(aes256_cbc_1_1_sha1, CRYPTO_AES_CBC, 256 / 8,			\
@@ -1423,6 +1503,10 @@ test_ktls_receive_app_data(const atf_tc_t *tc, struct tls_enable *en,
 	M(aes256_cbc_1_2_sha384, CRYPTO_AES_CBC, 256 / 8,		\
 	    CRYPTO_SHA2_384_HMAC, TLS_MINOR_VER_TWO)			\
 
+#define	AES_CBC_TESTS(M)						\
+	TLS_10_TESTS(M)							\
+	AES_CBC_NONZERO_TESTS(M)
+
 #define AES_GCM_TESTS(M)						\
 	M(aes128_gcm_1_2, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,		\
 	    TLS_MINOR_VER_TWO)						\
@@ -1727,22 +1811,111 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc)			\
  *
  * - a long test which sends 64KB of application data (split across
  *   multiple TLS records)
- *
- * Note that receive is currently only supported for TLS 1.2 AEAD
- * cipher suites.
  */
+AES_CBC_NONZERO_TESTS(GEN_RECEIVE_TESTS);
 AES_GCM_TESTS(GEN_RECEIVE_TESTS);
 CHACHA20_TESTS(GEN_RECEIVE_TESTS);
 
-#define GEN_PADDING_RECEIVE_TESTS(cipher_name, cipher_alg, key_size,	\
-	    auth_alg, minor)						\
+#define	GEN_RECEIVE_MTE_PADDING_TESTS(cipher_name, cipher_alg,		\
+	    key_size, auth_alg, minor)					\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_1, 1, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_2, 2, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_3, 3, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_4, 4, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_5, 5, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_6, 6, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_7, 7, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_8, 8, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_9, 9, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_10, 10, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_11, 11, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_12, 12, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_13, 13, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_14, 14, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_15, 15, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_16, 16, 0)				\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_16_extra, 16, 16)			\
+	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_32_extra, 16, 32)
+
+#define ADD_RECEIVE_MTE_PADDING_TESTS(cipher_name, cipher_alg,		\
+	    key_size, auth_alg, minor)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_1)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_2)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_3)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_4)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_5)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_6)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_7)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_8)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_9)					\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_10)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_11)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_12)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_13)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_14)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_15)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_16)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_16_extra)				\
+	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
+	    auth_alg, minor, padding_32_extra)
+
+/*
+ * For AES-CBC MTE cipher suites using padding, add tests of messages
+ * with each possible padding size.  Note that the padding_<N> tests
+ * do not necessarily test <N> bytes of padding as the padding is a
+ * function of the cipher suite's MAC length.  However, cycling
+ * through all of the payload sizes from 1 to 16 should exercise all
+ * of the possible padding lengths for each suite.
+ *
+ * Two additional tests check for additional padding with an extra
+ * 16 or 32 bytes beyond the normal padding.
+ */
+AES_CBC_NONZERO_TESTS(GEN_RECEIVE_MTE_PADDING_TESTS);
+
+#define GEN_RECEIVE_TLS13_PADDING_TESTS(cipher_name, cipher_alg,	\
+	    key_size, auth_alg, minor)					\
 	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
 	    auth_alg, minor, short_padded, 64, 16)			\
 	GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
 	    auth_alg, minor, long_padded, 64 * 1024, 15)
 
-#define ADD_PADDING_RECEIVE_TESTS(cipher_name, cipher_alg, key_size,	\
-	    auth_alg, minor)						\
+#define ADD_RECEIVE_TLS13_PADDING_TESTS(cipher_name, cipher_alg,	\
+	    key_size, auth_alg, minor)					\
 	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
 	    auth_alg, minor, short_padded)				\
 	ADD_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size,	\
@@ -1752,7 +1925,7 @@ CHACHA20_TESTS(GEN_RECEIVE_TESTS);
  * For TLS 1.3 cipher suites, run two additional receive tests which
  * use add padding to each record.
  */
-TLS_13_TESTS(GEN_PADDING_RECEIVE_TESTS);
+TLS_13_TESTS(GEN_RECEIVE_TLS13_PADDING_TESTS);
 
 static void
 test_ktls_invalid_receive_cipher_suite(const atf_tc_t *tc,
@@ -1833,7 +2006,7 @@ ATF_TC_BODY(ktls_receive_unsupported_##name, tc)			\
  * Ensure that valid cipher suites not supported for receive are
  * rejected.
  */
-AES_CBC_TESTS(GEN_UNSUPPORTED_RECEIVE_TEST);
+TLS_10_TESTS(GEN_UNSUPPORTED_RECEIVE_TEST);
 
 /*
  * Try to perform an invalid sendto(2) on a TXTLS-enabled socket, to exercise
@@ -1887,10 +2060,12 @@ ATF_TP_ADD_TCS(tp)
 	INVALID_CIPHER_SUITES(ADD_INVALID_TRANSMIT_TEST);
 
 	/* Receive tests */
-	AES_CBC_TESTS(ADD_UNSUPPORTED_RECEIVE_TEST);
+	TLS_10_TESTS(ADD_UNSUPPORTED_RECEIVE_TEST);
+	AES_CBC_NONZERO_TESTS(ADD_RECEIVE_TESTS);
 	AES_GCM_TESTS(ADD_RECEIVE_TESTS);
 	CHACHA20_TESTS(ADD_RECEIVE_TESTS);
-	TLS_13_TESTS(ADD_PADDING_RECEIVE_TESTS);
+	AES_CBC_NONZERO_TESTS(ADD_RECEIVE_MTE_PADDING_TESTS);
+	TLS_13_TESTS(ADD_RECEIVE_TLS13_PADDING_TESTS);
 	INVALID_CIPHER_SUITES(ADD_INVALID_RECEIVE_TEST);
 
 	/* Miscellaneous */