The branch master has been updated
       via  9058d9bcd0a0391353720f7728a48596b575ad64 (commit)
       via  005080aa62a8da4a64cd749a2620a89b29e5be26 (commit)
       via  2fab79af4666d010647c1f3b2e2687ba1201dfa4 (commit)
       via  c35e921ffa58a84be7f68a37e5799ebefecf7326 (commit)
       via  e401ef801e410d4d0d6dba62cc599cde786024b5 (commit)
       via  f851a689328508cf1c5e64c0cde249956b72789f (commit)
      from  31b6ed76dfd53529b74e79830c81372d0b756929 (commit)


- Log -----------------------------------------------------------------
commit 9058d9bcd0a0391353720f7728a48596b575ad64
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Dec 6 21:36:08 2018 +0200

    add documentation
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

commit 005080aa62a8da4a64cd749a2620a89b29e5be26
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Dec 6 21:17:26 2018 +0200

    apps: print Kernel receive side TLS in s_client and s_server
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

commit 2fab79af4666d010647c1f3b2e2687ba1201dfa4
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Sun Mar 11 16:20:29 2018 +0200

    sslapitest: add test ktls Rx
    
    Add a unit-test for ktls receive side.
    
    Change-Id: I890588681d05fba419f644f6d903be6dc83c9ed5
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

commit c35e921ffa58a84be7f68a37e5799ebefecf7326
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Thu Feb 21 16:39:36 2019 +0200

    ssl: Linux TLS Rx Offload
    
    This patch adds support for the Linux TLS Rx socket option.
    It completes the previous patch for TLS Tx offload.
    If the socket option is successful, then the receive 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.
    
    Change-Id: I59741e04d89dddca7fb138e88fffcc1259b30132
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

commit e401ef801e410d4d0d6dba62cc599cde786024b5
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Sun Mar 11 16:17:51 2018 +0200

    bio: Linux TLS Rx Offload
    
    Add support for Linux TLS Rx offload in the BIO layer.
    
    Change-Id: I79924b25dd290a873d69f6c8d429e1f5bb2c3365
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

commit f851a689328508cf1c5e64c0cde249956b72789f
Author: Boris Pismenny <bor...@mellanox.com>
Date:   Sun Mar 11 16:16:16 2018 +0200

    Linux ktls Rx infrastructure
    
    Introduce the infrastructure for supproting receive side Linux Kernel TLS
    data-path.
    
    Change-Id: I71864d8f9d74a701cc8b0ad5536005f3c1716c1c
    Signed-off-by: Boris Pismenny <bor...@mellanox.com>
    
    Reviewed-by: Bernd Edlinger <bernd.edlin...@hotmail.de>
    Reviewed-by: Matt Caswell <m...@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/7848)

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

Summary of changes:
 apps/s_client.c           |   2 +
 apps/s_server.c           |   2 +
 crypto/bio/bss_sock.c     |  19 ++++--
 doc/man3/BIO_ctrl.pod     |  15 +++--
 include/internal/bio.h    |  37 ++++++------
 include/internal/ktls.h   | 107 ++++++++++++++++++++++++++++----
 include/openssl/bio.h     |   9 ++-
 include/openssl/ssl.h     |   6 +-
 ssl/record/rec_layer_s3.c |  10 ++-
 ssl/record/ssl3_record.c  |  47 +++++++++++++--
 ssl/t1_enc.c              |  87 ++++++++++++++++++++++----
 test/sslapitest.c         | 151 +++++++++++++++++++++++++++++++++++++++++-----
 util/private.num          |   1 +
 13 files changed, 415 insertions(+), 78 deletions(-)

diff --git a/apps/s_client.c b/apps/s_client.c
index 6d7a83f..bb4f0aa 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -3313,6 +3313,8 @@ static void print_stuff(BIO *bio, SSL *s, int full)
 #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
 
     if (OSSL_TRACE_ENABLED(TLS)) {
diff --git a/apps/s_server.c b/apps/s_server.c
index 92d4579..381b1c9 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -2921,6 +2921,8 @@ static void print_connection_info(SSL *con)
 #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/bio/bss_sock.c b/crypto/bio/bss_sock.c
index 60e5adc..0c99459 100644
--- a/crypto/bio/bss_sock.c
+++ b/crypto/bio/bss_sock.c
@@ -108,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))
@@ -177,20 +182,22 @@ static long sock_ctrl(BIO *b, int cmd, long num, void 
*ptr)
         ret = 1;
         break;
 # ifndef OPENSSL_NO_KTLS
-    case BIO_CTRL_SET_KTLS_SEND:
+    case BIO_CTRL_SET_KTLS:
         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);
+            BIO_set_ktls_flag(b, num);
         break;
     case BIO_CTRL_GET_KTLS_SEND:
-        return BIO_should_ktls_flag(b);
-    case BIO_CTRL_SET_KTLS_SEND_CTRL_MSG:
+        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_CTRL_MSG:
+    case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
         BIO_clear_ktls_ctrl_msg_flag(b);
         ret = 0;
         break;
diff --git a/doc/man3/BIO_ctrl.pod b/doc/man3/BIO_ctrl.pod
index 29e72aa..f51593f 100644
--- a/doc/man3/BIO_ctrl.pod
+++ b/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_ktls_send
+BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, BIO_get_ktls_send,
+BIO_get_ktls_recv
 - BIO control operations
 
 =head1 SYNOPSIS
@@ -35,6 +36,7 @@ BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, 
BIO_get_ktls_send
  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
 
@@ -74,8 +76,10 @@ 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
+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
 
@@ -97,8 +101,10 @@ 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
+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
 
@@ -134,7 +140,8 @@ 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.
+The BIO_get_ktls_send() and BIO_get_ktls_recv() functions were added in
+OpenSSL 3.0.0.
 
 =head1 COPYRIGHT
 
diff --git a/include/internal/bio.h b/include/internal/bio.h
index 1e80d5a..8f368e3 100644
--- a/include/internal/bio.h
+++ b/include/internal/bio.h
@@ -35,35 +35,38 @@ void bio_cleanup(void);
 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
+/* 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 means we are using ktls with this BIO.
- * BIO_FLAGS_KTLS_CTRL_MSG means we are about to send a ctrl message next.
+ * 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          0x800
-# define BIO_FLAGS_KTLS_CTRL_MSG 0x1000
+# 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) \
-    BIO_set_flags(b, BIO_FLAGS_KTLS)
-# define BIO_should_ktls_flag(b) \
-    BIO_test_flags(b, BIO_FLAGS_KTLS)
+# 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_CTRL_MSG)
+    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_CTRL_MSG))
+    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_CTRL_MSG))
+    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_SEND, is_tx, keyblob)
+     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_SEND_CTRL_MSG, record_type, NULL)
+     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_CTRL_MSG, 0, NULL)
+     BIO_ctrl(b, BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG, 0, NULL)
 
 #endif
diff --git a/include/internal/ktls.h b/include/internal/ktls.h
index 23a0397..5495a8d 100644
--- a/include/internal/ktls.h
+++ b/include/internal/ktls.h
@@ -21,10 +21,11 @@
 
 #    ifndef PEDANTIC
 #     warning "KTLS requires Kernel Headers >= 4.13.0"
-#     warning "Skipping Compilation of KTLS data path"
+#     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
@@ -67,11 +68,19 @@ static ossl_inline int ktls_send_ctrl_message(int fd, 
unsigned char record_type,
     return -1;
 }
 
+static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
+{
+    return -1;
+}
+
 #   else                        /* KERNEL_VERSION */
 
 #    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
@@ -96,16 +105,16 @@ static ossl_inline int ktls_enable(int fd)
  * 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)
 {
-    if (is_tx)
-        return setsockopt(fd, SOL_TLS, TLS_TX, crypto_info,
-                          sizeof(*crypto_info)) ? 0 : 1;
-    else
-        return 0;
+    return setsockopt(fd, SOL_TLS, is_tx ? TLS_TX : TLS_RX,
+                      crypto_info, sizeof(*crypto_info)) ? 0 : 1;
 }
 
 /*
@@ -121,12 +130,15 @@ static ossl_inline int ktls_send_ctrl_message(int fd, 
unsigned char record_type,
     struct msghdr msg;
     int cmsg_len = sizeof(record_type);
     struct cmsghdr *cmsg;
-    char buf[CMSG_SPACE(cmsg_len)];
+    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 = buf;
-    msg.msg_controllen = sizeof(buf);
+    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;
@@ -142,7 +154,76 @@ static ossl_inline int ktls_send_ctrl_message(int fd, 
unsigned char record_type,
     return sendmsg(fd, &msg, 0);
 }
 
-#   endif                       /* KERNEL_VERSION */
-#  endif                        /* OPENSSL_SYS_LINUX */
-# endif                         /* HEADER_INTERNAL_KTLS */
-#endif                          /* OPENSSL_NO_KTLS */
+#    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 a/include/openssl/bio.h b/include/openssl/bio.h
index ed9d489..85cbe0a 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -145,15 +145,20 @@ extern "C" {
 
 # define BIO_CTRL_DGRAM_SET_PEEK_MODE      71
 
-/* internal BIO see include/internal/bio.h:
+/*
+ * 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_CLEAR_KTLS_CTRL_MSG           75
  */
 
 #  define BIO_CTRL_GET_KTLS_SEND                 73
+#  define BIO_CTRL_GET_KTLS_RECV                 76
+
 #  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)
 
 /* modifiers */
 # define BIO_FP_READ             0x02
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 72c9d06..f4b17f1 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -500,7 +500,7 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
  */
 # define SSL_MODE_ASYNC 0x00000100U
 /*
- * Use the kernel TLS transmission data-path.
+ * Don't use the kernel TLS data-path for sending.
  */
 # define SSL_MODE_NO_KTLS_TX 0x00000200U
 /*
@@ -515,6 +515,10 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
  * - 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 */
 /*
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index b212277..8b2320d 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/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)
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index e1231d2..24694b3 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -187,9 +187,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;
@@ -208,8 +210,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) {
+                if (!BIO_get_ktls_recv(s->rbio))
+                    return rret;     /* error or non-blocking */
+#ifndef OPENSSL_NO_KTLS
+                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;
+                }
+                return rret;
+#endif
+            }
             RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
 
             p = RECORD_LAYER_get_packet(&s->rlayer);
@@ -387,7 +413,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;
@@ -405,6 +431,7 @@ int ssl3_get_record(SSL *s)
         } else {
             more = thisrr->length;
         }
+
         if (more > 0) {
             /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
 
@@ -493,6 +520,13 @@ int ssl3_get_record(SSL *s)
     }
 
     /*
+     * 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.
      */
@@ -674,6 +708,8 @@ int ssl3_get_record(SSL *s)
         return -1;
     }
 
+ skip_decryption:
+
     for (j = 0; j < num_recs; j++) {
         thisrr = &rr[j];
 
@@ -735,7 +771,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;
@@ -743,7 +779,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 a/ssl/t1_enc.c b/ssl/t1_enc.c
index fe4ba93..5925e6a 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -83,6 +83,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;
@@ -101,8 +134,10 @@ int tls1_change_cipher_state(SSL *s, int which)
     int reuse_dd = 0;
 #ifndef OPENSSL_NO_KTLS
     struct tls12_crypto_info_aes_gcm_128 crypto_info;
-    BIO *wbio;
+    BIO *bio;
     unsigned char geniv[12];
+    int count_unprocessed;
+    int bit;
 #endif
 
     c = s->s3->tmp.new_sym_enc;
@@ -326,8 +361,8 @@ int tls1_change_cipher_state(SSL *s, int which)
     if (s->compress)
         goto skip_ktls;
 
-    if ((which & SSL3_CC_READ) ||
-        ((which & SSL3_CC_WRITE) && (s->mode & SSL_MODE_NO_KTLS_TX)))
+    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 */
@@ -344,19 +379,26 @@ int tls1_change_cipher_state(SSL *s, int which)
     if (s->version != TLS1_2_VERSION)
         goto skip_ktls;
 
-    wbio = s->wbio;
-    if (!ossl_assert(wbio != NULL)) {
+    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 (BIO_flush(wbio) <= 0)
-        goto 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)) {
+    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;
@@ -373,12 +415,33 @@ int tls1_change_cipher_state(SSL *s, int which)
            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);
+    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--;
+        }
+    }
 
     /* ktls works with user provided buffers directly */
-    if (BIO_set_ktls(wbio, &crypto_info, which & SSL3_CC_WRITE)) {
-        ssl3_release_write_buffer(s);
+    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);
     }
 
diff --git a/test/sslapitest.c b/test/sslapitest.c
index bccf055..7ca8c75 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -723,6 +723,8 @@ static int ping_pong_query(SSL *clientssl, SSL *serverssl, 
int cfd, int sfd)
     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];
@@ -731,6 +733,8 @@ static int ping_pong_query(SSL *clientssl, SSL *serverssl, 
int cfd, int sfd)
     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,
@@ -756,6 +760,8 @@ static int ping_pong_query(SSL *clientssl, SSL *serverssl, 
int cfd, int sfd)
 
     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,
@@ -786,16 +792,33 @@ static int ping_pong_query(SSL *clientssl, SSL 
*serverssl, int cfd, int sfd)
             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;
+    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 sis_ktls_tx)
+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;
@@ -830,6 +853,16 @@ static int execute_test_ktls(int cis_ktls_tx, int 
sis_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;
@@ -850,6 +883,22 @@ static int execute_test_ktls(int cis_ktls_tx, int 
sis_ktls_tx)
             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;
 
@@ -869,24 +918,84 @@ end:
     return testresult;
 }
 
-static int test_ktls_client_server(void)
+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);
+    return execute_test_ktls(1, 1, 1, 0);
 }
 
-static int test_ktls_no_client_server(void)
+static int test_ktls_no_txrx_client_no_tx_server(void)
 {
-    return execute_test_ktls(0, 1);
+    return execute_test_ktls(0, 0, 0, 1);
 }
 
-static int test_ktls_client_no_server(void)
+static int test_ktls_no_rx_client_no_tx_server(void)
 {
-    return execute_test_ktls(1, 0);
+    return execute_test_ktls(1, 0, 0, 1);
 }
 
-static int test_ktls_no_client_no_server(void)
+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(0, 0);
+    return execute_test_ktls(1, 1, 1, 1);
 }
 
 #endif
@@ -6155,10 +6264,22 @@ int setup_tests(void)
 
 #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_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);
diff --git a/util/private.num b/util/private.num
index 6c37fc0..f15957b 100644
--- a/util/private.num
+++ b/util/private.num
@@ -116,6 +116,7 @@ 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

Reply via email to