+#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS) \
+ && !defined(OPENSSL_NO_SOCK)
+
+/* sock must be connected */
+static int ktls_chk_platform(int sock)
+{
+ if (!ktls_enable(sock))
+ return 0;
+ return 1;
+}
+
+static int ping_pong_query(SSL *clientssl, SSL *serverssl, int cfd, int sfd)
+{
+ static char count = 1;
+ unsigned char cbuf[16000] = {0};
+ unsigned char sbuf[16000];
+ size_t err = 0;
+ char crec_wseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char crec_wseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char crec_rseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char crec_rseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_wseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_wseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_rseq_before[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+ char srec_rseq_after[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+
+ cbuf[0] = count++;
+ memcpy(crec_wseq_before, &clientssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(crec_rseq_before, &clientssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_wseq_before, &serverssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_rseq_before, &serverssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+
+ if (!TEST_true(SSL_write(clientssl, cbuf, sizeof(cbuf)) == sizeof(cbuf)))
+ goto end;
+
+ while ((err = SSL_read(serverssl, &sbuf, sizeof(sbuf))) != sizeof(sbuf)) {
+ if (SSL_get_error(serverssl, err) != SSL_ERROR_WANT_READ) {
+ goto end;
+ }
+ }
+
+ if (!TEST_true(SSL_write(serverssl, sbuf, sizeof(sbuf)) == sizeof(sbuf)))
+ goto end;
+
+ while ((err = SSL_read(clientssl, &cbuf, sizeof(cbuf))) != sizeof(cbuf)) {
+ if (SSL_get_error(clientssl, err) != SSL_ERROR_WANT_READ) {
+ goto end;
+ }
+ }
+
+ memcpy(crec_wseq_after, &clientssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(crec_rseq_after, &clientssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_wseq_after, &serverssl->rlayer.write_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+ memcpy(srec_rseq_after, &serverssl->rlayer.read_sequence,
+ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+
+ /* verify the payload */
+ if (!TEST_mem_eq(cbuf, sizeof(cbuf), sbuf, sizeof(sbuf)))
+ goto end;
+
+ /* ktls is used then kernel sequences are used instead of OpenSSL sequences */
+ if (clientssl->mode & SSL_MODE_NO_KTLS_TX) {
+ if (!TEST_mem_ne(crec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(crec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ if (serverssl->mode & SSL_MODE_NO_KTLS_TX) {
+ if (!TEST_mem_ne(srec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(srec_wseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_wseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ if (clientssl->mode & SSL_MODE_NO_KTLS_RX) {
+ if (!TEST_mem_ne(crec_rseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_rseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(crec_rseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ crec_rseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ if (serverssl->mode & SSL_MODE_NO_KTLS_RX) {
+ if (!TEST_mem_ne(srec_rseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_rseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ } else {
+ if (!TEST_mem_eq(srec_rseq_before, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE,
+ srec_rseq_after, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE))
+ goto end;
+ }
+
+ return 1;
+end:
+ return 0;
+}
+
+static int execute_test_ktls(int cis_ktls_tx, int cis_ktls_rx,
+ int sis_ktls_tx, int sis_ktls_rx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ int cfd, sfd;
+
+ if (!TEST_true(create_test_sockets(&cfd, &sfd)))
+ goto end;
+
+ /* Skip this test if the platform does not support ktls */
+ if (!ktls_chk_platform(cfd))
+ return 1;
+
+ /* Create a session based on SHA-256 */
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_2_VERSION, TLS1_2_VERSION,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ "AES128-GCM-SHA256"))
+ || !TEST_true(create_ssl_objects2(sctx, cctx, &serverssl,
+ &clientssl, sfd, cfd)))
+ goto end;
+
+ if (!cis_ktls_tx) {
+ if (!TEST_true(SSL_set_mode(clientssl, SSL_MODE_NO_KTLS_TX)))
+ goto end;
+ }
+
+ if (!sis_ktls_tx) {
+ if (!TEST_true(SSL_set_mode(serverssl, SSL_MODE_NO_KTLS_TX)))
+ goto end;
+ }
+
+ if (!cis_ktls_rx) {
+ if (!TEST_true(SSL_set_mode(clientssl, SSL_MODE_NO_KTLS_RX)))
+ goto end;
+ }
+
+ if (!sis_ktls_rx) {
+ if (!TEST_true(SSL_set_mode(serverssl, SSL_MODE_NO_KTLS_RX)))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ if (!cis_ktls_tx) {
+ if (!TEST_false(BIO_get_ktls_send(clientssl->wbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_send(clientssl->wbio)))
+ goto end;
+ }
+
+ if (!sis_ktls_tx) {
+ if (!TEST_false(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+ }
+
+ if (!cis_ktls_rx) {
+ if (!TEST_false(BIO_get_ktls_recv(clientssl->rbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_recv(clientssl->rbio)))
+ goto end;
+ }
+
+ if (!sis_ktls_rx) {
+ if (!TEST_false(BIO_get_ktls_recv(serverssl->rbio)))
+ goto end;
+ } else {
+ if (!TEST_true(BIO_get_ktls_recv(serverssl->rbio)))
+ goto end;
+ }
+
+ if (!TEST_true(ping_pong_query(clientssl, serverssl, cfd, sfd)))
+ goto end;
+
+ testresult = 1;
+end:
+ if (clientssl) {
+ SSL_shutdown(clientssl);
+ SSL_free(clientssl);
+ }
+ if (serverssl) {
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ }
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ serverssl = clientssl = NULL;
+ return testresult;
+}
+
+#define SENDFILE_SZ (16 * 4096)
+#define SENDFILE_CHUNK (4 * 4096)
+#define min(a,b) ((a) > (b) ? (b) : (a))
+
+static int test_ktls_sendfile(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ unsigned char *buf, *buf_dst;
+ BIO *out = NULL, *in = NULL;
+ int cfd, sfd, ffd, err;
+ ssize_t chunk_size = 0;
+ off_t chunk_off = 0;
+ int testresult = 0;
+ FILE *ffdp;
+
+ buf = OPENSSL_zalloc(SENDFILE_SZ);
+ buf_dst = OPENSSL_zalloc(SENDFILE_SZ);
+ if (!TEST_ptr(buf) || !TEST_ptr(buf_dst)
+ || !TEST_true(create_test_sockets(&cfd, &sfd)))
+ goto end;
+
+ /* Skip this test if the platform does not support ktls */
+ if (!ktls_chk_platform(sfd)) {
+ testresult = 1;
+ goto end;
+ }
+
+ /* Create a session based on SHA-256 */
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_2_VERSION, TLS1_2_VERSION,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ "AES128-GCM-SHA256"))
+ || !TEST_true(create_ssl_objects2(sctx, cctx, &serverssl,
+ &clientssl, sfd, cfd)))
+ goto end;
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_true(BIO_get_ktls_send(serverssl->wbio)))
+ goto end;
+
+ RAND_bytes(buf, SENDFILE_SZ);
+ out = BIO_new_file(tmpfilename, "wb");
+ if (!TEST_ptr(out))
+ goto end;
+
+ if (BIO_write(out, buf, SENDFILE_SZ) != SENDFILE_SZ)
+ goto end;
+
+ BIO_free(out);
+ out = NULL;
+ in = BIO_new_file(tmpfilename, "rb");
+ BIO_get_fp(in, &ffdp);
+ ffd = fileno(ffdp);
+
+ while (chunk_off < SENDFILE_SZ) {
+ chunk_size = min(SENDFILE_CHUNK, SENDFILE_SZ - chunk_off);
+ while ((err = SSL_sendfile(serverssl,
+ ffd,
+ chunk_off,
+ chunk_size,
+ 0)) != chunk_size) {
+ if (SSL_get_error(serverssl, err) != SSL_ERROR_WANT_WRITE)
+ goto end;
+ }
+ while ((err = SSL_read(clientssl,
+ buf_dst + chunk_off,
+ chunk_size)) != chunk_size) {
+ if (SSL_get_error(clientssl, err) != SSL_ERROR_WANT_READ)
+ goto end;
+ }
+
+ /* verify the payload */
+ if (!TEST_mem_eq(buf_dst + chunk_off,
+ chunk_size,
+ buf + chunk_off,
+ chunk_size))
+ goto end;
+
+ chunk_off += chunk_size;
+ }
+
+ testresult = 1;
+end:
+ if (clientssl) {
+ SSL_shutdown(clientssl);
+ SSL_free(clientssl);
+ }
+ if (serverssl) {
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ }
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ serverssl = clientssl = NULL;
+ BIO_free(out);
+ BIO_free(in);
+ OPENSSL_free(buf);
+ OPENSSL_free(buf_dst);
+ return testresult;
+}
+
+static int test_ktls_no_txrx_client_no_txrx_server(void)
+{
+ return execute_test_ktls(0, 0, 0, 0);
+}
+
+static int test_ktls_no_rx_client_no_txrx_server(void)
+{
+ return execute_test_ktls(1, 0, 0, 0);
+}
+
+static int test_ktls_no_tx_client_no_txrx_server(void)
+{
+ return execute_test_ktls(0, 1, 0, 0);
+}
+
+static int test_ktls_client_no_txrx_server(void)
+{
+ return execute_test_ktls(1, 1, 0, 0);
+}
+
+static int test_ktls_no_txrx_client_no_rx_server(void)
+{
+ return execute_test_ktls(0, 0, 1, 0);
+}
+
+static int test_ktls_no_rx_client_no_rx_server(void)
+{
+ return execute_test_ktls(1, 0, 1, 0);
+}
+
+static int test_ktls_no_tx_client_no_rx_server(void)
+{
+ return execute_test_ktls(0, 1, 1, 0);
+}
+
+static int test_ktls_client_no_rx_server(void)
+{
+ return execute_test_ktls(1, 1, 1, 0);
+}
+
+static int test_ktls_no_txrx_client_no_tx_server(void)
+{
+ return execute_test_ktls(0, 0, 0, 1);
+}
+
+static int test_ktls_no_rx_client_no_tx_server(void)
+{
+ return execute_test_ktls(1, 0, 0, 1);
+}
+
+static int test_ktls_no_tx_client_no_tx_server(void)
+{
+ return execute_test_ktls(0, 1, 0, 1);
+}
+
+static int test_ktls_client_no_tx_server(void)
+{
+ return execute_test_ktls(1, 1, 0, 1);
+}
+
+static int test_ktls_no_txrx_client_server(void)
+{
+ return execute_test_ktls(0, 0, 1, 1);
+}
+
+static int test_ktls_no_rx_client_server(void)
+{
+ return execute_test_ktls(1, 0, 1, 1);
+}
+
+static int test_ktls_no_tx_client_server(void)
+{
+ return execute_test_ktls(0, 1, 1, 1);
+}
+
+static int test_ktls_client_server(void)
+{
+ return execute_test_ktls(1, 1, 1, 1);
+}
+#endif
+