Support KTLS on connections using BIO_TYPE_CONNECT.
authorJohn Baldwin <jhb@FreeBSD.org>
Tue, 19 Nov 2019 22:12:56 +0000 (14:12 -0800)
committerTomas Mraz <tmraz@fedoraproject.org>
Mon, 16 Mar 2020 09:41:51 +0000 (10:41 +0100)
This requires duplicating the KTLS changes from bss_sock.c in
bss_conn.c.  One difference from BIO_TYPE_SOCKET is that the call to
ktls_enable is performed after the socket is created in BIO_socket
rather than BIO_new_connect.

Some applications such as 'openssl s_time' use connect BIOs instead of
socket BIOs.  Note that the new connections created for accept BIOs
use BIO_TYPE_SOCKET via BIO_new_socket, so bss_acpt.c does not require
changes.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/10489)

crypto/bio/b_sock2.c
crypto/bio/bss_conn.c

index 942825a..df13d58 100644 (file)
@@ -12,6 +12,7 @@
 #include <errno.h>
 
 #include "bio_local.h"
+#include "internal/ktls.h"
 
 #include <openssl/err.h>
 
@@ -51,6 +52,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;
 }
index 6c554ff..87009fb 100644 (file)
@@ -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;
@@ -308,7 +312,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))
@@ -333,7 +342,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))
@@ -349,6 +367,13 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
     const char **pptr = NULL;
     long ret = 1;
     BIO_CONNECT *data;
+# ifndef OPENSSL_NO_KTLS
+#  ifdef __FreeBSD__
+    struct tls_enable *crypto_info;
+#  else
+    struct tls12_crypto_info_aes_gcm_128 *crypto_info;
+#  endif
+# endif
 
     data = (BIO_CONNECT *)b->ptr;
 
@@ -497,6 +522,31 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
     case BIO_CTRL_EOF:
         ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0;
         break;
+# ifndef OPENSSL_NO_KTLS
+    case BIO_CTRL_SET_KTLS:
+#  ifdef __FreeBSD__
+        crypto_info = (struct tls_enable *)ptr;
+#  else
+        crypto_info = (struct tls12_crypto_info_aes_gcm_128 *)ptr;
+#  endif
+        ret = ktls_start(b->num, crypto_info, sizeof(*crypto_info), num);
+        if (ret)
+            BIO_set_ktls_flag(b, num);
+        break;
+    case BIO_CTRL_GET_KTLS_SEND:
+        return BIO_should_ktls_flag(b, 1);
+    case BIO_CTRL_GET_KTLS_RECV:
+        return BIO_should_ktls_flag(b, 0);
+    case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
+        BIO_set_ktls_ctrl_msg_flag(b);
+        data->record_type = num;
+        ret = 0;
+        break;
+    case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
+        BIO_clear_ktls_ctrl_msg_flag(b);
+        ret = 0;
+        break;
+# endif
     default:
         ret = 0;
         break;