aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorBernard Spil <brnrd@FreeBSD.org>2020-05-23 19:35:43 +0000
committerBernard Spil <brnrd@FreeBSD.org>2020-05-23 19:35:43 +0000
commit7d2920a88632cb15846c16ad1ded880a75609db9 (patch)
treefc6454b670463490a2e987a0cbfd34de2a235a62 /security
parent4cc4fe832aea828ad373251a0fe8e35b3979d1ba (diff)
downloadports-7d2920a88632cb15846c16ad1ded880a75609db9.tar.gz
ports-7d2920a88632cb15846c16ad1ded880a75609db9.zip
security/openssl: Add kernel TLS option
Submitted by: jhb@freebsd.org Differential Revision: https://reviews.freebsd.org/D24274
Notes
Notes: svn path=/head/; revision=536339
Diffstat (limited to 'security')
-rw-r--r--security/openssl/Makefile8
-rw-r--r--security/openssl/files/extra-patch-ktls2567
-rw-r--r--security/openssl/pkg-plist3
3 files changed, 2576 insertions, 2 deletions
diff --git a/security/openssl/Makefile b/security/openssl/Makefile
index 747dab3bb244..c01cc01ae4f4 100644
--- a/security/openssl/Makefile
+++ b/security/openssl/Makefile
@@ -40,11 +40,13 @@ OPTIONS_GROUP_OPTIMIZE= ASM SSE2 THREADS
OPTIONS_DEFINE_i386= I386
OPTIONS_GROUP_PROTOCOLS=NEXTPROTONEG SCTP SSL3 TLS1 TLS1_1 TLS1_2
-OPTIONS_DEFINE= ASYNC CT MAN3 RFC3779 SHARED ZLIB
+OPTIONS_DEFINE= ASYNC CT KTLS MAN3 RFC3779 SHARED ZLIB
OPTIONS_DEFAULT=ASM ASYNC CT GOST DES EC MAN3 MD4 NEXTPROTONEG RC2 RC4 \
RMD160 SCTP SHARED SSE2 THREADS TLS1 TLS1_1 TLS1_2
+OPTIONS_EXCLUDE=${${OSVERSION} < 1300042:?KTLS:}
+
OPTIONS_GROUP_OPTIMIZE_amd64= EC
.if ${MACHINE_ARCH} == "amd64"
@@ -66,6 +68,7 @@ GOST_DESC= GOST (Russian standard)
HASHES_DESC= Hash Function Support
I386_DESC= i386 (instead of i486+)
IDEA_DESC= International Data Encryption Algorithm
+KTLS_DESC= Kernel TLS offload
MAN3_DESC= Install API manpages (section 3, 7)
MD2_DESC= MD2 (obsolete)
MD4_DESC= MD4 (unsafe)
@@ -92,7 +95,7 @@ WEAK-SSL-CIPHERS_DESC= Weak cipher support (unsafe)
ZLIB_DESC= zlib compression support
# Upstream default disabled options
-.for _option in md2 rc5 sctp ssl3 zlib weak-ssl-ciphers
+.for _option in ktls md2 rc5 sctp ssl3 zlib weak-ssl-ciphers
${_option:tu}_CONFIGURE_ON= enable-${_option}
.endfor
@@ -108,6 +111,7 @@ TLS1_1_IMPLIES= TLS1_2
EC_CONFIGURE_ON= enable-ec_nistp_64_gcc_128
I386_CONFIGURE_ON= 386
+KTLS_EXTRA_PATCHES= ${FILESDIR}/extra-patch-ktls
MAN3_EXTRA_PATCHES_OFF= ${FILESDIR}/extra-patch-util_process__docs.pl
SHARED_MAKE_ENV= SHLIBVER=${OPENSSL_SHLIBVER}
SHARED_PLIST_SUB= SHLIBVER=${OPENSSL_SHLIBVER}
diff --git a/security/openssl/files/extra-patch-ktls b/security/openssl/files/extra-patch-ktls
new file mode 100644
index 000000000000..727922833cb4
--- /dev/null
+++ b/security/openssl/files/extra-patch-ktls
@@ -0,0 +1,2567 @@
+diff --git CHANGES CHANGES
+index f4230aaac0..3cc665f654 100644
+--- CHANGES
++++ CHANGES
+@@ -306,6 +306,11 @@
+ necessary to configure just to create a source distribution.
+ [Richard Levitte]
+
++ *) Added support for Linux Kernel TLS data-path. The Linux Kernel data-path
++ improves application performance by removing data copies and providing
++ applications with zero-copy system calls such as sendfile and splice.
++ [Boris Pismenny]
++
+ Changes between 1.1.1 and 1.1.1a [20 Nov 2018]
+
+ *) Timing vulnerability in DSA signature generation
+diff --git Configure Configure
+index 2e9efaa5f3..524b58cbb9 100755
+--- Configure
++++ Configure
+@@ -331,6 +331,7 @@ my @dtls = qw(dtls1 dtls1_2);
+ # For developers: keep it sorted alphabetically
+
+ my @disablables = (
++ "ktls",
+ "afalgeng",
+ "aria",
+ "asan",
+@@ -464,6 +465,7 @@ our %disabled = ( # "what" => "comment"
+ "weak-ssl-ciphers" => "default",
+ "zlib" => "default",
+ "zlib-dynamic" => "default",
++ "ktls" => "default",
+ );
+
+ # Note: => pair form used for aesthetics, not to truly make a hash table
+@@ -1567,6 +1569,33 @@ unless ($disabled{devcryptoeng}) {
+ }
+ }
+
++unless ($disabled{ktls}) {
++ $config{ktls}="";
++ if ($target =~ m/^linux/) {
++ my $usr = "/usr/$config{cross_compile_prefix}";
++ chop($usr);
++ if ($config{cross_compile_prefix} eq "") {
++ $usr = "/usr";
++ }
++ my $minver = (4 << 16) + (13 << 8) + 0;
++ my @verstr = split(" ",`cat $usr/include/linux/version.h | grep LINUX_VERSION_CODE`);
++
++ if ($verstr[2] < $minver) {
++ disable('too-old-kernel', 'ktls');
++ }
++ } elsif ($target =~ m/^BSD/) {
++ my $cc = $config{CROSS_COMPILE}.$config{CC};
++ system("printf '#include <sys/types.h>\n#include <sys/ktls.h>' | $cc -E - >/dev/null 2>&1");
++ if ($? != 0) {
++ disable('too-old-freebsd', 'ktls');
++ }
++ } else {
++ disable('not-linux-or-freebsd', 'ktls');
++ }
++}
++
++push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
++
+ # Get the extra flags used when building shared libraries and modules. We
+ # do this late because some of them depend on %disabled.
+
+diff --git INSTALL INSTALL
+index 328ad2baf4..46735b8236 100644
+--- INSTALL
++++ INSTALL
+@@ -262,6 +262,15 @@
+ Don't build the AFALG engine. This option will be forced if
+ on a platform that does not support AFALG.
+
++ enable-ktls
++ Build with Kernel TLS support. This option will enable the
++ use of the Kernel TLS data-path, which can improve
++ performance and allow for the use of sendfile and splice
++ system calls on TLS sockets. The Kernel may use TLS
++ accelerators if any are available on the system.
++ This option will be forced off on systems that do not support
++ the Kernel TLS data-path.
++
+ enable-asan
+ Build with the Address sanitiser. This is a developer option
+ only. It may not work on all platforms and should never be
+diff --git apps/s_client.c apps/s_client.c
+index 26a6789d81..457e539b85 100644
+--- apps/s_client.c
++++ apps/s_client.c
+@@ -3262,6 +3262,12 @@ static void print_stuff(BIO *bio, SSL *s, int full)
+ BIO_printf(bio, "Expansion: %s\n",
+ expansion ? SSL_COMP_get_name(expansion) : "NONE");
+ #endif
++#ifndef OPENSSL_NO_KTLS
++ if (BIO_get_ktls_send(SSL_get_wbio(s)))
++ BIO_printf(bio_err, "Using Kernel TLS for sending\n");
++ if (BIO_get_ktls_recv(SSL_get_rbio(s)))
++ BIO_printf(bio_err, "Using Kernel TLS for receiving\n");
++#endif
+
+ #ifdef SSL_DEBUG
+ {
+diff --git apps/s_server.c apps/s_server.c
+index 0ba75999fd..ddc0b4bcd7 100644
+--- apps/s_server.c
++++ apps/s_server.c
+@@ -2923,6 +2923,12 @@ static void print_connection_info(SSL *con)
+ }
+ OPENSSL_free(exportedkeymat);
+ }
++#ifndef OPENSSL_NO_KTLS
++ if (BIO_get_ktls_send(SSL_get_wbio(con)))
++ BIO_printf(bio_err, "Using Kernel TLS for sending\n");
++ if (BIO_get_ktls_recv(SSL_get_rbio(con)))
++ BIO_printf(bio_err, "Using Kernel TLS for receiving\n");
++#endif
+
+ (void)BIO_flush(bio_s_out);
+ }
+diff --git crypto/bio/b_sock2.c crypto/bio/b_sock2.c
+index 335dfabc61..80ef348d92 100644
+--- crypto/bio/b_sock2.c
++++ crypto/bio/b_sock2.c
+@@ -12,6 +12,7 @@
+ #include <errno.h>
+
+ #include "bio_local.h"
++#include "internal/ktls.h"
+
+ #include <openssl/err.h>
+
+@@ -50,6 +51,17 @@ int BIO_socket(int domain, int socktype, int protocol, int options)
+ BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET);
+ return INVALID_SOCKET;
+ }
++# ifndef OPENSSL_NO_KTLS
++ {
++ /*
++ * The new socket is created successfully regardless of ktls_enable.
++ * ktls_enable doesn't change any functionality of the socket, except
++ * changing the setsockopt to enable the processing of ktls_start.
++ * Thus, it is not a problem to call it for non-TLS sockets.
++ */
++ ktls_enable(sock);
++ }
++# endif
+
+ return sock;
+ }
+diff --git crypto/bio/bss_conn.c crypto/bio/bss_conn.c
+index dd43a40601..3def4550cb 100644
+--- crypto/bio/bss_conn.c
++++ crypto/bio/bss_conn.c
+@@ -11,6 +11,7 @@
+ #include <errno.h>
+
+ #include "bio_local.h"
++#include "internal/ktls.h"
+
+ #ifndef OPENSSL_NO_SOCK
+
+@@ -20,6 +21,9 @@ typedef struct bio_connect_st {
+ char *param_hostname;
+ char *param_service;
+ int connect_mode;
++# ifndef OPENSSL_NO_KTLS
++ unsigned char record_type;
++# endif
+
+ BIO_ADDRINFO *addr_first;
+ const BIO_ADDRINFO *addr_iter;
+@@ -311,7 +315,12 @@ static int conn_read(BIO *b, char *out, int outl)
+
+ if (out != NULL) {
+ clear_socket_error();
+- ret = readsocket(b->num, out, outl);
++# ifndef OPENSSL_NO_KTLS
++ if (BIO_get_ktls_recv(b))
++ ret = ktls_read_record(b->num, out, outl);
++ else
++# endif
++ ret = readsocket(b->num, out, outl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (BIO_sock_should_retry(ret))
+@@ -336,7 +345,16 @@ static int conn_write(BIO *b, const char *in, int inl)
+ }
+
+ clear_socket_error();
+- ret = writesocket(b->num, in, inl);
++# ifndef OPENSSL_NO_KTLS
++ if (BIO_should_ktls_ctrl_msg_flag(b)) {
++ ret = ktls_send_ctrl_message(b->num, data->record_type, in, inl);
++ if (ret >= 0) {
++ ret = inl;
++ BIO_clear_ktls_ctrl_msg_flag(b);
++ }
++ } else
++# endif
++ ret = writesocket(b->num, in, inl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (BIO_sock_should_retry(ret))
+@@ -352,6 +370,13 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
+ const char **pptr = NULL;
+ long ret = 1;
+ BIO_CONNECT *data;
++# ifndef OPENSSL_NO_KTLS
++# ifdef __FreeBSD__
++ struct tls_enable *crypto_info;
++# else
++ struct tls12_crypto_info_aes_gcm_128 *crypto_info;
++# endif
++# endif
+
+ data = (BIO_CONNECT *)b->ptr;
+
+@@ -500,6 +525,31 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
+ case BIO_CTRL_EOF:
+ ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0;
+ break;
++# ifndef OPENSSL_NO_KTLS
++ case BIO_CTRL_SET_KTLS:
++# ifdef __FreeBSD__
++ crypto_info = (struct tls_enable *)ptr;
++# else
++ crypto_info = (struct tls12_crypto_info_aes_gcm_128 *)ptr;
++# endif
++ ret = ktls_start(b->num, crypto_info, sizeof(*crypto_info), num);
++ if (ret)
++ BIO_set_ktls_flag(b, num);
++ break;
++ case BIO_CTRL_GET_KTLS_SEND:
++ return BIO_should_ktls_flag(b, 1);
++ case BIO_CTRL_GET_KTLS_RECV:
++ return BIO_should_ktls_flag(b, 0);
++ case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
++ BIO_set_ktls_ctrl_msg_flag(b);
++ data->record_type = num;
++ ret = 0;
++ break;
++ case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
++ BIO_clear_ktls_ctrl_msg_flag(b);
++ ret = 0;
++ break;
++# endif
+ default:
+ ret = 0;
+ break;
+diff --git crypto/bio/bss_sock.c crypto/bio/bss_sock.c
+index 6251f3d46a..c879533fef 100644
+--- crypto/bio/bss_sock.c
++++ crypto/bio/bss_sock.c
+@@ -11,6 +11,7 @@
+ #include <errno.h>
+ #include "bio_local.h"
+ #include "internal/cryptlib.h"
++#include "internal/ktls.h"
+
+ #ifndef OPENSSL_NO_SOCK
+
+@@ -64,6 +65,17 @@ BIO *BIO_new_socket(int fd, int close_flag)
+ if (ret == NULL)
+ return NULL;
+ BIO_set_fd(ret, fd, close_flag);
++# ifndef OPENSSL_NO_KTLS
++ {
++ /*
++ * The new socket is created successfully regardless of ktls_enable.
++ * ktls_enable doesn't change any functionality of the socket, except
++ * changing the setsockopt to enable the processing of ktls_start.
++ * Thus, it is not a problem to call it for non-TLS sockets.
++ */
++ ktls_enable(fd);
++ }
++# endif
+ return ret;
+ }
+
+@@ -96,7 +108,12 @@ static int sock_read(BIO *b, char *out, int outl)
+
+ if (out != NULL) {
+ clear_socket_error();
+- ret = readsocket(b->num, out, outl);
++# ifndef OPENSSL_NO_KTLS
++ if (BIO_get_ktls_recv(b))
++ ret = ktls_read_record(b->num, out, outl);
++ else
++# endif
++ ret = readsocket(b->num, out, outl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (BIO_sock_should_retry(ret))
+@@ -110,10 +127,20 @@ static int sock_read(BIO *b, char *out, int outl)
+
+ static int sock_write(BIO *b, const char *in, int inl)
+ {
+- int ret;
++ int ret = 0;
+
+ clear_socket_error();
+- ret = writesocket(b->num, in, inl);
++# ifndef OPENSSL_NO_KTLS
++ if (BIO_should_ktls_ctrl_msg_flag(b)) {
++ unsigned char record_type = (intptr_t)b->ptr;
++ ret = ktls_send_ctrl_message(b->num, record_type, in, inl);
++ if (ret >= 0) {
++ ret = inl;
++ BIO_clear_ktls_ctrl_msg_flag(b);
++ }
++ } else
++# endif
++ ret = writesocket(b->num, in, inl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (BIO_sock_should_retry(ret))
+@@ -126,6 +153,13 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
+ {
+ long ret = 1;
+ int *ip;
++# ifndef OPENSSL_NO_KTLS
++# ifdef __FreeBSD__
++ struct tls_enable *crypto_info;
++# else
++ struct tls12_crypto_info_aes_gcm_128 *crypto_info;
++# endif
++# endif
+
+ switch (cmd) {
+ case BIO_C_SET_FD:
+@@ -153,6 +187,31 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
++# ifndef OPENSSL_NO_KTLS
++ case BIO_CTRL_SET_KTLS:
++# ifdef __FreeBSD__
++ crypto_info = (struct tls_enable *)ptr;
++# else
++ crypto_info = (struct tls12_crypto_info_aes_gcm_128 *)ptr;
++# endif
++ ret = ktls_start(b->num, crypto_info, sizeof(*crypto_info), num);
++ if (ret)
++ BIO_set_ktls_flag(b, num);
++ break;
++ case BIO_CTRL_GET_KTLS_SEND:
++ return BIO_should_ktls_flag(b, 1);
++ case BIO_CTRL_GET_KTLS_RECV:
++ return BIO_should_ktls_flag(b, 0);
++ case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
++ BIO_set_ktls_ctrl_msg_flag(b);
++ b->ptr = (void *)num;
++ ret = 0;
++ break;
++ case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
++ BIO_clear_ktls_ctrl_msg_flag(b);
++ ret = 0;
++ break;
++# endif
+ case BIO_CTRL_EOF:
+ ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0;
+ break;
+diff --git crypto/err/openssl.txt crypto/err/openssl.txt
+index 35512f9caf..426297da8b 100644
+--- crypto/err/openssl.txt
++++ crypto/err/openssl.txt
+@@ -1315,6 +1315,7 @@ SSL_F_SSL_RENEGOTIATE:516:SSL_renegotiate
+ SSL_F_SSL_RENEGOTIATE_ABBREVIATED:546:SSL_renegotiate_abbreviated
+ SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT:320:*
+ SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT:321:*
++SSL_F_SSL_SENDFILE:639:SSL_sendfile
+ SSL_F_SSL_SESSION_DUP:348:ssl_session_dup
+ SSL_F_SSL_SESSION_NEW:189:SSL_SESSION_new
+ SSL_F_SSL_SESSION_PRINT_FP:190:SSL_SESSION_print_fp
+diff --git crypto/evp/e_aes.c crypto/evp/e_aes.c
+index 405ddbf9bf..4640c7528a 100644
+--- crypto/evp/e_aes.c
++++ crypto/evp/e_aes.c
+@@ -2895,6 +2895,14 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
+ memcpy(ptr, c->buf, arg);
+ return 1;
+
++ case EVP_CTRL_GET_IV:
++ if (gctx->iv_gen != 1)
++ return 0;
++ if (gctx->ivlen != arg)
++ return 0;
++ memcpy(ptr, gctx->iv, arg);
++ return 1;
++
+ case EVP_CTRL_GCM_SET_IV_FIXED:
+ /* Special case: -1 length restores whole IV */
+ if (arg == -1) {
+diff --git doc/man3/BIO_ctrl.pod doc/man3/BIO_ctrl.pod
+index 60cd10883b..589338dd51 100644
+--- doc/man3/BIO_ctrl.pod
++++ doc/man3/BIO_ctrl.pod
+@@ -5,7 +5,8 @@
+ BIO_ctrl, BIO_callback_ctrl, BIO_ptr_ctrl, BIO_int_ctrl, BIO_reset,
+ BIO_seek, BIO_tell, BIO_flush, BIO_eof, BIO_set_close, BIO_get_close,
+ BIO_pending, BIO_wpending, BIO_ctrl_pending, BIO_ctrl_wpending,
+-BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb
++BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, BIO_get_ktls_send,
++BIO_get_ktls_recv
+ - BIO control operations
+
+ =head1 SYNOPSIS
+@@ -34,6 +35,9 @@ BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb
+ int BIO_get_info_callback(BIO *b, BIO_info_cb **cbp);
+ int BIO_set_info_callback(BIO *b, BIO_info_cb *cb);
+
++ int BIO_get_ktls_send(BIO *b);
++ int BIO_get_ktls_recv(BIO *b);
++
+ =head1 DESCRIPTION
+
+ BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl()
+@@ -72,6 +76,11 @@ Not all BIOs support these calls. BIO_ctrl_pending() and BIO_ctrl_wpending()
+ return a size_t type and are functions, BIO_pending() and BIO_wpending() are
+ macros which call BIO_ctrl().
+
++BIO_get_ktls_send() returns 1 if the BIO is using the Kernel TLS data-path for
++sending. Otherwise, it returns zero.
++BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
++receiving. Otherwise, it returns zero.
++
+ =head1 RETURN VALUES
+
+ BIO_reset() normally returns 1 for success and 0 or -1 for failure. File
+@@ -92,6 +101,11 @@ BIO_get_close() returns the close flag value: BIO_CLOSE or BIO_NOCLOSE.
+ BIO_pending(), BIO_ctrl_pending(), BIO_wpending() and BIO_ctrl_wpending()
+ return the amount of pending data.
+
++BIO_get_ktls_send() returns 1 if the BIO is using the Kernel TLS data-path for
++sending. Otherwise, it returns zero.
++BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
++receiving. Otherwise, it returns zero.
++
+ =head1 NOTES
+
+ BIO_flush(), because it can write data may return 0 or -1 indicating
+@@ -124,6 +138,11 @@ particular a return value of 0 can be returned if an operation is not
+ supported, if an error occurred, if EOF has not been reached and in
+ the case of BIO_seek() on a file BIO for a successful operation.
+
++=head1 HISTORY
++
++The BIO_get_ktls_send() and BIO_get_ktls_recv() functions were added in
++OpenSSL 3.0.0.
++
+ =head1 COPYRIGHT
+
+ Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+diff --git doc/man3/SSL_CTX_set_mode.pod doc/man3/SSL_CTX_set_mode.pod
+index 387d1ec1ef..373b2aa0f2 100644
+--- doc/man3/SSL_CTX_set_mode.pod
++++ doc/man3/SSL_CTX_set_mode.pod
+@@ -114,6 +114,22 @@ enables this behaviour to allow interoperability with such broken
+ implementations. Please note that setting this option breaks interoperability
+ with correct implementations. This option only applies to DTLS over SCTP.
+
++=item SSL_MODE_NO_KTLS_TX
++
++Disable the use of the kernel TLS egress data-path.
++By default kernel TLS is enabled if it is supported by the negotiated ciphersuites
++and extensions and OpenSSL has been compiled with support for it.
++The kernel TLS data-path implements the record layer,
++and the crypto algorithm. The kernel will utilize the best hardware
++available for crypto. Using the kernel data-path should reduce the memory
++footprint of OpenSSL because no buffering is required. Also, the throughput
++should improve because data copy is avoided when user data is encrypted into
++kernel memory instead of the usual encrypt than copy to kernel.
++
++Kernel TLS might not support all the features of OpenSSL. For instance,
++renegotiation, and setting the maximum fragment size is not possible as of
++Linux 4.20.
++
+ =back
+
+ All modes are off by default except for SSL_MODE_AUTO_RETRY which is on by
+@@ -134,6 +150,7 @@ L<SSL_write(3)>, L<SSL_get_error(3)>
+ =head1 HISTORY
+
+ SSL_MODE_ASYNC was added in OpenSSL 1.1.0.
++SSL_MODE_NO_KTLS_TX was first added to OpenSSL 3.0.0.
+
+ =head1 COPYRIGHT
+
+diff --git doc/man3/SSL_write.pod doc/man3/SSL_write.pod
+index a76ffbb8fd..d7900fd87b 100644
+--- doc/man3/SSL_write.pod
++++ doc/man3/SSL_write.pod
+@@ -2,12 +2,13 @@
+
+ =head1 NAME
+
+-SSL_write_ex, SSL_write - write bytes to a TLS/SSL connection
++SSL_write_ex, SSL_write, SSL_sendfile - write bytes to a TLS/SSL connection
+
+ =head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
++ ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags);
+ int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written);
+ int SSL_write(SSL *ssl, const void *buf, int num);
+
+@@ -17,6 +18,14 @@ SSL_write_ex() and SSL_write() write B<num> bytes from the buffer B<buf> into
+ the specified B<ssl> connection. On success SSL_write_ex() will store the number
+ of bytes written in B<*written>.
+
++SSL_sendfile() writes B<size> bytes from offset B<offset> in the file
++descriptor B<fd> to the specified SSL connection B<s>. This function provides
++efficient zero-copy semantics. SSL_sendfile() is available only when
++Kernel TLS is enabled, which can be checked by calling BIO_get_ktls_send().
++It is provided here to allow users to maintain the same interface.
++The meaning of B<flags> is platform dependent.
++Currently, under Linux it is ignored.
++
+ =head1 NOTES
+
+ In the paragraphs below a "write function" is defined as one of either
+@@ -104,17 +113,35 @@ You should instead call SSL_get_error() to find out if it's retryable.
+
+ =back
+
++For SSL_sendfile(), the following return values can occur:
++
++=over 4
++
++=item Z<>>= 0
++
++The write operation was successful, the return value is the number
++of bytes of the file written to the TLS/SSL connection.
++
++=item E<lt> 0
++
++The write operation was not successful, because either the connection was
++closed, an error occured or action must be taken by the calling process.
++Call SSL_get_error() with the return value to find out the reason.
++
++=back
++
+ =head1 SEE ALSO
+
+ L<SSL_get_error(3)>, L<SSL_read_ex(3)>, L<SSL_read(3)>
+ L<SSL_CTX_set_mode(3)>, L<SSL_CTX_new(3)>,
+ L<SSL_connect(3)>, L<SSL_accept(3)>
+-L<SSL_set_connect_state(3)>,
++L<SSL_set_connect_state(3)>, L<BIO_ctrl(3)>,
+ L<ssl(7)>, L<bio(7)>
+
+ =head1 HISTORY
+
+ The SSL_write_ex() function was added in OpenSSL 1.1.1.
++The SSL_sendfile() function was added in OpenSSL 3.0.0.
+
+ =head1 COPYRIGHT
+
+diff --git engines/e_afalg.c engines/e_afalg.c
+index 4b17228461..5ef3a8d457 100644
+--- engines/e_afalg.c
++++ engines/e_afalg.c
+@@ -407,7 +407,7 @@ static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in,
+ size_t inl, const unsigned char *iv,
+ unsigned int enc)
+ {
+- struct msghdr msg = { 0 };
++ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ ssize_t sbytes;
+@@ -416,6 +416,7 @@ static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in,
+ # endif
+ char cbuf[CMSG_SPACE(ALG_IV_LEN(ALG_AES_IV_LEN)) + CMSG_SPACE(ALG_OP_LEN)];
+
++ memset(&msg, 0, sizeof(msg));
+ memset(cbuf, 0, sizeof(cbuf));
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+diff --git include/internal/bio.h include/internal/bio.h
+index c343b27629..521b5fa219 100644
+--- include/internal/bio.h
++++ include/internal/bio.h
+@@ -7,6 +7,9 @@
+ * https://www.openssl.org/source/license.html
+ */
+
++#ifndef HEADER_INTERNAL_BIO_H
++# define HEADER_INTERNAL_BIO_H
++
+ #include <openssl/bio.h>
+
+ struct bio_method_st {
+@@ -31,3 +34,39 @@ void bio_cleanup(void);
+ /* Old style to new style BIO_METHOD conversion functions */
+ int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written);
+ int bread_conv(BIO *bio, char *data, size_t datal, size_t *read);
++
++/* Changes to these internal BIOs must also update include/openssl/bio.h */
++# define BIO_CTRL_SET_KTLS 72
++# define BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG 74
++# define BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG 75
++
++/*
++ * This is used with socket BIOs:
++ * BIO_FLAGS_KTLS_TX means we are using ktls with this BIO for sending.
++ * BIO_FLAGS_KTLS_TX_CTRL_MSG means we are about to send a ctrl message next.
++ * BIO_FLAGS_KTLS_RX means we are using ktls with this BIO for receiving.
++ */
++# define BIO_FLAGS_KTLS_TX 0x800
++# define BIO_FLAGS_KTLS_TX_CTRL_MSG 0x1000
++# define BIO_FLAGS_KTLS_RX 0x2000
++
++/* KTLS related controls and flags */
++# define BIO_set_ktls_flag(b, is_tx) \
++ BIO_set_flags(b, (is_tx) ? BIO_FLAGS_KTLS_TX : BIO_FLAGS_KTLS_RX)
++# define BIO_should_ktls_flag(b, is_tx) \
++ BIO_test_flags(b, (is_tx) ? BIO_FLAGS_KTLS_TX : BIO_FLAGS_KTLS_RX)
++# define BIO_set_ktls_ctrl_msg_flag(b) \
++ BIO_set_flags(b, BIO_FLAGS_KTLS_TX_CTRL_MSG)
++# define BIO_should_ktls_ctrl_msg_flag(b) \
++ BIO_test_flags(b, BIO_FLAGS_KTLS_TX_CTRL_MSG)
++# define BIO_clear_ktls_ctrl_msg_flag(b) \
++ BIO_clear_flags(b, BIO_FLAGS_KTLS_TX_CTRL_MSG)
++
++# define BIO_set_ktls(b, keyblob, is_tx) \
++ BIO_ctrl(b, BIO_CTRL_SET_KTLS, is_tx, keyblob)
++# define BIO_set_ktls_ctrl_msg(b, record_type) \
++ BIO_ctrl(b, BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG, record_type, NULL)
++# define BIO_clear_ktls_ctrl_msg(b) \
++ BIO_ctrl(b, BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG, 0, NULL)
++
++#endif
+diff --git include/internal/ktls.h include/internal/ktls.h
+new file mode 100644
+index 0000000000..209dff1689
+--- /dev/null
++++ include/internal/ktls.h
+@@ -0,0 +1,345 @@
++/*
++ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
++ *
++ * Licensed under the Apache License 2.0 (the "License"). You may not use
++ * this file except in compliance with the License. You can obtain a copy
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef OPENSSL_NO_KTLS
++# ifndef HEADER_INTERNAL_KTLS
++# define HEADER_INTERNAL_KTLS
++
++# if defined(__FreeBSD__)
++# include <sys/types.h>
++# include <sys/socket.h>
++# include <sys/ktls.h>
++# include <netinet/in.h>
++# include <netinet/tcp.h>
++# include <crypto/cryptodev.h>
++
++/*
++ * Only used by the tests in sslapitest.c.
++ */
++# define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8
++
++/*
++ * FreeBSD does not require any additional steps to enable KTLS before
++ * setting keys.
++ */
++static ossl_inline int ktls_enable(int fd)
++{
++ return 1;
++}
++
++/*
++ * The TCP_TXTLS_ENABLE socket option marks the outgoing socket buffer
++ * as using TLS. If successful, then data sent using this socket will
++ * be encrypted and encapsulated in TLS records using the tls_en.
++ * provided here.
++ */
++static ossl_inline int ktls_start(int fd,
++ struct tls_enable *tls_en,
++ size_t len, int is_tx)
++{
++ if (is_tx)
++ return setsockopt(fd, IPPROTO_TCP, TCP_TXTLS_ENABLE,
++ tls_en, sizeof(*tls_en)) ? 0 : 1;
++ else
++ return 0;
++}
++
++/*
++ * Send a TLS record using the tls_en provided in ktls_start and use
++ * record_type instead of the default SSL3_RT_APPLICATION_DATA.
++ * When the socket is non-blocking, then this call either returns EAGAIN or
++ * the entire record is pushed to TCP. It is impossible to send a partial
++ * record using this control message.
++ */
++static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
++ const void *data, size_t length)
++{
++ struct msghdr msg = { 0 };
++ int cmsg_len = sizeof(record_type);
++ struct cmsghdr *cmsg;
++ char buf[CMSG_SPACE(cmsg_len)];
++ struct iovec msg_iov; /* Vector of data to send/receive into */
++
++ msg.msg_control = buf;
++ msg.msg_controllen = sizeof(buf);
++ cmsg = CMSG_FIRSTHDR(&msg);
++ cmsg->cmsg_level = IPPROTO_TCP;
++ cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
++ cmsg->cmsg_len = CMSG_LEN(cmsg_len);
++ *((unsigned char *)CMSG_DATA(cmsg)) = record_type;
++ msg.msg_controllen = cmsg->cmsg_len;
++
++ msg_iov.iov_base = (void *)data;
++ msg_iov.iov_len = length;
++ msg.msg_iov = &msg_iov;
++ msg.msg_iovlen = 1;
++
++ return sendmsg(fd, &msg, 0);
++}
++
++static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
++{
++ return -1;
++}
++
++/*
++ * KTLS enables the sendfile system call to send data from a file over
++ * TLS.
++ */
++static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off,
++ size_t size, int flags)
++{
++ off_t sbytes;
++ int ret;
++
++ ret = sendfile(fd, s, off, size, NULL, &sbytes, flags);
++ if (ret == -1) {
++ if (errno == EAGAIN && sbytes != 0)
++ return sbytes;
++ return -1;
++ }
++ return sbytes;
++}
++# endif /* __FreeBSD__ */
++
++# if defined(OPENSSL_SYS_LINUX)
++# include <linux/version.h>
++
++# define K_MAJ 4
++# define K_MIN1 13
++# define K_MIN2 0
++# if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1, K_MIN2)
++
++# ifndef PEDANTIC
++# warning "KTLS requires Kernel Headers >= 4.13.0"
++# warning "Skipping Compilation of KTLS"
++# endif
++
++# define TLS_TX 1
++# define TLS_RX 2
++
++# define TLS_CIPHER_AES_GCM_128 51
++# define TLS_CIPHER_AES_GCM_128_IV_SIZE 8
++# define TLS_CIPHER_AES_GCM_128_KEY_SIZE 16
++# define TLS_CIPHER_AES_GCM_128_SALT_SIZE 4
++# define TLS_CIPHER_AES_GCM_128_TAG_SIZE 16
++# define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8
++
++# define TLS_SET_RECORD_TYPE 1
++
++struct tls_crypto_info {
++ unsigned short version;
++ unsigned short cipher_type;
++};
++
++struct tls12_crypto_info_aes_gcm_128 {
++ struct tls_crypto_info info;
++ unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE];
++ unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE];
++ unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE];
++ unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
++};
++
++/* Dummy functions here */
++static ossl_inline int ktls_enable(int fd)
++{
++ return 0;
++}
++
++static ossl_inline int ktls_start(int fd,
++ struct tls12_crypto_info_aes_gcm_128
++ *crypto_info, size_t len, int is_tx)
++{
++ return 0;
++}
++
++static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
++ const void *data, size_t length)
++{
++ return -1;
++}
++
++static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
++{
++ return -1;
++}
++
++static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)
++{
++ return -1;
++}
++
++# else /* KERNEL_VERSION */
++
++# include <sys/sendfile.h>
++# include <netinet/tcp.h>
++# include <linux/tls.h>
++# include <linux/socket.h>
++# include "openssl/ssl3.h"
++# include "openssl/tls1.h"
++# include "openssl/evp.h"
++
++# ifndef SOL_TLS
++# define SOL_TLS 282
++# endif
++
++# ifndef TCP_ULP
++# define TCP_ULP 31
++# endif
++
++# ifndef TLS_RX
++# define TLS_RX 2
++# endif
++
++/*
++ * When successful, this socket option doesn't change the behaviour of the
++ * TCP socket, except changing the TCP setsockopt handler to enable the
++ * processing of SOL_TLS socket options. All other functionality remains the
++ * same.
++ */
++static ossl_inline int ktls_enable(int fd)
++{
++ return setsockopt(fd, SOL_TCP, TCP_ULP, "tls", sizeof("tls")) ? 0 : 1;
++}
++
++/*
++ * The TLS_TX socket option changes the send/sendmsg handlers of the TCP socket.
++ * If successful, then data sent using this socket will be encrypted and
++ * encapsulated in TLS records using the crypto_info provided here.
++ * The TLS_RX socket option changes the recv/recvmsg handlers of the TCP socket.
++ * If successful, then data received using this socket will be decrypted,
++ * authenticated and decapsulated using the crypto_info provided here.
++ */
++static ossl_inline int ktls_start(int fd,
++ struct tls12_crypto_info_aes_gcm_128
++ *crypto_info, size_t len, int is_tx)
++{
++ return setsockopt(fd, SOL_TLS, is_tx ? TLS_TX : TLS_RX,
++ crypto_info, sizeof(*crypto_info)) ? 0 : 1;
++}
++
++/*
++ * Send a TLS record using the crypto_info provided in ktls_start and use
++ * record_type instead of the default SSL3_RT_APPLICATION_DATA.
++ * When the socket is non-blocking, then this call either returns EAGAIN or
++ * the entire record is pushed to TCP. It is impossible to send a partial
++ * record using this control message.
++ */
++static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
++ const void *data, size_t length)
++{
++ struct msghdr msg;
++ int cmsg_len = sizeof(record_type);
++ struct cmsghdr *cmsg;
++ union {
++ struct cmsghdr hdr;
++ char buf[CMSG_SPACE(sizeof(unsigned char))];
++ } cmsgbuf;
++ struct iovec msg_iov; /* Vector of data to send/receive into */
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_control = cmsgbuf.buf;
++ msg.msg_controllen = sizeof(cmsgbuf.buf);
++ cmsg = CMSG_FIRSTHDR(&msg);
++ cmsg->cmsg_level = SOL_TLS;
++ cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
++ cmsg->cmsg_len = CMSG_LEN(cmsg_len);
++ *((unsigned char *)CMSG_DATA(cmsg)) = record_type;
++ msg.msg_controllen = cmsg->cmsg_len;
++
++ msg_iov.iov_base = (void *)data;
++ msg_iov.iov_len = length;
++ msg.msg_iov = &msg_iov;
++ msg.msg_iovlen = 1;
++
++ return sendmsg(fd, &msg, 0);
++}
++
++/*
++ * KTLS enables the sendfile system call to send data from a file over TLS.
++ * @flags are ignored on Linux. (placeholder for FreeBSD sendfile)
++ * */
++static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)
++{
++ return sendfile(s, fd, &off, size);
++}
++
++# define K_MIN1_RX 17
++# if LINUX_VERSION_CODE < KERNEL_VERSION(K_MAJ, K_MIN1_RX, K_MIN2)
++
++# ifndef PEDANTIC
++# warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"
++# warning "Skipping Compilation of KTLS receive data path"
++# endif
++
++static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
++{
++ return -1;
++}
++
++# else
++
++/*
++ * Receive a TLS record using the crypto_info provided in ktls_start.
++ * The kernel strips the TLS record header, IV and authentication tag,
++ * returning only the plaintext data or an error on failure.
++ * We add the TLS record header here to satisfy routines in rec_layer_s3.c
++ */
++static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
++{
++ struct msghdr msg;
++ struct cmsghdr *cmsg;
++ union {
++ struct cmsghdr hdr;
++ char buf[CMSG_SPACE(sizeof(unsigned char))];
++ } cmsgbuf;
++ struct iovec msg_iov;
++ int ret;
++ unsigned char *p = data;
++ const size_t prepend_length = SSL3_RT_HEADER_LENGTH;
++
++ if (length < prepend_length + EVP_GCM_TLS_TAG_LEN) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_control = cmsgbuf.buf;
++ msg.msg_controllen = sizeof(cmsgbuf.buf);
++
++ msg_iov.iov_base = p + prepend_length;
++ msg_iov.iov_len = length - prepend_length - EVP_GCM_TLS_TAG_LEN;
++ msg.msg_iov = &msg_iov;
++ msg.msg_iovlen = 1;
++
++ ret = recvmsg(fd, &msg, 0);
++ if (ret < 0)
++ return ret;
++
++ if (msg.msg_controllen > 0) {
++ cmsg = CMSG_FIRSTHDR(&msg);
++ if (cmsg->cmsg_type == TLS_GET_RECORD_TYPE) {
++ p[0] = *((unsigned char *)CMSG_DATA(cmsg));
++ p[1] = TLS1_2_VERSION_MAJOR;
++ p[2] = TLS1_2_VERSION_MINOR;
++ /* returned length is limited to msg_iov.iov_len above */
++ p[3] = (ret >> 8) & 0xff;
++ p[4] = ret & 0xff;
++ ret += prepend_length;
++ }
++ }
++
++ return ret;
++}
++
++# endif
++# endif
++# endif
++# endif
++#endif
+diff --git include/openssl/bio.h include/openssl/bio.h
+index ae559a5105..fa50337aab 100644
+--- include/openssl/bio.h
++++ include/openssl/bio.h
+@@ -141,6 +141,26 @@ extern "C" {
+
+ # define BIO_CTRL_DGRAM_SET_PEEK_MODE 71
+
++/*
++ * internal BIO see include/internal/bio.h:
++ * # define BIO_CTRL_SET_KTLS_SEND 72
++ * # define BIO_CTRL_SET_KTLS_SEND_CTRL_MSG 74
++ * # define BIO_CTRL_CLEAR_KTLS_CTRL_MSG 75
++ */
++
++# define BIO_CTRL_GET_KTLS_SEND 73
++# define BIO_CTRL_GET_KTLS_RECV 76
++
++# ifndef OPENSSL_NO_KTLS
++# define BIO_get_ktls_send(b) \
++ BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL)
++# define BIO_get_ktls_recv(b) \
++ BIO_ctrl(b, BIO_CTRL_GET_KTLS_RECV, 0, NULL)
++# else
++# define BIO_get_ktls_send(b) (0)
++# define BIO_get_ktls_recv(b) (0)
++# endif
++
+ /* modifiers */
+ # define BIO_FP_READ 0x02
+ # define BIO_FP_WRITE 0x04
+diff --git include/openssl/err.h include/openssl/err.h
+index b49f88129e..dce9885d3f 100644
+--- include/openssl/err.h
++++ include/openssl/err.h
+@@ -169,6 +169,7 @@ typedef struct err_state_st {
+ # define SYS_F_STAT 22
+ # define SYS_F_FCNTL 23
+ # define SYS_F_FSTAT 24
++# define SYS_F_SENDFILE 25
+
+ /* reasons */
+ # define ERR_R_SYS_LIB ERR_LIB_SYS/* 2 */
+diff --git include/openssl/evp.h include/openssl/evp.h
+index a411f3f2f9..60103707d2 100644
+--- include/openssl/evp.h
++++ include/openssl/evp.h
+@@ -352,6 +352,8 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
+ # define EVP_CTRL_SET_PIPELINE_INPUT_LENS 0x24
+
+ # define EVP_CTRL_GET_IVLEN 0x25
++/* Get the IV used by the cipher */
++# define EVP_CTRL_GET_IV 0x26
+
+ /* Padding modes */
+ #define EVP_PADDING_PKCS7 1
+diff --git include/openssl/ssl.h include/openssl/ssl.h
+index 6724ccf2d2..48710cde1f 100644
+--- include/openssl/ssl.h
++++ include/openssl/ssl.h
+@@ -493,6 +493,10 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
+ * Support Asynchronous operation
+ */
+ # define SSL_MODE_ASYNC 0x00000100U
++/*
++ * Don't use the kernel TLS data-path for sending.
++ */
++# define SSL_MODE_NO_KTLS_TX 0x00000200U
+
+ /*
+ * When using DTLS/SCTP, include the terminating zero in the label
+@@ -506,6 +510,10 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
+ * - OpenSSL 1.1.1 and 1.1.1a
+ */
+ # define SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG 0x00000400U
++/*
++ * Don't use the kernel TLS data-path for receiving.
++ */
++# define SSL_MODE_NO_KTLS_RX 0x00000800U
+
+ /* Cert related flags */
+ /*
+@@ -1837,6 +1845,8 @@ __owur int SSL_read_early_data(SSL *s, void *buf, size_t num,
+ size_t *readbytes);
+ __owur int SSL_peek(SSL *ssl, void *buf, int num);
+ __owur int SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
++__owur ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size,
++ int flags);
+ __owur int SSL_write(SSL *ssl, const void *buf, int num);
+ __owur int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written);
+ __owur int SSL_write_early_data(SSL *s, const void *buf, size_t num,
+diff --git include/openssl/sslerr.h include/openssl/sslerr.h
+index 82983d3c1e..0bdc8f3b2c 100644
+--- include/openssl/sslerr.h
++++ include/openssl/sslerr.h
+@@ -219,6 +219,7 @@ int ERR_load_SSL_strings(void);
+ # define SSL_F_SSL_RENEGOTIATE_ABBREVIATED 546
+ # define SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT 320
+ # define SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT 321
++# define SSL_F_SSL_SENDFILE 639
+ # define SSL_F_SSL_SESSION_DUP 348
+ # define SSL_F_SSL_SESSION_NEW 189
+ # define SSL_F_SSL_SESSION_PRINT_FP 190
+diff --git ssl/record/rec_layer_s3.c ssl/record/rec_layer_s3.c
+index b2a7a47eb0..36f37c4ae2 100644
+--- ssl/record/rec_layer_s3.c
++++ ssl/record/rec_layer_s3.c
+@@ -268,11 +268,15 @@ int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
+ return -1;
+ }
+
+- /* We always act like read_ahead is set for DTLS */
+- if (!s->rlayer.read_ahead && !SSL_IS_DTLS(s))
++ /*
++ * Ktls always reads full records.
++ * Also, we always act like read_ahead is set for DTLS.
++ */
++ if (!BIO_get_ktls_recv(s->rbio) && !s->rlayer.read_ahead
++ && !SSL_IS_DTLS(s)) {
+ /* ignore max parameter */
+ max = n;
+- else {
++ } else {
+ if (max < n)
+ max = n;
+ if (max > rb->len - rb->offset)
+@@ -422,6 +426,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
+ len >= 4 * (max_send_fragment = ssl_get_max_send_fragment(s)) &&
+ s->compress == NULL && s->msg_callback == NULL &&
+ !SSL_WRITE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&
++ (BIO_get_ktls_send(s->wbio) == 0) &&
+ EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &
+ EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) {
+ unsigned char aad[13];
+@@ -751,6 +756,19 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ s->s3->empty_fragment_done = 1;
+ }
+
++ if (BIO_get_ktls_send(s->wbio)) {
++ /*
++ * ktls doesn't modify the buffer, but to avoid a warning we need to
++ * discard the const qualifier.
++ * This doesn't leak memory because the buffers have been released when
++ * switching to ktls.
++ */
++ SSL3_BUFFER_set_buf(&s->rlayer.wbuf[0], (unsigned char *)buf);
++ SSL3_BUFFER_set_offset(&s->rlayer.wbuf[0], 0);
++ SSL3_BUFFER_set_app_buffer(&s->rlayer.wbuf[0], 1);
++ goto wpacket_init_complete;
++ }
++
+ if (create_empty_fragment) {
+ wb = &s->rlayer.wbuf[0];
+ #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+@@ -820,6 +838,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ }
+ }
+
++ wpacket_init_complete:
++
+ totlen = 0;
+ /* Clear our SSL3_RECORD structures */
+ memset(wr, 0, sizeof(wr));
+@@ -861,15 +881,19 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ if (s->compress != NULL)
+ maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+
+- /* write the header */
+- if (!WPACKET_put_bytes_u8(thispkt, rectype)
++ /*
++ * When using offload kernel will write the header.
++ * Otherwise write the header now
++ */
++ if (!BIO_get_ktls_send(s->wbio)
++ && (!WPACKET_put_bytes_u8(thispkt, rectype)
+ || !WPACKET_put_bytes_u16(thispkt, version)
+ || !WPACKET_start_sub_packet_u16(thispkt)
+ || (eivlen > 0
+ && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
+ || (maxcomplen > 0
+ && !WPACKET_reserve_bytes(thispkt, maxcomplen,
+- &compressdata))) {
++ &compressdata)))) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+@@ -895,12 +919,16 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ goto err;
+ }
+ } else {
+- if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
+- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+- ERR_R_INTERNAL_ERROR);
+- goto err;
++ if (BIO_get_ktls_send(s->wbio)) {
++ SSL3_RECORD_reset_data(&wr[j]);
++ } else {
++ if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
++ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
++ ERR_R_INTERNAL_ERROR);
++ goto err;
++ }
++ SSL3_RECORD_reset_input(&wr[j]);
+ }
+- SSL3_RECORD_reset_input(&wr[j]);
+ }
+
+ if (SSL_TREAT_AS_TLS13(s)
+@@ -959,7 +987,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ * in the wb->buf
+ */
+
+- if (!SSL_WRITE_ETM(s) && mac_size != 0) {
++ if (!BIO_get_ktls_send(s->wbio) && !SSL_WRITE_ETM(s) && mac_size != 0) {
+ unsigned char *mac;
+
+ if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+@@ -975,24 +1003,26 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ * This will be at most one cipher block or the tag length if using
+ * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
+ */
+- if (!WPACKET_reserve_bytes(thispkt, SSL_RT_MAX_CIPHER_BLOCK_SIZE,
+- NULL)
+- /*
+- * We also need next the amount of bytes written to this
+- * sub-packet
+- */
++ if (!BIO_get_ktls_send(s->wbio)) {
++ if (!WPACKET_reserve_bytes(thispkt,
++ SSL_RT_MAX_CIPHER_BLOCK_SIZE,
++ NULL)
++ /*
++ * We also need next the amount of bytes written to this
++ * sub-packet
++ */
+ || !WPACKET_get_length(thispkt, &len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
++ }
++
++ /* Get a pointer to the start of this record excluding header */
++ recordstart = WPACKET_get_curr(thispkt) - len;
++ SSL3_RECORD_set_data(thiswr, recordstart);
++ SSL3_RECORD_reset_input(thiswr);
++ SSL3_RECORD_set_length(thiswr, len);
+ }
+-
+- /* Get a pointer to the start of this record excluding header */
+- recordstart = WPACKET_get_curr(thispkt) - len;
+-
+- SSL3_RECORD_set_data(thiswr, recordstart);
+- SSL3_RECORD_reset_input(thiswr);
+- SSL3_RECORD_set_length(thiswr, len);
+ }
+
+ if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
+@@ -1008,12 +1038,14 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ goto err;
+ }
+ } else {
+- if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) {
+- if (!ossl_statem_in_error(s)) {
+- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+- ERR_R_INTERNAL_ERROR);
++ if (!BIO_get_ktls_send(s->wbio)) {
++ if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) {
++ if (!ossl_statem_in_error(s)) {
++ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
++ ERR_R_INTERNAL_ERROR);
++ }
++ goto err;
+ }
+- goto err;
+ }
+ }
+
+@@ -1023,13 +1055,17 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ thispkt = &pkt[j];
+ thiswr = &wr[j];
+
++ if (BIO_get_ktls_send(s->wbio))
++ goto mac_done;
++
+ /* Allocate bytes for the encryption overhead */
+ if (!WPACKET_get_length(thispkt, &origlen)
+ /* Encryption should never shrink the data! */
+ || origlen > thiswr->length
+ || (thiswr->length > origlen
+ && !WPACKET_allocate_bytes(thispkt,
+- thiswr->length - origlen, NULL))) {
++ thiswr->length - origlen,
++ NULL))) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+@@ -1074,13 +1110,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ goto err;
+ }
+
+- /*
+- * we should now have thiswr->data pointing to the encrypted data, which
+- * is thiswr->length long
+- */
+- SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
+- * debugging */
+- SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
++ /* header is added by the kernel when using offload */
++ SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH);
+
+ if (create_empty_fragment) {
+ /*
+@@ -1097,6 +1128,14 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ return 1;
+ }
+
++ mac_done:
++ /*
++ * we should now have thiswr->data pointing to the encrypted data, which
++ * is thiswr->length long
++ */
++ SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
++ * debugging */
++
+ /* now let's set up wb */
+ SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
+ prefix_len + SSL3_RECORD_get_length(thiswr));
+@@ -1150,6 +1189,21 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
+ clear_sys_error();
+ if (s->wbio != NULL) {
+ s->rwstate = SSL_WRITING;
++
++ /*
++ * To prevent coalescing of control and data messages,
++ * such as in buffer_write, we flush the BIO
++ */
++ if (BIO_get_ktls_send(s->wbio) && type != SSL3_RT_APPLICATION_DATA) {
++ i = BIO_flush(s->wbio);
++ if (i <= 0)
++ return i;
++ }
++
++ if (BIO_get_ktls_send(s->wbio)
++ && type != SSL3_RT_APPLICATION_DATA) {
++ BIO_set_ktls_ctrl_msg(s->wbio, type);
++ }
+ /* TODO(size_t): Convert this call */
+ i = BIO_write(s->wbio, (char *)
+ &(SSL3_BUFFER_get_buf(&wb[currbuf])
+diff --git ssl/record/record.h ssl/record/record.h
+index af56206e07..10fdde71a8 100644
+--- ssl/record/record.h
++++ ssl/record/record.h
+@@ -25,6 +25,8 @@ typedef struct ssl3_buffer_st {
+ size_t offset;
+ /* how many bytes left */
+ size_t left;
++ /* 'buf' is from application for KTLS */
++ int app_buffer;
+ } SSL3_BUFFER;
+
+ #define SEQ_NUM_SIZE 8
+diff --git ssl/record/record_local.h ssl/record/record_local.h
+index 5e8dd7f704..4760eeb7d8 100644
+--- ssl/record/record_local.h
++++ ssl/record/record_local.h
+@@ -65,6 +65,8 @@ void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+ #define SSL3_BUFFER_add_offset(b, o) ((b)->offset += (o))
+ #define SSL3_BUFFER_is_initialised(b) ((b)->buf != NULL)
+ #define SSL3_BUFFER_set_default_len(b, l) ((b)->default_len = (l))
++#define SSL3_BUFFER_set_app_buffer(b, l) ((b)->app_buffer = (l))
++#define SSL3_BUFFER_is_app_buffer(b) ((b)->app_buffer)
+
+ void SSL3_BUFFER_clear(SSL3_BUFFER *b);
+ void SSL3_BUFFER_set_data(SSL3_BUFFER *b, const unsigned char *d, size_t n);
+@@ -88,6 +90,7 @@ int ssl3_release_write_buffer(SSL *s);
+ #define SSL3_RECORD_get_input(r) ((r)->input)
+ #define SSL3_RECORD_set_input(r, i) ((r)->input = (i))
+ #define SSL3_RECORD_reset_input(r) ((r)->input = (r)->data)
++#define SSL3_RECORD_reset_data(r) ((r)->data = (r)->input)
+ #define SSL3_RECORD_get_seq_num(r) ((r)->seq_num)
+ #define SSL3_RECORD_get_off(r) ((r)->off)
+ #define SSL3_RECORD_set_off(r, o) ((r)->off = (o))
+diff --git ssl/record/ssl3_buffer.c ssl/record/ssl3_buffer.c
+index 605f8f9b75..32ee4f1786 100644
+--- ssl/record/ssl3_buffer.c
++++ ssl/record/ssl3_buffer.c
+@@ -111,23 +111,27 @@ int ssl3_setup_write_buffer(SSL *s, size_t numwpipes, size_t len)
+ for (currpipe = 0; currpipe < numwpipes; currpipe++) {
+ SSL3_BUFFER *thiswb = &wb[currpipe];
+
+- if (thiswb->buf != NULL && thiswb->len != len) {
++ if (thiswb->len != len) {
+ OPENSSL_free(thiswb->buf);
+ thiswb->buf = NULL; /* force reallocation */
+ }
+
+ if (thiswb->buf == NULL) {
+- p = OPENSSL_malloc(len);
+- if (p == NULL) {
+- s->rlayer.numwpipes = currpipe;
+- /*
+- * We've got a malloc failure, and we're still initialising
+- * buffers. We assume we're so doomed that we won't even be able
+- * to send an alert.
+- */
+- SSLfatal(s, SSL_AD_NO_ALERT,
+- SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE);
+- return 0;
++ if (s->wbio == NULL || !BIO_get_ktls_send(s->wbio)) {
++ p = OPENSSL_malloc(len);
++ if (p == NULL) {
++ s->rlayer.numwpipes = currpipe;
++ /*
++ * We've got a malloc failure, and we're still initialising
++ * buffers. We assume we're so doomed that we won't even be able
++ * to send an alert.
++ */
++ SSLfatal(s, SSL_AD_NO_ALERT,
++ SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++ } else {
++ p = NULL;
+ }
+ memset(thiswb, 0, sizeof(SSL3_BUFFER));
+ thiswb->buf = p;
+@@ -160,7 +164,10 @@ int ssl3_release_write_buffer(SSL *s)
+ while (pipes > 0) {
+ wb = &RECORD_LAYER_get_wbuf(&s->rlayer)[pipes - 1];
+
+- OPENSSL_free(wb->buf);
++ if (SSL3_BUFFER_is_app_buffer(wb))
++ SSL3_BUFFER_set_app_buffer(wb, 0);
++ else
++ OPENSSL_free(wb->buf);
+ wb->buf = NULL;
+ pipes--;
+ }
+diff --git ssl/record/ssl3_record.c ssl/record/ssl3_record.c
+index ab5d22aa10..5f450fd940 100644
+--- ssl/record/ssl3_record.c
++++ ssl/record/ssl3_record.c
+@@ -186,9 +186,11 @@ int ssl3_get_record(SSL *s)
+ size_t num_recs = 0, max_recs, j;
+ PACKET pkt, sslv2pkt;
+ size_t first_rec_len;
++ int is_ktls_left;
+
+ rr = RECORD_LAYER_get_rrec(&s->rlayer);
+ rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
++ is_ktls_left = (rbuf->left > 0);
+ max_recs = s->max_pipelines;
+ if (max_recs == 0)
+ max_recs = 1;
+@@ -207,8 +209,32 @@ int ssl3_get_record(SSL *s)
+ rret = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH,
+ SSL3_BUFFER_get_len(rbuf), 0,
+ num_recs == 0 ? 1 : 0, &n);
+- if (rret <= 0)
+- return rret; /* error or non-blocking */
++ if (rret <= 0) {
++#ifndef OPENSSL_NO_KTLS
++ if (!BIO_get_ktls_recv(s->rbio))
++ return rret; /* error or non-blocking */
++ switch (errno) {
++ case EBADMSG:
++ SSLfatal(s, SSL_AD_BAD_RECORD_MAC,
++ SSL_F_SSL3_GET_RECORD,
++ SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
++ break;
++ case EMSGSIZE:
++ SSLfatal(s, SSL_AD_RECORD_OVERFLOW,
++ SSL_F_SSL3_GET_RECORD,
++ SSL_R_PACKET_LENGTH_TOO_LONG);
++ break;
++ case EINVAL:
++ SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
++ SSL_F_SSL3_GET_RECORD,
++ SSL_R_WRONG_VERSION_NUMBER);
++ break;
++ default:
++ break;
++ }
++#endif
++ return rret;
++ }
+ RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
+
+ p = RECORD_LAYER_get_packet(&s->rlayer);
+@@ -386,7 +412,7 @@ int ssl3_get_record(SSL *s)
+ len -= SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+ #endif
+
+- if (thisrr->length > len) {
++ if (thisrr->length > len && !BIO_get_ktls_recv(s->rbio)) {
+ SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+ SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+ return -1;
+@@ -404,6 +430,7 @@ int ssl3_get_record(SSL *s)
+ } else {
+ more = thisrr->length;
+ }
++
+ if (more > 0) {
+ /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
+
+@@ -491,6 +518,13 @@ int ssl3_get_record(SSL *s)
+ return 1;
+ }
+
++ /*
++ * KTLS reads full records. If there is any data left,
++ * then it is from before enabling ktls
++ */
++ if (BIO_get_ktls_recv(s->rbio) && !is_ktls_left)
++ goto skip_decryption;
++
+ /*
+ * If in encrypt-then-mac mode calculate mac from encrypted record. All
+ * the details below are public so no timing details can leak.
+@@ -678,6 +712,8 @@ int ssl3_get_record(SSL *s)
+ return -1;
+ }
+
++ skip_decryption:
++
+ for (j = 0; j < num_recs; j++) {
+ thisrr = &rr[j];
+
+@@ -739,7 +775,7 @@ int ssl3_get_record(SSL *s)
+ return -1;
+ }
+
+- if (thisrr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
++ if (thisrr->length > SSL3_RT_MAX_PLAIN_LENGTH && !BIO_get_ktls_recv(s->rbio)) {
+ SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ return -1;
+@@ -747,7 +783,8 @@ int ssl3_get_record(SSL *s)
+
+ /* If received packet overflows current Max Fragment Length setting */
+ if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)
+- && thisrr->length > GET_MAX_FRAGMENT_LENGTH(s->session)) {
++ && thisrr->length > GET_MAX_FRAGMENT_LENGTH(s->session)
++ && !BIO_get_ktls_recv(s->rbio)) {
+ SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_F_SSL3_GET_RECORD,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ return -1;
+diff --git ssl/ssl_err.c ssl/ssl_err.c
+index 4b12ed1485..0561678c33 100644
+--- ssl/ssl_err.c
++++ ssl/ssl_err.c
+@@ -312,6 +312,7 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
+ "SSL_renegotiate_abbreviated"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, 0), ""},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, 0), ""},
++ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SENDFILE, 0), "SSL_sendfile"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_DUP, 0), "ssl_session_dup"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_NEW, 0), "SSL_SESSION_new"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_PRINT_FP, 0),
+diff --git ssl/ssl_lib.c ssl/ssl_lib.c
+index 7c7e59789c..9d242fc25d 100644
+--- ssl/ssl_lib.c
++++ ssl/ssl_lib.c
+@@ -11,6 +11,7 @@
+
+ #include <stdio.h>
+ #include "ssl_local.h"
++#include "e_os.h"
+ #include <openssl/objects.h>
+ #include <openssl/x509v3.h>
+ #include <openssl/rand.h>
+@@ -22,6 +23,7 @@
+ #include <openssl/ct.h>
+ #include "internal/cryptlib.h"
+ #include "internal/refcount.h"
++#include "internal/ktls.h"
+
+ const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
+
+@@ -1153,11 +1155,15 @@ void SSL_free(SSL *s)
+ dane_final(&s->dane);
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data);
+
++ RECORD_LAYER_release(&s->rlayer);
++
+ /* Ignore return value */
+ ssl_free_wbio_buffer(s);
+
+ BIO_free_all(s->wbio);
++ s->wbio = NULL;
+ BIO_free_all(s->rbio);
++ s->rbio = NULL;
+
+ BUF_MEM_free(s->init_buf);
+
+@@ -1212,8 +1218,6 @@ void SSL_free(SSL *s)
+ if (s->method != NULL)
+ s->method->ssl_free(s);
+
+- RECORD_LAYER_release(&s->rlayer);
+-
+ SSL_CTX_free(s->ctx);
+
+ ASYNC_WAIT_CTX_free(s->waitctx);
+@@ -1353,6 +1357,15 @@ int SSL_set_fd(SSL *s, int fd)
+ }
+ BIO_set_fd(bio, fd, BIO_NOCLOSE);
+ SSL_set_bio(s, bio, bio);
++#ifndef OPENSSL_NO_KTLS
++ /*
++ * The new socket is created successfully regardless of ktls_enable.
++ * ktls_enable doesn't change any functionality of the socket, except
++ * changing the setsockopt to enable the processing of ktls_start.
++ * Thus, it is not a problem to call it for non-TLS sockets.
++ */
++ ktls_enable(fd);
++#endif /* OPENSSL_NO_KTLS */
+ ret = 1;
+ err:
+ return ret;
+@@ -1372,6 +1385,15 @@ int SSL_set_wfd(SSL *s, int fd)
+ }
+ BIO_set_fd(bio, fd, BIO_NOCLOSE);
+ SSL_set0_wbio(s, bio);
++#ifndef OPENSSL_NO_KTLS
++ /*
++ * The new socket is created successfully regardless of ktls_enable.
++ * ktls_enable doesn't change any functionality of the socket, except
++ * changing the setsockopt to enable the processing of ktls_start.
++ * Thus, it is not a problem to call it for non-TLS sockets.
++ */
++ ktls_enable(fd);
++#endif /* OPENSSL_NO_KTLS */
+ } else {
+ BIO_up_ref(rbio);
+ SSL_set0_wbio(s, rbio);
+@@ -1953,6 +1975,69 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
+ }
+ }
+
++ossl_ssize_t SSL_sendfile(SSL *s, int fd, off_t offset, size_t size, int flags)
++{
++ ossl_ssize_t ret;
++
++ if (s->handshake_func == NULL) {
++ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
++ return -1;
++ }
++
++ if (s->shutdown & SSL_SENT_SHUTDOWN) {
++ s->rwstate = SSL_NOTHING;
++ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_PROTOCOL_IS_SHUTDOWN);
++ return -1;
++ }
++
++ if (!BIO_get_ktls_send(s->wbio)) {
++ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
++ return -1;
++ }
++
++ /* If we have an alert to send, lets send it */
++ if (s->s3->alert_dispatch) {
++ ret = (ossl_ssize_t)s->method->ssl_dispatch_alert(s);
++ if (ret <= 0) {
++ /* SSLfatal() already called if appropriate */
++ return ret;
++ }
++ /* if it went, fall through and send more stuff */
++ }
++
++ s->rwstate = SSL_WRITING;
++ if (BIO_flush(s->wbio) <= 0) {
++ if (!BIO_should_retry(s->wbio)) {
++ s->rwstate = SSL_NOTHING;
++ } else {
++#ifdef EAGAIN
++ set_sys_error(EAGAIN);
++#endif
++ }
++ return -1;
++ }
++
++#ifdef OPENSSL_NO_KTLS
++ ERR_raise_data(ERR_LIB_SYS, ERR_R_INTERNAL_ERROR, "calling sendfile()");
++ return -1;
++#else
++ ret = ktls_sendfile(SSL_get_wfd(s), fd, offset, size, flags);
++ if (ret < 0) {
++#if defined(EAGAIN) && defined(EINTR) && defined(EBUSY)
++ if ((get_last_sys_error() == EAGAIN) ||
++ (get_last_sys_error() == EINTR) ||
++ (get_last_sys_error() == EBUSY))
++ BIO_set_retry_write(s->wbio);
++ else
++#endif
++ SSLerr(SSL_F_SSL_SENDFILE, SSL_R_UNINITIALIZED);
++ return ret;
++ }
++ s->rwstate = SSL_NOTHING;
++ return ret;
++#endif
++}
++
+ int SSL_write(SSL *s, const void *buf, int num)
+ {
+ int ret;
+@@ -2197,6 +2282,10 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
+ case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+ if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0;
++#ifndef OPENSSL_NO_KTLS
++ if (s->wbio != NULL && BIO_get_ktls_send(s->wbio))
++ return 0;
++#endif /* OPENSSL_NO_KTLS */
+ s->max_send_fragment = larg;
+ if (s->max_send_fragment < s->split_send_fragment)
+ s->split_send_fragment = s->max_send_fragment;
+diff --git ssl/ssl_local.h ssl/ssl_local.h
+index 8ddbde7729..aea5c76809 100644
+--- ssl/ssl_local.h
++++ ssl/ssl_local.h
+@@ -34,6 +34,7 @@
+ # include "internal/dane.h"
+ # include "internal/refcount.h"
+ # include "internal/tsan_assist.h"
++# include "internal/bio.h"
+
+ # ifdef OPENSSL_BUILD_SHLIBSSL
+ # undef OPENSSL_EXTERN
+diff --git ssl/t1_enc.c ssl/t1_enc.c
+index c85c0b0310..9e988ab321 100644
+--- ssl/t1_enc.c
++++ ssl/t1_enc.c
+@@ -10,10 +10,14 @@
+
+ #include <stdio.h>
+ #include "ssl_local.h"
++#include "record/record_local.h"
++#include "internal/ktls.h"
++#include "internal/cryptlib.h"
+ #include <openssl/comp.h>
+ #include <openssl/evp.h>
+ #include <openssl/kdf.h>
+ #include <openssl/rand.h>
++#include <openssl/obj_mac.h>
+
+ /* seed1 through seed5 are concatenated */
+ static int tls1_PRF(SSL *s,
+@@ -78,6 +82,39 @@ static int tls1_generate_key_block(SSL *s, unsigned char *km, size_t num)
+ return ret;
+ }
+
++#ifndef OPENSSL_NO_KTLS
++ /*
++ * Count the number of records that were not processed yet from record boundary.
++ *
++ * This function assumes that there are only fully formed records read in the
++ * record layer. If read_ahead is enabled, then this might be false and this
++ * function will fail.
++ */
++static int count_unprocessed_records(SSL *s)
++{
++ SSL3_BUFFER *rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
++ PACKET pkt, subpkt;
++ int count = 0;
++
++ if (!PACKET_buf_init(&pkt, rbuf->buf + rbuf->offset, rbuf->left))
++ return -1;
++
++ while (PACKET_remaining(&pkt) > 0) {
++ /* Skip record type and version */
++ if (!PACKET_forward(&pkt, 3))
++ return -1;
++
++ /* Read until next record */
++ if (PACKET_get_length_prefixed_2(&pkt, &subpkt))
++ return -1;
++
++ count += 1;
++ }
++
++ return count;
++}
++#endif
++
+ int tls1_change_cipher_state(SSL *s, int which)
+ {
+ unsigned char *p, *mac_secret;
+@@ -94,6 +131,17 @@ int tls1_change_cipher_state(SSL *s, int which)
+ EVP_PKEY *mac_key;
+ size_t n, i, j, k, cl;
+ int reuse_dd = 0;
++#ifndef OPENSSL_NO_KTLS
++# ifdef __FreeBSD__
++ struct tls_enable crypto_info;
++# else
++ struct tls12_crypto_info_aes_gcm_128 crypto_info;
++ unsigned char geniv[12];
++ int count_unprocessed;
++ int bit;
++# endif
++ BIO *bio;
++#endif
+
+ c = s->s3->tmp.new_sym_enc;
+ m = s->s3->tmp.new_hash;
+@@ -312,6 +360,138 @@ int tls1_change_cipher_state(SSL *s, int which)
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
++#ifndef OPENSSL_NO_KTLS
++ if (s->compress)
++ goto skip_ktls;
++
++ if (((which & SSL3_CC_READ) && (s->mode & SSL_MODE_NO_KTLS_RX))
++ || ((which & SSL3_CC_WRITE) && (s->mode & SSL_MODE_NO_KTLS_TX)))
++ goto skip_ktls;
++
++ /* ktls supports only the maximum fragment size */
++ if (ssl_get_max_send_fragment(s) != SSL3_RT_MAX_PLAIN_LENGTH)
++ goto skip_ktls;
++
++# ifdef __FreeBSD__
++ memset(&crypto_info, 0, sizeof(crypto_info));
++ switch (s->s3->tmp.new_cipher->algorithm_enc) {
++ case SSL_AES128GCM:
++ case SSL_AES256GCM:
++ crypto_info.cipher_algorithm = CRYPTO_AES_NIST_GCM_16;
++ crypto_info.iv_len = EVP_GCM_TLS_FIXED_IV_LEN;
++ break;
++ case SSL_AES128:
++ case SSL_AES256:
++ if (s->ext.use_etm)
++ goto skip_ktls;
++ switch (s->s3->tmp.new_cipher->algorithm_mac) {
++ case SSL_SHA1:
++ crypto_info.auth_algorithm = CRYPTO_SHA1_HMAC;
++ break;
++ case SSL_SHA256:
++ crypto_info.auth_algorithm = CRYPTO_SHA2_256_HMAC;
++ break;
++ case SSL_SHA384:
++ crypto_info.auth_algorithm = CRYPTO_SHA2_384_HMAC;
++ break;
++ default:
++ goto skip_ktls;
++ }
++ crypto_info.cipher_algorithm = CRYPTO_AES_CBC;
++ crypto_info.iv_len = EVP_CIPHER_iv_length(c);
++ crypto_info.auth_key = ms;
++ crypto_info.auth_key_len = *mac_secret_size;
++ break;
++ default:
++ goto skip_ktls;
++ }
++ crypto_info.cipher_key = key;
++ crypto_info.cipher_key_len = EVP_CIPHER_key_length(c);
++ crypto_info.iv = iv;
++ crypto_info.tls_vmajor = (s->version >> 8) & 0x000000ff;
++ crypto_info.tls_vminor = (s->version & 0x000000ff);
++# else
++ /* check that cipher is AES_GCM_128 */
++ if (EVP_CIPHER_nid(c) != NID_aes_128_gcm
++ || EVP_CIPHER_mode(c) != EVP_CIPH_GCM_MODE
++ || EVP_CIPHER_key_length(c) != TLS_CIPHER_AES_GCM_128_KEY_SIZE)
++ goto skip_ktls;
++
++ /* check version is 1.2 */
++ if (s->version != TLS1_2_VERSION)
++ goto skip_ktls;
++# endif
++
++ if (which & SSL3_CC_WRITE)
++ bio = s->wbio;
++ else
++ bio = s->rbio;
++
++ if (!ossl_assert(bio != NULL)) {
++ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
++ ERR_R_INTERNAL_ERROR);
++ goto err;
++ }
++
++ /* All future data will get encrypted by ktls. Flush the BIO or skip ktls */
++ if (which & SSL3_CC_WRITE) {
++ if (BIO_flush(bio) <= 0)
++ goto skip_ktls;
++ }
++
++ /* ktls doesn't support renegotiation */
++ if ((BIO_get_ktls_send(s->wbio) && (which & SSL3_CC_WRITE)) ||
++ (BIO_get_ktls_recv(s->rbio) && (which & SSL3_CC_READ))) {
++ SSLfatal(s, SSL_AD_NO_RENEGOTIATION, SSL_F_TLS1_CHANGE_CIPHER_STATE,
++ ERR_R_INTERNAL_ERROR);
++ goto err;
++ }
++
++# ifndef __FreeBSD__
++ memset(&crypto_info, 0, sizeof(crypto_info));
++ crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128;
++ crypto_info.info.version = s->version;
++
++ EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GET_IV,
++ EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN,
++ geniv);
++ memcpy(crypto_info.iv, geniv + EVP_GCM_TLS_FIXED_IV_LEN,
++ TLS_CIPHER_AES_GCM_128_IV_SIZE);
++ memcpy(crypto_info.salt, geniv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
++ memcpy(crypto_info.key, key, EVP_CIPHER_key_length(c));
++ if (which & SSL3_CC_WRITE)
++ memcpy(crypto_info.rec_seq, &s->rlayer.write_sequence,
++ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
++ else
++ memcpy(crypto_info.rec_seq, &s->rlayer.read_sequence,
++ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
++
++ if (which & SSL3_CC_READ) {
++ count_unprocessed = count_unprocessed_records(s);
++ if (count_unprocessed < 0)
++ goto skip_ktls;
++
++ /* increment the crypto_info record sequence */
++ while (count_unprocessed) {
++ for (bit = 7; bit >= 0; bit--) { /* increment */
++ ++crypto_info.rec_seq[bit];
++ if (crypto_info.rec_seq[bit] != 0)
++ break;
++ }
++ count_unprocessed--;
++ }
++ }
++# endif
++
++ /* ktls works with user provided buffers directly */
++ if (BIO_set_ktls(bio, &crypto_info, which & SSL3_CC_WRITE)) {
++ if (which & SSL3_CC_WRITE)
++ ssl3_release_write_buffer(s);
++ SSL_set_options(s, SSL_OP_NO_RENEGOTIATION);
++ }
++
++ skip_ktls:
++#endif /* OPENSSL_NO_KTLS */
+ s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+
+ #ifdef SSL_DEBUG
+diff --git test/sslapitest.c test/sslapitest.c
+index 5c118108ef..98b8574aba 100644
+--- test/sslapitest.c
++++ test/sslapitest.c
+@@ -7,6 +7,7 @@
+ * https://www.openssl.org/source/license.html
+ */
+
++#include <stdio.h>
+ #include <string.h>
+
+ #include <openssl/opensslconf.h>
+@@ -17,11 +18,13 @@
+ #include <openssl/srp.h>
+ #include <openssl/txt_db.h>
+ #include <openssl/aes.h>
++#include <openssl/rand.h>
+
+ #include "ssltestlib.h"
+ #include "testutil.h"
+ #include "testutil/output.h"
+ #include "internal/nelem.h"
++#include "internal/ktls.h"
+ #include "../ssl/ssl_local.h"
+
+ #ifndef OPENSSL_NO_TLS1_3
+@@ -779,6 +782,406 @@ static int execute_test_large_message(const SSL_METHOD *smeth,
+ return testresult;
+ }
+
++#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
++
+ static int test_large_message_tls(void)
+ {
+ return execute_test_large_message(TLS_server_method(), TLS_client_method(),
+@@ -6504,6 +6907,26 @@ int setup_tests(void)
+ return 0;
+ }
+
++#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS) \
++ && !defined(OPENSSL_NO_SOCK)
++ ADD_TEST(test_ktls_no_txrx_client_no_txrx_server);
++ ADD_TEST(test_ktls_no_rx_client_no_txrx_server);
++ ADD_TEST(test_ktls_no_tx_client_no_txrx_server);
++ ADD_TEST(test_ktls_client_no_txrx_server);
++ ADD_TEST(test_ktls_no_txrx_client_no_rx_server);
++ ADD_TEST(test_ktls_no_rx_client_no_rx_server);
++ ADD_TEST(test_ktls_no_tx_client_no_rx_server);
++ ADD_TEST(test_ktls_client_no_rx_server);
++ ADD_TEST(test_ktls_no_txrx_client_no_tx_server);
++ ADD_TEST(test_ktls_no_rx_client_no_tx_server);
++ ADD_TEST(test_ktls_no_tx_client_no_tx_server);
++ ADD_TEST(test_ktls_client_no_tx_server);
++ ADD_TEST(test_ktls_no_txrx_client_server);
++ ADD_TEST(test_ktls_no_rx_client_server);
++ ADD_TEST(test_ktls_no_tx_client_server);
++ ADD_TEST(test_ktls_client_server);
++ ADD_TEST(test_ktls_sendfile);
++#endif
+ ADD_TEST(test_large_message_tls);
+ ADD_TEST(test_large_message_tls_read_ahead);
+ #ifndef OPENSSL_NO_DTLS
+diff --git test/ssltestlib.c test/ssltestlib.c
+index 456afdf471..bae39823d2 100644
+--- test/ssltestlib.c
++++ test/ssltestlib.c
+@@ -16,6 +16,14 @@
+
+ #ifdef OPENSSL_SYS_UNIX
+ # include <unistd.h>
++#ifndef OPENSSL_NO_KTLS
++# include <netinet/in.h>
++# include <netinet/in.h>
++# include <arpa/inet.h>
++# include <sys/socket.h>
++# include <unistd.h>
++# include <fcntl.h>
++#endif
+
+ static ossl_inline void ossl_sleep(unsigned int millis)
+ {
+@@ -763,6 +771,114 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
+
+ #define MAXLOOPS 1000000
+
++#if !defined(OPENSSL_NO_KTLS) && !defined(OPENSSL_NO_SOCK)
++static int set_nb(int fd)
++{
++ int flags;
++
++ flags = fcntl(fd,F_GETFL,0);
++ if (flags == -1)
++ return flags;
++ flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
++ return flags;
++}
++
++int create_test_sockets(int *cfd, int *sfd)
++{
++ struct sockaddr_in sin;
++ const char *host = "127.0.0.1";
++ int cfd_connected = 0, ret = 0;
++ socklen_t slen = sizeof(sin);
++ int afd = -1;
++
++ *cfd = -1;
++ *sfd = -1;
++
++ memset ((char *) &sin, 0, sizeof(sin));
++ sin.sin_family = AF_INET;
++ sin.sin_addr.s_addr = inet_addr(host);
++
++ afd = socket(AF_INET, SOCK_STREAM, 0);
++ if (afd < 0)
++ return 0;
++
++ if (bind(afd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
++ goto out;
++
++ if (getsockname(afd, (struct sockaddr*)&sin, &slen) < 0)
++ goto out;
++
++ if (listen(afd, 1) < 0)
++ goto out;
++
++ *cfd = socket(AF_INET, SOCK_STREAM, 0);
++ if (*cfd < 0)
++ goto out;
++
++ if (set_nb(afd) == -1)
++ goto out;
++
++ while (*sfd == -1 || !cfd_connected ) {
++ *sfd = accept(afd, NULL, 0);
++ if (*sfd == -1 && errno != EAGAIN)
++ goto out;
++
++ if (!cfd_connected && connect(*cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
++ goto out;
++ else
++ cfd_connected = 1;
++ }
++
++ if (set_nb(*cfd) == -1 || set_nb(*sfd) == -1)
++ goto out;
++ ret = 1;
++ goto success;
++
++out:
++ if (*cfd != -1)
++ close(*cfd);
++ if (*sfd != -1)
++ close(*sfd);
++success:
++ if (afd != -1)
++ close(afd);
++ return ret;
++}
++
++int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
++ SSL **cssl, int sfd, int cfd)
++{
++ SSL *serverssl = NULL, *clientssl = NULL;
++ BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL;
++
++ if (*sssl != NULL)
++ serverssl = *sssl;
++ else if (!TEST_ptr(serverssl = SSL_new(serverctx)))
++ goto error;
++ if (*cssl != NULL)
++ clientssl = *cssl;
++ else if (!TEST_ptr(clientssl = SSL_new(clientctx)))
++ goto error;
++
++ if (!TEST_ptr(s_to_c_bio = BIO_new_socket(sfd, BIO_NOCLOSE))
++ || !TEST_ptr(c_to_s_bio = BIO_new_socket(cfd, BIO_NOCLOSE)))
++ goto error;
++
++ SSL_set_bio(clientssl, c_to_s_bio, c_to_s_bio);
++ SSL_set_bio(serverssl, s_to_c_bio, s_to_c_bio);
++ *sssl = serverssl;
++ *cssl = clientssl;
++ return 1;
++
++ error:
++ SSL_free(serverssl);
++ SSL_free(clientssl);
++ BIO_free(s_to_c_bio);
++ BIO_free(c_to_s_bio);
++ return 0;
++}
++#endif
++
+ /*
+ * NOTE: Transfers control of the BIOs - this function will free them on error
+ */
+diff --git test/ssltestlib.h test/ssltestlib.h
+index 17b278219a..756975435d 100644
+--- test/ssltestlib.h
++++ test/ssltestlib.h
+@@ -20,6 +20,9 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
+ SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio);
+ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
+ int read);
++int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
++ SSL **cssl, int sfd, int cfd);
++int create_test_sockets(int *cfd, int *sfd);
+ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
+ void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl);
+
+diff --git util/libssl.num util/libssl.num
+index 297522c363..5b3c048871 100644
+--- util/libssl.num
++++ util/libssl.num
+@@ -498,3 +498,4 @@ SSL_CTX_get_recv_max_early_data 498 1_1_1 EXIST::FUNCTION:
+ SSL_CTX_set_recv_max_early_data 499 1_1_1 EXIST::FUNCTION:
+ SSL_CTX_set_post_handshake_auth 500 1_1_1 EXIST::FUNCTION:
+ SSL_get_signature_type_nid 501 1_1_1a EXIST::FUNCTION:
++SSL_sendfile 502 1_1_1e EXIST::FUNCTION:
+diff --git util/private.num util/private.num
+index bc7d967b5d..5bfbfc9fa4 100644
+--- util/private.num
++++ util/private.num
+@@ -109,6 +109,8 @@ BIO_get_buffer_num_lines define
+ BIO_get_cipher_ctx define
+ BIO_get_cipher_status define
+ BIO_get_close define
++BIO_get_ktls_send define
++BIO_get_ktls_recv define
+ BIO_get_conn_address define
+ BIO_get_conn_hostname define
+ BIO_get_conn_port definE
diff --git a/security/openssl/pkg-plist b/security/openssl/pkg-plist
index cf8206a1727d..b99c56b3e762 100644
--- a/security/openssl/pkg-plist
+++ b/security/openssl/pkg-plist
@@ -409,6 +409,8 @@ man/man1/x509.1.gz
%%MAN3%%man/man3/BIO_get_fp.3.gz
%%MAN3%%man/man3/BIO_get_info_callback.3.gz
%%MAN3%%man/man3/BIO_get_init.3.gz
+%%KTLS%%%%MAN3%%man/man3/BIO_get_ktls_recv.3.gz
+%%KTLS%%%%MAN3%%man/man3/BIO_get_ktls_send.3.gz
%%MAN3%%man/man3/BIO_get_md.3.gz
%%MAN3%%man/man3/BIO_get_md_ctx.3.gz
%%MAN3%%man/man3/BIO_get_mem_data.3.gz
@@ -3000,6 +3002,7 @@ man/man1/x509.1.gz
%%MAN3%%man/man3/SSL_rstate_string_long.3.gz
%%MAN3%%man/man3/SSL_select_current_cert.3.gz
%%MAN3%%man/man3/SSL_select_next_proto.3.gz
+%%KTLS%%%%MAN3%%man/man3/SSL_sendfile.3.gz
%%MAN3%%man/man3/SSL_session_reused.3.gz
%%MAN3%%man/man3/SSL_set0_CA_list.3.gz
%%MAN3%%man/man3/SSL_set0_chain.3.gz