git: aa906e2a4957 - main - OpenSSL: Support for kernel TLS offload (KTLS)

John Baldwin jhb at FreeBSD.org
Thu Jan 28 18:25:29 UTC 2021


The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=aa906e2a4957db700d9e6cc60857e1afe1aecc85

commit aa906e2a4957db700d9e6cc60857e1afe1aecc85
Author:     John Baldwin <jhb at FreeBSD.org>
AuthorDate: 2021-01-16 00:17:31 +0000
Commit:     John Baldwin <jhb at FreeBSD.org>
CommitDate: 2021-01-28 18:24:13 +0000

    OpenSSL: Support for kernel TLS offload (KTLS)
    
    This merges upstream patches from OpenSSL's master branch to add
    KTLS infrastructure for TLS 1.0-1.3 including both RX and TX
    offload and SSL_sendfile support on both Linux and FreeBSD.
    
    Note that TLS 1.3 only supports TX offload.
    
    A new WITH/WITHOUT_OPENSSL_KTLS determines if OpenSSL is built with
    KTLS support.  It defaults to enabled on amd64 and disabled on all
    other architectures.
    
    Reviewed by:    jkim (earlier version)
    Approved by:    secteam
    Obtained from:  OpenSSL (patches from master)
    MFC after:      1 week
    Relnotes:       yes
    Sponsored by:   Netflix
    Differential Revision:  https://reviews.freebsd.org/D28273
---
 crypto/openssl/CHANGES                             |   5 +
 crypto/openssl/Configure                           |  29 ++
 crypto/openssl/INSTALL                             |   9 +
 crypto/openssl/apps/s_client.c                     |   6 +
 crypto/openssl/apps/s_server.c                     |   6 +
 crypto/openssl/crypto/bio/b_sock2.c                |  12 +
 crypto/openssl/crypto/bio/bss_conn.c               |  46 ++-
 crypto/openssl/crypto/bio/bss_sock.c               |  57 ++-
 crypto/openssl/crypto/err/openssl.txt              |   1 +
 crypto/openssl/crypto/evp/e_aes.c                  |   8 +
 crypto/openssl/doc/man3/BIO_ctrl.pod               |  21 +-
 crypto/openssl/doc/man3/SSL_CTX_set_mode.pod       |  17 +
 .../man3/SSL_CTX_set_record_padding_callback.pod   |  10 +-
 crypto/openssl/doc/man3/SSL_write.pod              |  31 +-
 crypto/openssl/engines/e_afalg.c                   |   3 +-
 crypto/openssl/include/internal/bio.h              |  39 ++
 crypto/openssl/include/internal/ktls.h             | 403 +++++++++++++++++++++
 crypto/openssl/include/openssl/bio.h               |  20 +
 crypto/openssl/include/openssl/err.h               |   1 +
 crypto/openssl/include/openssl/evp.h               |   2 +
 crypto/openssl/include/openssl/ssl.h               |  12 +-
 crypto/openssl/include/openssl/sslerr.h            |   1 +
 crypto/openssl/ssl/build.info                      |   5 +
 crypto/openssl/ssl/ktls.c                          | 221 +++++++++++
 crypto/openssl/ssl/record/rec_layer_s3.c           | 137 +++++--
 crypto/openssl/ssl/record/record.h                 |   2 +
 crypto/openssl/ssl/record/record_local.h           |   3 +
 crypto/openssl/ssl/record/ssl3_buffer.c            |  33 +-
 crypto/openssl/ssl/record/ssl3_record.c            |  47 ++-
 crypto/openssl/ssl/ssl_err.c                       |   1 +
 crypto/openssl/ssl/ssl_lib.c                       | 104 +++++-
 crypto/openssl/ssl/ssl_local.h                     |  13 +
 crypto/openssl/ssl/t1_enc.c                        | 128 +++++++
 crypto/openssl/ssl/tls13_enc.c                     |  81 ++++-
 secure/lib/libcrypto/Makefile                      |  18 +-
 secure/lib/libcrypto/opensslconf.h.in              |   3 +
 secure/lib/libssl/Makefile                         |   6 +
 secure/lib/libssl/Version.map                      |   6 +
 share/mk/src.opts.mk                               |   7 +
 tools/build/options/WITHOUT_OPENSSL_KTLS           |   1 +
 tools/build/options/WITH_OPENSSL_KTLS              |   1 +
 41 files changed, 1465 insertions(+), 91 deletions(-)

diff --git a/crypto/openssl/CHANGES b/crypto/openssl/CHANGES
index 37dd60b726ee..4d61c1dadbaa 100644
--- a/crypto/openssl/CHANGES
+++ b/crypto/openssl/CHANGES
@@ -390,6 +390,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 a/crypto/openssl/Configure b/crypto/openssl/Configure
index 1d73d06e1b3b..1423e1bfe14f 100755
--- a/crypto/openssl/Configure
+++ b/crypto/openssl/Configure
@@ -387,6 +387,7 @@ my @disablables = (
     "heartbeats",
     "hw(-.+)?",
     "idea",
+    "ktls",
     "makedepend",
     "md2",
     "md4",
@@ -474,6 +475,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
@@ -1580,6 +1582,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 a/crypto/openssl/INSTALL b/crypto/openssl/INSTALL
index f5118428b3bc..be84f2aa8e5d 100644
--- a/crypto/openssl/INSTALL
+++ b/crypto/openssl/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 a/crypto/openssl/apps/s_client.c b/crypto/openssl/apps/s_client.c
index 83b3fc9c7f13..68bd9ced015f 100644
--- a/crypto/openssl/apps/s_client.c
+++ b/crypto/openssl/apps/s_client.c
@@ -3282,6 +3282,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 a/crypto/openssl/apps/s_server.c b/crypto/openssl/apps/s_server.c
index 0ba75999fd28..ddc0b4bcd76d 100644
--- a/crypto/openssl/apps/s_server.c
+++ b/crypto/openssl/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 a/crypto/openssl/crypto/bio/b_sock2.c b/crypto/openssl/crypto/bio/b_sock2.c
index 335dfabc6180..80ef348d9254 100644
--- a/crypto/openssl/crypto/bio/b_sock2.c
+++ b/crypto/openssl/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 a/crypto/openssl/crypto/bio/bss_conn.c b/crypto/openssl/crypto/bio/bss_conn.c
index 807a82b23ba2..d4786442803e 100644
--- a/crypto/openssl/crypto/bio/bss_conn.c
+++ b/crypto/openssl/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;
@@ -320,7 +324,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))
@@ -345,7 +354,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))
@@ -361,6 +379,9 @@ 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
+    ktls_crypto_info_t *crypto_info;
+# endif
 
     data = (BIO_CONNECT *)b->ptr;
 
@@ -520,6 +541,27 @@ 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:
+        crypto_info = (ktls_crypto_info_t *)ptr;
+        ret = ktls_start(b->num, 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 a/crypto/openssl/crypto/bio/bss_sock.c b/crypto/openssl/crypto/bio/bss_sock.c
index 6251f3d46a17..a1fc23c7c938 100644
--- a/crypto/openssl/crypto/bio/bss_sock.c
+++ b/crypto/openssl/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,9 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
 {
     long ret = 1;
     int *ip;
+# ifndef OPENSSL_NO_KTLS
+    ktls_crypto_info_t *crypto_info;
+# endif
 
     switch (cmd) {
     case BIO_C_SET_FD:
@@ -153,6 +183,27 @@ 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:
+        crypto_info = (ktls_crypto_info_t *)ptr;
+        ret = ktls_start(b->num, 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 a/crypto/openssl/crypto/err/openssl.txt b/crypto/openssl/crypto/err/openssl.txt
index 815460b24f67..d547c45913d6 100644
--- a/crypto/openssl/crypto/err/openssl.txt
+++ b/crypto/openssl/crypto/err/openssl.txt
@@ -1318,6 +1318,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 a/crypto/openssl/crypto/evp/e_aes.c b/crypto/openssl/crypto/evp/e_aes.c
index 405ddbf9bf09..4640c7528a20 100644
--- a/crypto/openssl/crypto/evp/e_aes.c
+++ b/crypto/openssl/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 a/crypto/openssl/doc/man3/BIO_ctrl.pod b/crypto/openssl/doc/man3/BIO_ctrl.pod
index 2e438c3ce952..31b18b2879fe 100644
--- a/crypto/openssl/doc/man3/BIO_ctrl.pod
+++ b/crypto/openssl/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-2020 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/crypto/openssl/doc/man3/SSL_CTX_set_mode.pod b/crypto/openssl/doc/man3/SSL_CTX_set_mode.pod
index 85e3353e0e2c..27eaebad1ea0 100644
--- a/crypto/openssl/doc/man3/SSL_CTX_set_mode.pod
+++ b/crypto/openssl/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 a/crypto/openssl/doc/man3/SSL_CTX_set_record_padding_callback.pod b/crypto/openssl/doc/man3/SSL_CTX_set_record_padding_callback.pod
index 13e56f0c57f6..247a39fc0355 100644
--- a/crypto/openssl/doc/man3/SSL_CTX_set_record_padding_callback.pod
+++ b/crypto/openssl/doc/man3/SSL_CTX_set_record_padding_callback.pod
@@ -16,7 +16,7 @@ SSL_set_block_padding - install callback to specify TLS 1.3 record padding
  #include <openssl/ssl.h>
 
  void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx, size_t (*cb)(SSL *s, int type, size_t len, void *arg));
- void SSL_set_record_padding_callback(SSL *ssl, size_t (*cb)(SSL *s, int type, size_t len, void *arg));
+ int SSL_set_record_padding_callback(SSL *ssl, size_t (*cb)(SSL *s, int type, size_t len, void *arg));
 
  void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg);
  void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx);
@@ -32,6 +32,8 @@ SSL_set_block_padding - install callback to specify TLS 1.3 record padding
 SSL_CTX_set_record_padding_callback() or SSL_set_record_padding_callback()
 can be used to assign a callback function I<cb> to specify the padding
 for TLS 1.3 records. The value set in B<ctx> is copied to a new SSL by SSL_new().
+Kernel TLS is not possible if the record padding callback is set, and the callback
+function cannot be set if Kernel TLS is already configured for the current SSL object.
 
 SSL_CTX_set_record_padding_callback_arg() and SSL_set_record_padding_callback_arg()
 assign a value B<arg> that is passed to the callback when it is invoked. The value
@@ -64,6 +66,9 @@ indicates no padding will be added. A return value that causes the record to
 exceed the maximum record size (SSL3_RT_MAX_PLAIN_LENGTH) will pad out to the
 maximum record size.
 
+The SSL_CTX_get_record_padding_callback_arg() function returns 1 on success or 0 if
+the callback function is not set because Kernel TLS is configured for the SSL object.
+
 =head1 NOTES
 
 The default behavior is to add no padding to the record.
@@ -84,6 +89,9 @@ L<ssl(7)>, L<SSL_new(3)>
 
 The record padding API was added for TLS 1.3 support in OpenSSL 1.1.1.
 
+The return type of SSL_CTX_set_record_padding_callback() function was
+changed to int in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/crypto/openssl/doc/man3/SSL_write.pod b/crypto/openssl/doc/man3/SSL_write.pod
index 5e3ce1e7e4dd..20c7953deb06 100644
--- a/crypto/openssl/doc/man3/SSL_write.pod
+++ b/crypto/openssl/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 a/crypto/openssl/engines/e_afalg.c b/crypto/openssl/engines/e_afalg.c
index 4b1722846133..5ef3a8d457e6 100644
--- a/crypto/openssl/engines/e_afalg.c
+++ b/crypto/openssl/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 a/crypto/openssl/include/internal/bio.h b/crypto/openssl/include/internal/bio.h
index c343b276295c..521b5fa2198f 100644
--- a/crypto/openssl/include/internal/bio.h
+++ b/crypto/openssl/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 a/crypto/openssl/include/internal/ktls.h b/crypto/openssl/include/internal/ktls.h
new file mode 100644
index 000000000000..9032c0ed6174
--- /dev/null
+++ b/crypto/openssl/include/internal/ktls.h
@@ -0,0 +1,403 @@
+/*
+ * 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
+ */
+
+#if defined(OPENSSL_SYS_LINUX)
+# ifndef OPENSSL_NO_KTLS
+#  include <linux/version.h>
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
+#   define OPENSSL_NO_KTLS
+#   ifndef PEDANTIC
+#    warning "KTLS requires Kernel Headers >= 4.13.0"
+#    warning "Skipping Compilation of KTLS"
+#   endif
+#  endif
+# endif
+#endif
+
+#ifndef HEADER_INTERNAL_KTLS
+# define HEADER_INTERNAL_KTLS
+# ifndef OPENSSL_NO_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 "openssl/ssl3.h"
+
+#   ifndef TCP_RXTLS_ENABLE
+#    define OPENSSL_NO_KTLS_RX
+#   endif
+#   define OPENSSL_KTLS_AES_GCM_128
+#   define OPENSSL_KTLS_AES_GCM_256
+#   define OPENSSL_KTLS_TLS13
+
+/*
+ * Only used by the tests in sslapitest.c.
+ */
+#   define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE             8
+#   define TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE             8
+
+typedef struct tls_enable ktls_crypto_info_t;
+
+/*
+ * 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.
+ *
+ * The TCP_RXTLS_ENABLE socket option marks the incoming socket buffer
+ * as using TLS.  If successful, then data received for this socket will
+ * be authenticated and decrypted using the tls_en provided here.
+ */
+static ossl_inline int ktls_start(int fd, ktls_crypto_info_t *tls_en, int is_tx)
+{
+    if (is_tx)
+        return setsockopt(fd, IPPROTO_TCP, TCP_TXTLS_ENABLE,
+                          tls_en, sizeof(*tls_en)) ? 0 : 1;
+#   ifndef OPENSSL_NO_KTLS_RX
+    return setsockopt(fd, IPPROTO_TCP, TCP_RXTLS_ENABLE, tls_en,
+                      sizeof(*tls_en)) ? 0 : 1;
+#   else
+    return 0;
+#   endif
+}
+
+/*
+ * 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);
+}
+
+#   ifdef OPENSSL_NO_KTLS_RX
+
+static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
+{
+    return -1;
+}
+
+#   else /* !defined(OPENSSL_NO_KTLS_RX) */
+
+/*
+ * Receive a TLS record using the tls_en provided in ktls_start.  The
+ * kernel strips any explicit IV and authentication tag, but provides
+ * the TLS record header via a control message.  If there is an error
+ * with the TLS record such as an invalid header, invalid padding, or
+ * authentication failure recvmsg() will fail with an error.
+ */
+static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
+{
+    struct msghdr msg = { 0 };
+    int cmsg_len = sizeof(struct tls_get_record);
+    struct tls_get_record *tgr;
+    struct cmsghdr *cmsg;
+    char buf[CMSG_SPACE(cmsg_len)];
+    struct iovec msg_iov;   /* Vector of data to send/receive into */
+    int ret;
+    unsigned char *p = data;
+    const size_t prepend_length = SSL3_RT_HEADER_LENGTH;
+
+    if (length <= prepend_length) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    msg.msg_control = buf;
+    msg.msg_controllen = sizeof(buf);
+
+    msg_iov.iov_base = p + prepend_length;
+    msg_iov.iov_len = length - prepend_length;
+    msg.msg_iov = &msg_iov;
+    msg.msg_iovlen = 1;
+
+    ret = recvmsg(fd, &msg, 0);
+    if (ret <= 0)
+        return ret;
+
+    if ((msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) != MSG_EOR) {
+        errno = EMSGSIZE;
+        return -1;
+    }
+
+    if (msg.msg_controllen == 0) {
+        errno = EBADMSG;
+        return -1;
+    }
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    if (cmsg->cmsg_level != IPPROTO_TCP || cmsg->cmsg_type != TLS_GET_RECORD
+        || cmsg->cmsg_len != CMSG_LEN(cmsg_len)) {
+        errno = EBADMSG;
+        return -1;
+    }
+
+    tgr = (struct tls_get_record *)CMSG_DATA(cmsg);
+    p[0] = tgr->tls_type;
+    p[1] = tgr->tls_vmajor;
+    p[2] = tgr->tls_vminor;
+    *(uint16_t *)(p + 3) = htons(ret);
+
+    return ret + prepend_length;
+}
+
+#   endif /* OPENSSL_NO_KTLS_RX */
+
+/*
+ * 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/tls.h>
+#   if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
+#    define OPENSSL_NO_KTLS_RX
+#    ifndef PEDANTIC
+#     warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"
+#     warning "Skipping Compilation of KTLS receive data path"
+#    endif
+#   endif
+#   define OPENSSL_KTLS_AES_GCM_128
+#   if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+#    define OPENSSL_KTLS_AES_GCM_256
+#    define OPENSSL_KTLS_TLS13
+#    if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
+#     define OPENSSL_KTLS_AES_CCM_128
+#    endif
+#   endif
+
+#   include <sys/sendfile.h>
+#   include <netinet/tcp.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
*** 1681 LINES SKIPPED ***


More information about the dev-commits-src-all mailing list