--- sys/opencrypto/ktls_ocf.c.orig +++ sys/opencrypto/ktls_ocf.c @@ -500,13 +500,14 @@ iov[0].iov_base = &ad; iov[0].iov_len = sizeof(ad); skip = sizeof(*hdr) + AES_BLOCK_LEN; - for (i = 1, n = m; n != NULL; i++, n = n->m_next) { + for (i = 1, n = m; n != NULL; n = n->m_next) { if (n->m_len < skip) { skip -= n->m_len; continue; } iov[i].iov_base = mtod(n, char *) + skip; iov[i].iov_len = n->m_len - skip; + i++; skip = 0; } uio.uio_iov = iov; --- tests/sys/kern/ktls_test.c.orig +++ tests/sys/kern/ktls_test.c @@ -303,6 +303,15 @@ ATF_REQUIRE(fcntl(fd, F_SETFL, flags) != -1); } +static void +tcp_nodelay(int fd) +{ + int nodelay = 1; + + ATF_REQUIRE(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, + sizeof(nodelay)) == 0); +} + static bool cbc_crypt(const EVP_CIPHER *cipher, const char *key, const char *iv, const char *input, char *output, size_t size, int enc) @@ -1920,6 +1929,55 @@ close_sockets_ignore_errors(sockets); } +static void +test_ktls_receive_split_record(const atf_tc_t *tc, struct tls_enable *en, + uint64_t seqno, size_t len, size_t first_len) +{ + char *plaintext, *received, *outbuf; + size_t outbuf_cap, outbuf_len; + ssize_t rv; + int sockets[2]; + + ATF_REQUIRE(len <= TLS_MAX_MSG_SIZE_V10_2); + + plaintext = alloc_buffer(len); + received = malloc(len); + outbuf_cap = tls_header_len(en) + len + tls_trailer_len(en); + outbuf = malloc(outbuf_cap); + + ATF_REQUIRE_MSG(open_sockets(tc, sockets), "failed to create sockets"); + + ATF_REQUIRE(setsockopt(sockets[0], IPPROTO_TCP, TCP_RXTLS_ENABLE, en, + sizeof(*en)) == 0); + check_tls_mode(tc, sockets[0], TCP_RXTLS_MODE); + + fd_set_blocking(sockets[0]); + fd_set_blocking(sockets[1]); + + outbuf_len = encrypt_tls_record(tc, en, TLS_RLTYPE_APP, seqno, + plaintext, len, outbuf, outbuf_cap, 0); + ATF_REQUIRE(first_len < outbuf_len); + + tcp_nodelay(sockets[1]); + rv = write(sockets[1], outbuf, first_len); + ATF_REQUIRE_INTEQ((ssize_t)(first_len), rv); + + rv = write(sockets[1], outbuf + first_len, outbuf_len - first_len); + ATF_REQUIRE_INTEQ((ssize_t)(outbuf_len - first_len), rv); + + rv = ktls_receive_tls_record(en, sockets[0], TLS_RLTYPE_APP, received, + len); + ATF_REQUIRE_INTEQ((ssize_t)len, rv); + + ATF_REQUIRE(memcmp(plaintext, received, len) == 0); + + free(outbuf); + free(received); + free(plaintext); + + close_sockets(sockets); +} + #define TLS_10_TESTS(M) \ M(aes128_cbc_1_0_sha1, CRYPTO_AES_CBC, 128 / 8, \ CRYPTO_SHA1_HMAC, TLS_MINOR_VER_ZERO) \ @@ -2360,6 +2418,26 @@ auth_alg, minor, name) \ ATF_TP_ADD_TC(tp, ktls_receive_##cipher_name##_##name); +#define GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, name, len, first_len) \ +ATF_TC_WITHOUT_HEAD(ktls_receive_##cipher_name##_split_##name); \ +ATF_TC_BODY(ktls_receive_##cipher_name##_split_##name, tc) \ +{ \ + struct tls_enable en; \ + uint64_t seqno; \ + \ + ATF_REQUIRE_KTLS(); \ + seqno = random(); \ + build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor, \ + seqno, &en); \ + test_ktls_receive_split_record(tc, &en, seqno, len, first_len); \ + free_tls_enable(&en); \ +} + +#define ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, name) \ + ATF_TP_ADD_TC(tp, ktls_receive_##cipher_name##_split_##name); + #define GEN_RECEIVE_TESTS(cipher_name, cipher_alg, key_size, auth_alg, \ minor) \ GEN_RECEIVE_APP_DATA_TEST(cipher_name, cipher_alg, key_size, \ @@ -2381,7 +2459,22 @@ tls_minimum_record_payload(&en) - 1) \ GEN_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ auth_alg, minor, oversized_record, \ - TLS_MAX_MSG_SIZE_V10_2 * 2) + TLS_MAX_MSG_SIZE_V10_2 * 2) \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, header, 64, \ + sizeof(struct tls_record_layer)); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, full_header, 64, \ + tls_header_len(&en)); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, half, 64, \ + tls_header_len(&en) + 32); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_start, 64, \ + tls_header_len(&en) + 64); \ + GEN_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_middle, 64, \ + tls_header_len(&en) + 64 + tls_trailer_len(&en) / 2); #define ADD_RECEIVE_TESTS(cipher_name, cipher_alg, key_size, auth_alg, \ minor) \ @@ -2402,7 +2495,17 @@ ADD_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ auth_alg, minor, small_record) \ ADD_RECEIVE_BAD_SIZE_TEST(cipher_name, cipher_alg, key_size, \ - auth_alg, minor, oversized_record) + auth_alg, minor, oversized_record) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, header) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, full_header) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, half) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_start) \ + ADD_RECEIVE_SPLIT_RECORD_TEST(cipher_name, cipher_alg, \ + key_size, auth_alg, minor, trailer_middle) \ /* * For each supported cipher suite, run several receive tests: @@ -2425,6 +2528,9 @@ * size * * - a test with an oversized TLS record + * + * - tests of a single record whose data is split across two writes, + * with each test using a different split point */ AES_CBC_NONZERO_TESTS(GEN_RECEIVE_TESTS); AES_GCM_TESTS(GEN_RECEIVE_TESTS);