[openssl-dev] [RFC 2/4] bio: Linux TLS Offload

Boris Pismenny borisp at mellanox.com
Wed Jun 7 12:35:47 UTC 2017


Add support for Linux TLS offload in the BIO layer
and specifically in bss_sock.c.

Change-Id: I64e08da83c595a9067a3c7de80f73408010fcde6
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
---
 crypto/bio/bss_sock.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/openssl/bio.h | 32 ++++++++++++++++++
 2 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/crypto/bio/bss_sock.c b/crypto/bio/bss_sock.c
index 570e898..5f02d04 100644
--- a/crypto/bio/bss_sock.c
+++ b/crypto/bio/bss_sock.c
@@ -27,6 +27,11 @@
 #  define sock_puts  SockPuts
 # endif
 
+#if defined(OPENSSL_LINUX_TLS)
+    #include "netinet/tcp.h"
+#endif
+
+
 static int sock_write(BIO *h, const char *buf, int num);
 static int sock_read(BIO *h, char *buf, int size);
 static int sock_puts(BIO *h, const char *str);
@@ -56,11 +61,21 @@ const BIO_METHOD *BIO_s_socket(void)
 BIO *BIO_new_socket(int fd, int close_flag)
 {
     BIO *ret;
+    int rc;
 
     ret = BIO_new(BIO_s_socket());
     if (ret == NULL)
         return (NULL);
     BIO_set_fd(ret, fd, close_flag);
+#ifdef OPENSSL_LINUX_TLS
+    rc = setsockopt(fd, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
+#ifdef SSL_DEBUG
+    if (rc) {
+        printf("setsockopt failed %d\n", errno);
+    }
+#endif
+
+# endif
     return (ret);
 }
 
@@ -103,12 +118,54 @@ static int sock_read(BIO *b, char *out, int outl)
     return (ret);
 }
 
+static int 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);
+}
+
 static int sock_write(BIO *b, const char *in, int inl)
 {
     int ret;
 
     clear_socket_error();
-    ret = writesocket(b->num, in, inl);
+    if (BIO_should_offload_tx_ctrl_msg_flag(b)) {
+        unsigned char record_type = (unsigned char)b->ptr;
+
+#ifdef SSL_DEBUG
+        printf("\nsending ctrl msg\n");
+#endif
+        BIO_clear_offload_tx_ctrl_msg_flag(b);
+        ret = send_ctrl_message(b->num, record_type, in, inl);
+        if (ret >= 0) {
+            ret = inl;
+        }
+    } else {
+#ifdef SSL_DEBUG
+        printf("\nsending data msg %p %d\n", b, b->flags);
+#endif
+        ret = writesocket(b->num, in, inl);
+    }
     BIO_clear_retry_flags(b);
     if (ret <= 0) {
         if (BIO_sock_should_retry(ret))
@@ -121,6 +178,9 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
 {
     long ret = 1;
     int *ip;
+# ifdef OPENSSL_LINUX_TLS
+    struct tls12_crypto_info_aes_gcm_128 *crypto_info;
+# endif
 
     switch (cmd) {
     case BIO_C_SET_FD:
@@ -148,6 +208,37 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
     case BIO_CTRL_FLUSH:
         ret = 1;
         break;
+# if defined(OPENSSL_LINUX_TLS)
+    case BIO_CTRL_SET_OFFLOAD_TX:
+        crypto_info = (struct tls12_crypto_info_aes_gcm_128 *)ptr;
+        ret = setsockopt(b->num, SOL_TLS, TLS_TX,
+                         crypto_info, sizeof(*crypto_info));
+#ifdef SSL_DEBUG
+        printf("\nAttempt to offload...");
+#endif
+        if (!ret) {
+            BIO_set_offload_tx_flag(b);
+#ifdef SSL_DEBUG
+            printf("Success %p %p\n", b, &(b->flags));
+#endif
+        } else {
+#ifdef SSL_DEBUG
+            printf("Failed ret=%ld\n", ret);
+#endif
+        }
+        break;
+     case BIO_CTRL_GET_OFFLOAD_TX:
+         return BIO_should_offload_tx_flag(b);
+     case BIO_CTRL_SET_OFFLOAD_TX_CTRL_MSG:
+         BIO_set_offload_tx_ctrl_msg_flag(b);
+	 b->ptr = (void *)num;
+         ret = 0;
+         break;
+     case BIO_CTRL_CLEAR_OFFLOAD_TX_CTRL_MSG:
+         BIO_clear_offload_tx_ctrl_msg_flag(b);
+         ret = 0;
+         break;
+# endif
     default:
         ret = 0;
         break;
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 31d41b4..c718627 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -146,6 +146,11 @@ extern "C" {
 #  define BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN               70
 # endif
 
+# define BIO_CTRL_SET_OFFLOAD_TX               71
+# define BIO_CTRL_GET_OFFLOAD_TX               72
+# define BIO_CTRL_SET_OFFLOAD_TX_CTRL_MSG      73
+# define BIO_CTRL_CLEAR_OFFLOAD_TX_CTRL_MSG    74
+
 /* modifiers */
 # define BIO_FP_READ             0x02
 # define BIO_FP_WRITE            0x04
@@ -175,6 +180,13 @@ extern "C" {
 # define BIO_FLAGS_MEM_RDONLY    0x200
 # define BIO_FLAGS_NONCLEAR_RST  0x400
 
+/*
+ * This is used with socket BIOs:
+ * BIO_FLAGS_OFFLOAD_TX means we are using offload with this BIO for TX.
+ * BIO_FLAGS_OFFLOAD_TX_CTRL_MSG means we are about to send a ctrl message next.
+ */
+# define BIO_FLAGS_OFFLOAD_TX          0x2000
+# define BIO_FLAGS_OFFLOAD_TX_CTRL_MSG 0x4000
 typedef union bio_addr_st BIO_ADDR;
 typedef struct bio_addrinfo_st BIO_ADDRINFO;
 
@@ -191,6 +203,18 @@ void BIO_clear_flags(BIO *b, int flags);
 # define BIO_set_retry_write(b) \
                 BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
 
+/* Offload related controls and flags */
+# define BIO_set_offload_tx_flag(b) \
+                BIO_set_flags(b, BIO_FLAGS_OFFLOAD_TX)
+# define BIO_should_offload_tx_flag(b) \
+    BIO_test_flags(b, BIO_FLAGS_OFFLOAD_TX)
+# define BIO_set_offload_tx_ctrl_msg_flag(b) \
+    BIO_set_flags(b, BIO_FLAGS_OFFLOAD_TX_CTRL_MSG)
+# define BIO_should_offload_tx_ctrl_msg_flag(b) \
+    BIO_test_flags(b, (BIO_FLAGS_OFFLOAD_TX_CTRL_MSG))
+# define BIO_clear_offload_tx_ctrl_msg_flag(b) \
+    BIO_clear_flags(b, (BIO_FLAGS_OFFLOAD_TX_CTRL_MSG))
+
 /* These are normally used internally in BIOs */
 # define BIO_clear_retry_flags(b) \
                 BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
@@ -370,6 +394,14 @@ struct bio_dgram_sctp_prinfo {
 #  define BIO_get_conn_address(b)       ((const BIO_ADDR *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2,NULL))
 #  define BIO_get_conn_ip_family(b)     BIO_ctrl(b,BIO_C_GET_CONNECT,3,NULL)
 #  define BIO_set_conn_mode(b,n)        BIO_ctrl(b,BIO_C_SET_CONNECT_MODE,(n),NULL)
+#  define BIO_set_offload_tx(b, keyblob) \
+    BIO_ctrl(b, BIO_CTRL_SET_OFFLOAD_TX, 0, keyblob)
+#  define BIO_get_offload_tx(b)         \
+    BIO_ctrl(b, BIO_CTRL_GET_OFFLOAD_TX, 0, NULL)
+#  define BIO_set_offload_tx_ctrl_msg(b, record_type)   \
+    BIO_ctrl(b, BIO_CTRL_SET_OFFLOAD_TX_CTRL_MSG, record_type, NULL)
+#  define BIO_clear_offload_tx_ctrl_msg(b) \
+    BIO_ctrl(b, BIO_CTRL_CLEAR_OFFLOAD_TX_CTRL_MSG, 0, NULL)
 
 /* BIO_s_accept() */
 #  define BIO_set_accept_name(b,name)   BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name)
-- 
1.8.3.1



More information about the openssl-dev mailing list