The branch master has been updated
       via  d6c3c1896cf3c0d69bc27da923d63f8130b13ca0 (commit)
       via  42ea4ef2db123b4060d6d1b92556416c5a6ce2a1 (commit)
       via  fe5d945028758becae5e2bfa85b770b922ed2a96 (commit)
       via  50ec750567e056fcecff2344c2d9044d81cc731b (commit)
       via  ecd1557fb4589103316c65b1fd1d4217a30900c0 (commit)
       via  6ba76c4f23e4b4ddc27b9e7234c8b9c3bcff5eff (commit)
       via  69495e3df57335ad43bc66fa2477636f66afed85 (commit)
       via  fe3ad3aee37f7bcb52c647a4f1c8a6f60360d095 (commit)
      from  a86003162138031137727147c9b642d99db434b1 (commit)


- Log -----------------------------------------------------------------
commit d6c3c1896cf3c0d69bc27da923d63f8130b13ca0
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Wed Nov 14 23:53:57 2018 +0200

    apps: print Kernel TLS in s_client and s_server
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit 42ea4ef2db123b4060d6d1b92556416c5a6ce2a1
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Wed Nov 14 21:13:05 2018 +0200

    CHANGES: Add Linux Kernel TLS data-path
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit fe5d945028758becae5e2bfa85b770b922ed2a96
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Tue Feb 13 20:22:09 2018 +0200

    sslapitest: add test ktls
    
    Add a unit-test for ktls.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit 50ec750567e056fcecff2344c2d9044d81cc731b
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Jun 1 09:25:47 2017 +0300

    ssl: Linux TLS Tx Offload
    
    This patch adds support for the Linux TLS Tx socket option.
    If the socket option is successful, then the data-path of the TCP socket
    is implemented by the kernel.
    We choose to set this option at the earliest - just after CCS is complete.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit ecd1557fb4589103316c65b1fd1d4217a30900c0
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Jun 1 08:54:55 2017 +0300

    evp/e_aes: Expose IV
    
    This commit exposes the cipher's IV to applications.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit 6ba76c4f23e4b4ddc27b9e7234c8b9c3bcff5eff
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Jun 1 08:46:33 2017 +0300

    bio: Linux TLS Offload
    
    Add support for Linux TLS offload in the BIO layer
    and specifically in bss_sock.c.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit 69495e3df57335ad43bc66fa2477636f66afed85
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Feb 1 14:10:22 2018 +0200

    Configure Kernel TLS datapath
    
    Allow users to disable ktls using the "no-ktls" option.
    Also, disable ktls when cross-compiling, non-linux, or too-old-kernel.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

commit fe3ad3aee37f7bcb52c647a4f1c8a6f60360d095
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Wed Jan 31 16:43:35 2018 +0200

    Linux ktls infrastructure
    
    Introduce a compatability layer that exposes the required structures
    and constants for supporting ktls.
    
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Tim Hudson <t...@openssl.org>
    Reviewed-by: Paul Yang <yang.y...@baishancloud.com>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5253)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                       |   5 ++
 Configure                     |  23 +++++
 INSTALL                       |   9 ++
 apps/s_client.c               |   4 +
 apps/s_server.c               |   4 +
 crypto/bio/bss_sock.c         |  48 ++++++++++-
 crypto/evp/e_aes.c            |   8 ++
 doc/man3/BIO_ctrl.pod         |  14 ++-
 doc/man3/SSL_CTX_set_mode.pod |  17 ++++
 include/internal/bio.h        |  36 ++++++++
 include/internal/ktls.h       | 147 ++++++++++++++++++++++++++++++++
 include/openssl/bio.h         |  10 +++
 include/openssl/evp.h         |   2 +
 include/openssl/ssl.h         |   4 +
 ssl/record/rec_layer_s3.c     | 116 +++++++++++++++++--------
 ssl/record/record_locl.h      |   1 +
 ssl/record/ssl3_buffer.c      |  31 ++++---
 ssl/ssl_lib.c                 |  29 ++++++-
 ssl/ssl_locl.h                |   1 +
 ssl/t1_enc.c                  |  71 ++++++++++++++++
 test/sslapitest.c             | 193 ++++++++++++++++++++++++++++++++++++++++++
 test/ssltestlib.c             | 121 ++++++++++++++++++++++++++
 test/ssltestlib.h             |   3 +
 util/private.num              |   1 +
 24 files changed, 846 insertions(+), 52 deletions(-)
 create mode 100644 include/internal/ktls.h

diff --git a/CHANGES b/CHANGES
index 1b6c91e..0770f55 100644
--- a/CHANGES
+++ b/CHANGES
@@ -87,6 +87,11 @@
      list of built in objects, i.e. OIDs with names.
      [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 a/Configure b/Configure
index ffbb8e1..37c9b2a 100755
--- a/Configure
+++ b/Configure
@@ -318,6 +318,7 @@ my @dtls = qw(dtls1 dtls1_2);
 # For developers: keep it sorted alphabetically
 
 my @disablables = (
+    "ktls",
     "afalgeng",
     "aria",
     "asan",
@@ -448,6 +449,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
@@ -1570,6 +1572,27 @@ unless ($disabled{afalgeng}) {
 
 push @{$config{openssl_feature_defines}}, "OPENSSL_NO_AFALGENG" if 
($disabled{afalgeng});
 
+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) {
+            $disabled{ktls} = "too-old-kernel";
+        }
+    } else {
+        $disabled{ktls}  = "not-linux";
+    }
+}
+
+push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
+
 # Finish up %config by appending things the user gave us on the command line
 # apart from "make variables"
 foreach (keys %useradd) {
diff --git a/INSTALL b/INSTALL
index 4ce6651..5cca299 100644
--- a/INSTALL
+++ b/INSTALL
@@ -250,6 +250,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 a/apps/s_client.c b/apps/s_client.c
index 8a7613d..8bdfbb6 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -3245,6 +3245,10 @@ 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");
+#endif
 
 #ifdef SSL_DEBUG
     {
diff --git a/apps/s_server.c b/apps/s_server.c
index 6921161..364f76b 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -2911,6 +2911,10 @@ 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");
+#endif
 
     (void)BIO_flush(bio_s_out);
 }
diff --git a/crypto/bio/bss_sock.c b/crypto/bio/bss_sock.c
index 0c87e18..60e5adc 100644
--- a/crypto/bio/bss_sock.c
+++ b/crypto/bio/bss_sock.c
@@ -11,6 +11,7 @@
 #include <errno.h>
 #include "bio_lcl.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;
 }
 
@@ -108,10 +120,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))
@@ -124,6 +146,9 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
 {
     long ret = 1;
     int *ip;
+# ifndef OPENSSL_NO_KTLS
+    struct tls12_crypto_info_aes_gcm_128 *crypto_info;
+# endif
 
     switch (cmd) {
     case BIO_C_SET_FD:
@@ -151,6 +176,25 @@ 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_SEND:
+        crypto_info = (struct tls12_crypto_info_aes_gcm_128 *)ptr;
+        ret = ktls_start(b->num, crypto_info, sizeof(*crypto_info), num);
+        if (ret)
+            BIO_set_ktls_flag(b);
+        break;
+    case BIO_CTRL_GET_KTLS_SEND:
+        return BIO_should_ktls_flag(b);
+    case BIO_CTRL_SET_KTLS_SEND_CTRL_MSG:
+        BIO_set_ktls_ctrl_msg_flag(b);
+        b->ptr = (void *)num;
+        ret = 0;
+        break;
+    case BIO_CTRL_CLEAR_KTLS_CTRL_MSG:
+        BIO_clear_ktls_ctrl_msg_flag(b);
+        ret = 0;
+        break;
+# endif
     default:
         ret = 0;
         break;
diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c
index 7b35575..09f6598 100644
--- a/crypto/evp/e_aes.c
+++ b/crypto/evp/e_aes.c
@@ -2866,6 +2866,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 a/doc/man3/BIO_ctrl.pod b/doc/man3/BIO_ctrl.pod
index 69df85a..29e72aa 100644
--- a/doc/man3/BIO_ctrl.pod
+++ b/doc/man3/BIO_ctrl.pod
@@ -5,7 +5,7 @@
 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 control operations
 
 =head1 SYNOPSIS
@@ -34,6 +34,8 @@ 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);
+
 =head1 DESCRIPTION
 
 BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl()
@@ -72,6 +74,9 @@ 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() return 1 if the BIO is using the Kernel TLS data-path for
+sending. Otherwise, it returns zero.
+
 =head1 RETURN VALUES
 
 BIO_reset() normally returns 1 for success and 0 or -1 for failure. File
@@ -92,6 +97,9 @@ 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() return 1 if the BIO is using the Kernel TLS data-path for
+sending. Otherwise, it returns zero.
+
 =head1 NOTES
 
 BIO_flush(), because it can write data may return 0 or -1 indicating
@@ -124,6 +132,10 @@ 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() function was added in OpenSSL 3.0.0.
+
 =head1 COPYRIGHT
 
 Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/SSL_CTX_set_mode.pod b/doc/man3/SSL_CTX_set_mode.pod
index 8c3b760..de4d5f2 100644
--- a/doc/man3/SSL_CTX_set_mode.pod
+++ b/doc/man3/SSL_CTX_set_mode.pod
@@ -105,6 +105,22 @@ Enable asynchronous processing. TLS I/O operations may 
indicate a retry with
 SSL_ERROR_WANT_ASYNC with this mode set if an asynchronous capable engine is
 used to perform cryptographic operations. See L<SSL_get_error(3)>.
 
+=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
@@ -125,6 +141,7 @@ L<SSL_write(3)>, L<SSL_get_error(3)>
 =head1 HISTORY
 
 SSL_MODE_ASYNC was first added to OpenSSL 1.1.0.
+SSL_MODE_NO_KTLS_TX was first added to OpenSSL 3.0.0.
 
 =head1 COPYRIGHT
 
diff --git a/include/internal/bio.h b/include/internal/bio.h
index e1251f6..1e80d5a 100644
--- a/include/internal/bio.h
+++ b/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,36 @@ 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);
+
+# define BIO_CTRL_SET_KTLS_SEND                 72
+# define BIO_CTRL_SET_KTLS_SEND_CTRL_MSG        74
+# define BIO_CTRL_CLEAR_KTLS_CTRL_MSG      75
+
+/*
+ * This is used with socket BIOs:
+ * BIO_FLAGS_KTLS means we are using ktls with this BIO.
+ * BIO_FLAGS_KTLS_CTRL_MSG means we are about to send a ctrl message next.
+ */
+# define BIO_FLAGS_KTLS          0x800
+# define BIO_FLAGS_KTLS_CTRL_MSG 0x1000
+
+/* KTLS related controls and flags */
+# define BIO_set_ktls_flag(b) \
+    BIO_set_flags(b, BIO_FLAGS_KTLS)
+# define BIO_should_ktls_flag(b) \
+    BIO_test_flags(b, BIO_FLAGS_KTLS)
+# define BIO_set_ktls_ctrl_msg_flag(b) \
+    BIO_set_flags(b, BIO_FLAGS_KTLS_CTRL_MSG)
+# define BIO_should_ktls_ctrl_msg_flag(b) \
+    BIO_test_flags(b, (BIO_FLAGS_KTLS_CTRL_MSG))
+# define BIO_clear_ktls_ctrl_msg_flag(b) \
+    BIO_clear_flags(b, (BIO_FLAGS_KTLS_CTRL_MSG))
+
+#  define BIO_set_ktls(b, keyblob, is_tx)   \
+     BIO_ctrl(b, BIO_CTRL_SET_KTLS_SEND, is_tx, keyblob)
+#  define BIO_set_ktls_ctrl_msg(b, record_type)   \
+     BIO_ctrl(b, BIO_CTRL_SET_KTLS_SEND_CTRL_MSG, record_type, NULL)
+#  define BIO_clear_ktls_ctrl_msg(b) \
+     BIO_ctrl(b, BIO_CTRL_CLEAR_KTLS_CTRL_MSG, 0, NULL)
+
+#endif
diff --git a/include/internal/ktls.h b/include/internal/ktls.h
new file mode 100644
index 0000000..542acf3
--- /dev/null
+++ b/include/internal/ktls.h
@@ -0,0 +1,147 @@
+/*
+ * 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(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 data path"
+#    endif
+
+#    define TLS_TX                  1
+
+#    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;
+}
+
+#   else                        /* KERNEL_VERSION */
+
+#    include <netinet/tcp.h>
+#    include <linux/tls.h>
+#    include <linux/socket.h>
+
+#    ifndef SOL_TLS
+#     define SOL_TLS 282
+#    endif
+
+#    ifndef TCP_ULP
+#     define TCP_ULP 31
+#    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.
+ */
+static ossl_inline int ktls_start(int fd,
+                                  struct tls12_crypto_info_aes_gcm_128
+                                  *crypto_info, size_t len, int is_tx)
+{
+    if (is_tx)
+        return setsockopt(fd, SOL_TLS, TLS_TX, crypto_info,
+                          sizeof(*crypto_info)) ? 0 : 1;
+    else
+        return 0;
+}
+
+/*
+ * 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 = { 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 = 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);
+}
+
+#   endif                       /* KERNEL_VERSION */
+#  endif                        /* OPENSSL_SYS_LINUX */
+# endif                         /* HEADER_INTERNAL_KTLS */
+#endif                          /* OPENSSL_NO_KTLS */
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 9f118d9..cdeacc8 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -145,6 +145,16 @@ 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_get_ktls_send(b)         \
+     BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL)
+
 /* modifiers */
 # define BIO_FP_READ             0x02
 # define BIO_FP_WRITE            0x04
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index f381a57..636ed1b 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -350,6 +350,8 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER 
*cipher))(EVP_CIPHER_CTX *,
 # define         EVP_CTRL_SET_PIPELINE_INPUT_BUFS        0x23
 /* Set the input buffer lengths to use for a pipelined operation */
 # define         EVP_CTRL_SET_PIPELINE_INPUT_LENS        0x24
+/* Get the IV used by the cipher */
+# define         EVP_CTRL_GET_IV                         0x25
 
 /* Padding modes */
 #define EVP_PADDING_PKCS7       1
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index dd664a0..ea41dd0 100644
--- a/include/openssl/ssl.h
+++ b/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
+/*
+ * Use the kernel TLS transmission data-path.
+ */
+# define SSL_MODE_NO_KTLS_TX 0x00000200U
 
 /* Cert related flags */
 /*
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 9ab3708..2f5987b 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -743,6 +743,18 @@ 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);
+        goto wpacket_init_complete;
+    }
+
     if (create_empty_fragment) {
         wb = &s->rlayer.wbuf[0];
 #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
@@ -812,6 +824,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));
@@ -853,15 +867,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;
@@ -887,12 +905,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)
@@ -967,24 +989,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) {
@@ -1000,12 +1024,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;
         }
     }
 
@@ -1015,13 +1041,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;
@@ -1066,13 +1096,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) {
             /*
@@ -1089,6 +1114,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));
@@ -1142,6 +1175,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 a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index bf52ee1..ed42188 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -88,6 +88,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 a/ssl/record/ssl3_buffer.c b/ssl/record/ssl3_buffer.c
index 8960290..09cf587 100644
--- a/ssl/record/ssl3_buffer.c
+++ b/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,8 @@ int ssl3_release_write_buffer(SSL *s)
     while (pipes > 0) {
         wb = &RECORD_LAYER_get_wbuf(&s->rlayer)[pipes - 1];
 
-        OPENSSL_free(wb->buf);
+        if (s->wbio == NULL || !BIO_get_ktls_send(s->wbio))
+            OPENSSL_free(wb->buf);
         wb->buf = NULL;
         pipes--;
     }
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a709792..ba606e3 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -22,6 +22,7 @@
 #include <openssl/ct.h>
 #include "internal/cryptlib.h"
 #include "internal/refcount.h"
+#include "internal/ktls.h"
 
 static int ssl_undefined_function_1(SSL *ssl, SSL3_RECORD *r, size_t s, int t)
 {
@@ -1146,11 +1147,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);
 
@@ -1201,8 +1206,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);
@@ -1342,6 +1345,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;
@@ -1361,6 +1373,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);
@@ -2186,6 +2207,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 a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 98e8e8a..c2e6474 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.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 a/ssl/t1_enc.c b/ssl/t1_enc.c
index 2313afd..adcc626 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -10,10 +10,14 @@
 
 #include <stdio.h>
 #include "ssl_locl.h"
+#include "record/record_locl.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,
@@ -98,6 +102,11 @@ 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
+    struct tls12_crypto_info_aes_gcm_128 crypto_info;
+    BIO *wbio;
+    unsigned char geniv[12];
+#endif
 
     c = s->s3->tmp.new_sym_enc;
     m = s->s3->tmp.new_hash;
@@ -319,6 +328,68 @@ 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) ||
+        ((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;
+
+    /* 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;
+
+    wbio = s->wbio;
+    if (!ossl_assert(wbio != 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 (BIO_flush(wbio) <= 0)
+        goto skip_ktls;
+
+    /* ktls doesn't support renegotiation */
+    if (BIO_get_ktls_send(s->wbio)) {
+        SSLfatal(s, SSL_AD_NO_RENEGOTIATION, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    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));
+    memcpy(crypto_info.rec_seq, &s->rlayer.write_sequence,
+           TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
+
+    /* ktls works with user provided buffers directly */
+    if (BIO_set_ktls(wbio, &crypto_info, 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 a/test/sslapitest.c b/test/sslapitest.c
index 2aea527..fb70562 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -22,6 +22,7 @@
 #include "testutil.h"
 #include "testutil/output.h"
 #include "internal/nelem.h"
+#include "internal/ktls.h"
 #include "../ssl/ssl_locl.h"
 
 #ifndef OPENSSL_NO_TLS1_3
@@ -656,6 +657,192 @@ static int execute_test_large_message(const SSL_METHOD 
*smeth,
     return testresult;
 }
 
+#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS)
+
+/* 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 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(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(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 (!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;
+
+    return 1;
+end:
+    return 0;
+}
+
+static int execute_test_ktls(int cis_ktls_tx, int sis_ktls_tx)
+{
+    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 (!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 (!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;
+}
+
+static int test_ktls_client_server(void)
+{
+    return execute_test_ktls(1, 1);
+}
+
+static int test_ktls_no_client_server(void)
+{
+    return execute_test_ktls(0, 1);
+}
+
+static int test_ktls_client_no_server(void)
+{
+    return execute_test_ktls(1, 0);
+}
+
+static int test_ktls_no_client_no_server(void)
+{
+    return execute_test_ktls(0, 0);
+}
+
+#endif
+
 static int test_large_message_tls(void)
 {
     return execute_test_large_message(TLS_server_method(), TLS_client_method(),
@@ -5869,6 +6056,12 @@ int setup_tests(void)
 #endif
     }
 
+#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS)
+    ADD_TEST(test_ktls_client_server);
+    ADD_TEST(test_ktls_no_client_server);
+    ADD_TEST(test_ktls_client_no_server);
+    ADD_TEST(test_ktls_no_client_no_server);
+#endif
     ADD_TEST(test_large_message_tls);
     ADD_TEST(test_large_message_tls_read_ahead);
 #ifndef OPENSSL_NO_DTLS
diff --git a/test/ssltestlib.c b/test/ssltestlib.c
index 9e78430..50c7112 100644
--- a/test/ssltestlib.c
+++ b/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) {
     usleep(millis * 1000);
@@ -655,6 +663,119 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const 
SSL_METHOD *cm,
 
 #define MAXLOOPS    1000000
 
+#ifndef OPENSSL_NO_KTLS
+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;
+}
+#else
+int create_test_sockets(int *cfd, int *sfd)
+{
+    return 0;
+}
+#endif
+
+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;
+}
+
 /*
  * NOTE: Transfers control of the BIOs - this function will free them on error
  */
diff --git a/test/ssltestlib.h b/test/ssltestlib.h
index 435bbbc..8dd6269 100644
--- a/test/ssltestlib.h
+++ b/test/ssltestlib.h
@@ -19,6 +19,9 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const 
SSL_METHOD *cm,
 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 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 a/util/private.num b/util/private.num
index 8e89f1f..09ab417 100644
--- a/util/private.num
+++ b/util/private.num
@@ -108,6 +108,7 @@ 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_conn_address                    define
 BIO_get_conn_hostname                   define
 BIO_get_conn_port                       define
_____
openssl-commits mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-commits

Reply via email to