diff --git a/tests/sys/kern/ktls_test.c b/tests/sys/kern/ktls_test.c --- a/tests/sys/kern/ktls_test.c +++ b/tests/sys/kern/ktls_test.c @@ -270,8 +270,8 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ /* * 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 @@ 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 @@ #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 @@ 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 @@ 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 @@ * * - 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_ tests + * do not necessarily test 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 @@ * 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 @@ * 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 @@ 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 */