summaryrefslogtreecommitdiff
path: root/net/tls/tls_main.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-03-31 23:37:33 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-31 23:37:33 -0400
commit06b19fe9a6df7aaa423cd8404ebe5ac9ec4b2960 (patch)
treeab415d55353d186a7b3c68fe46666f8f0a48cc4d /net/tls/tls_main.c
parentd4069fe6fc91d496e4d1fe38b1a8b71aeb181c50 (diff)
parentbd7f48576660022b0779c5c7bf384ec1e8ca83c8 (diff)
Merge branch 'chelsio-inline-tls'
Atul Gupta says: ==================== Chelsio Inline TLS Series for Chelsio Inline TLS driver (chtls) Use tls ULP infrastructure to register chtls as Inline TLS driver. Chtls use TCP Sockets to Tx/Rx TLS records. TCP sk_proto APIs are enhanced to offload TLS record. T6 adapter provides the following features: -TLS record offload, TLS header, encrypt, digest and transmit -TLS record receive and decrypt -TLS keys store -TCP/IP engine -TLS engine -GCM crypto engine [support CBC also] TLS provides security at the transport layer. It uses TCP to provide reliable end-to-end transport of application data. It relies on TCP for any retransmission. TLS session comprises of three parts: a. TCP/IP connection b. TLS handshake c. Record layer processing TLS handshake state machine is executed in host (refer standard implementation eg. OpenSSL). Setsockopt [SOL_TCP, TCP_ULP] initialize TCP proto-ops for Chelsio inline tls support. setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls")); Tx and Rx Keys are decided during handshake and programmed on the chip after CCS is exchanged. struct tls12_crypto_info_aes_gcm_128 crypto_info setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info)) Finish is the first encrypted/decrypted message tx/rx inline. On the Tx path TLS engine receive plain text from openssl, insert IV, fetches the tx key, create cipher text records and generate MAC. TLS header is added to cipher text and forward to TCP/IP engine for transport layer processing and transmission on wire. TX PATH: Apps--openssl--chtls---TLS engine---encrypt/auth---TCP/IP engine---wire On the Rx side, data received is PDU aligned at record boundaries. TLS processes only the complete record. If rx key is programmed on CCS receive, data is decrypted and plain text is posted to host. RX PATH: Wire--cipher-text--TCP/IP engine [PDU align]---TLS engine--- decrypt/auth---plain-text--chtls--openssl--application v15: indent fix in mark_urg -removed unwanted checks in sendmsg, sendpage, recvmsg, close, disconnect,shutdown, destroy sock [Sabrina] - removed unused chtls_free_kmap [chtls.h] - rebase to top of net-next v14: -Reverse christmas tree style for variable declarations for various functions in chtls_hw.c, chtls_io.c [Stefano Brivio] - replaced break with return in tcp_state_to_flowc_state [Stefano Brivio] - renamed tlstx_seq_number to tlstx_incr_seqnum [Stefano Brivio] - use bool for corked, should_push and send_should_push [Stefano Brivio] - removed "Reviewed-by" tag for Stefano, Sabrina, Dave Watson v13: handle clean ctx free for HW_RECORD in tls_sk_proto_close -removed SOCK_INLINE [chtls.h], using csk_conn_inline instead in send_abort_rpl,chtls_send_abort_rpl,chtls_sendmsg,chtls_sendpage -removed sk_no_receive [chtls_io.c] replaced with sk_shutdown & RCV_SHUTDOWN in chtls_pt_recvmsg, peekmsg and chtls_recvmsg -cleaned chtls_expansion_size [Stefano Brivio] - u8 conf:3 in tls_sw_context to add TLS_HW_RECORD -removed is_tls_skb, using tls_skb_inline [Stefano Brivio] -reverse christmas tree formatting in chtls_io.c, chtls_cm.c [Stefano Brivio] -fixed build warning reported by kbuild robot -retained ctx conf enum in chtls_main vs earlier versions, tls_prots not used in chtls. -cleanup [removed syn_sent, base_prot, added synq] [Michael Werner] - passing struct fw_wr_hdr * to ofldtxq_stop [Casey] - rebased on top of the current net-next v12: patch against net-next -fixed build error [reported by Julia] -replace set_queue with skb_set_queue_mapping [Sabrina] -copyright year correction [chtls] v11: formatting and cleanup, few function rename and error handling [Stefano Brivio] - ctx freed later for TLS_HW_RECORD - split tx and rx in different patch v10: fixed following based on the review comments of Sabrina Dubroca -docs header added for struct tls_device [tls.h] -changed TLS_FULL_HW to TLS_HW_RECORD -similary using tls-hw-record instead of tls-inline for ethtool feature config -added more description to patch sets -replaced kmalloc/vmalloc/kfree with kvzalloc/kvfree -reordered the patch sequence -formatted entire patch for func return values v9: corrected __u8 and similar usage -create_ctx to alloc tls_context -tls_hw_prot before sk !establish check v8: tls_main.c cleanup comment [Dave Watson] v7: func name change, use sk->sk_prot where required v6: modify prot only for FULL_HW -corrected commit message for patch 11 v5: set TLS_FULL_HW for registered inline tls drivers -set TLS_FULL_HW prot for offload connection else move to TLS_SW_TX -Case handled for interface with same IP [Dave Miller] -Removed Specific IP and INADDR_ANY handling [v4] v4: removed chtls ULP type, retained tls ULP -registered chtls with net tls -defined struct tls_device to register the Inline drivers -ethtool interface tls-inline to enable Inline TLS for interface -prot update to support inline TLS v3: fixed the kbuild test issues -made few funtions static -initialized few variables v2: fixed the following based on the review comments of Stephan Mueller, Stefano Brivio and Hannes Frederic -Added more details in cover letter -Fixed indentation and formating issues -Using aes instead of aes-generic -memset key info after programing the key on chip -reordered the patch sequence ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tls/tls_main.c')
-rw-r--r--net/tls/tls_main.c114
1 files changed, 111 insertions, 3 deletions
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 6f5c1146da4a..0d379970960e 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -38,6 +38,7 @@
#include <linux/highmem.h>
#include <linux/netdevice.h>
#include <linux/sched/signal.h>
+#include <linux/inetdevice.h>
#include <net/tls.h>
@@ -56,11 +57,14 @@ enum {
TLS_SW_TX,
TLS_SW_RX,
TLS_SW_RXTX,
+ TLS_HW_RECORD,
TLS_NUM_CONFIG,
};
static struct proto *saved_tcpv6_prot;
static DEFINE_MUTEX(tcpv6_prot_mutex);
+static LIST_HEAD(device_list);
+static DEFINE_MUTEX(device_mutex);
static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG];
static struct proto_ops tls_sw_proto_ops;
@@ -241,8 +245,12 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
lock_sock(sk);
sk_proto_close = ctx->sk_proto_close;
+ if (ctx->conf == TLS_HW_RECORD)
+ goto skip_tx_cleanup;
+
if (ctx->conf == TLS_BASE) {
kfree(ctx);
+ ctx = NULL;
goto skip_tx_cleanup;
}
@@ -276,6 +284,11 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
skip_tx_cleanup:
release_sock(sk);
sk_proto_close(sk, timeout);
+ /* free ctx for TLS_HW_RECORD, used by tcp_set_state
+ * for sk->sk_prot->unhash [tls_hw_unhash]
+ */
+ if (ctx && ctx->conf == TLS_HW_RECORD)
+ kfree(ctx);
}
static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval,
@@ -493,6 +506,79 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
return do_tls_setsockopt(sk, optname, optval, optlen);
}
+static struct tls_context *create_ctx(struct sock *sk)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tls_context *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ icsk->icsk_ulp_data = ctx;
+ return ctx;
+}
+
+static int tls_hw_prot(struct sock *sk)
+{
+ struct tls_context *ctx;
+ struct tls_device *dev;
+ int rc = 0;
+
+ mutex_lock(&device_mutex);
+ list_for_each_entry(dev, &device_list, dev_list) {
+ if (dev->feature && dev->feature(dev)) {
+ ctx = create_ctx(sk);
+ if (!ctx)
+ goto out;
+
+ ctx->hash = sk->sk_prot->hash;
+ ctx->unhash = sk->sk_prot->unhash;
+ ctx->sk_proto_close = sk->sk_prot->close;
+ ctx->conf = TLS_HW_RECORD;
+ update_sk_prot(sk, ctx);
+ rc = 1;
+ break;
+ }
+ }
+out:
+ mutex_unlock(&device_mutex);
+ return rc;
+}
+
+static void tls_hw_unhash(struct sock *sk)
+{
+ struct tls_context *ctx = tls_get_ctx(sk);
+ struct tls_device *dev;
+
+ mutex_lock(&device_mutex);
+ list_for_each_entry(dev, &device_list, dev_list) {
+ if (dev->unhash)
+ dev->unhash(dev, sk);
+ }
+ mutex_unlock(&device_mutex);
+ ctx->unhash(sk);
+}
+
+static int tls_hw_hash(struct sock *sk)
+{
+ struct tls_context *ctx = tls_get_ctx(sk);
+ struct tls_device *dev;
+ int err;
+
+ err = ctx->hash(sk);
+ mutex_lock(&device_mutex);
+ list_for_each_entry(dev, &device_list, dev_list) {
+ if (dev->hash)
+ err |= dev->hash(dev, sk);
+ }
+ mutex_unlock(&device_mutex);
+
+ if (err)
+ tls_hw_unhash(sk);
+ return err;
+}
+
static void build_protos(struct proto *prot, struct proto *base)
{
prot[TLS_BASE] = *base;
@@ -511,15 +597,22 @@ static void build_protos(struct proto *prot, struct proto *base)
prot[TLS_SW_RXTX] = prot[TLS_SW_TX];
prot[TLS_SW_RXTX].recvmsg = tls_sw_recvmsg;
prot[TLS_SW_RXTX].close = tls_sk_proto_close;
+
+ prot[TLS_HW_RECORD] = *base;
+ prot[TLS_HW_RECORD].hash = tls_hw_hash;
+ prot[TLS_HW_RECORD].unhash = tls_hw_unhash;
+ prot[TLS_HW_RECORD].close = tls_sk_proto_close;
}
static int tls_init(struct sock *sk)
{
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
- struct inet_connection_sock *icsk = inet_csk(sk);
struct tls_context *ctx;
int rc = 0;
+ if (tls_hw_prot(sk))
+ goto out;
+
/* The TLS ulp is currently supported only for TCP sockets
* in ESTABLISHED state.
* Supporting sockets in LISTEN state will require us
@@ -530,12 +623,11 @@ static int tls_init(struct sock *sk)
return -ENOTSUPP;
/* allocate tls context */
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = create_ctx(sk);
if (!ctx) {
rc = -ENOMEM;
goto out;
}
- icsk->icsk_ulp_data = ctx;
ctx->setsockopt = sk->sk_prot->setsockopt;
ctx->getsockopt = sk->sk_prot->getsockopt;
ctx->sk_proto_close = sk->sk_prot->close;
@@ -557,6 +649,22 @@ out:
return rc;
}
+void tls_register_device(struct tls_device *device)
+{
+ mutex_lock(&device_mutex);
+ list_add_tail(&device->dev_list, &device_list);
+ mutex_unlock(&device_mutex);
+}
+EXPORT_SYMBOL(tls_register_device);
+
+void tls_unregister_device(struct tls_device *device)
+{
+ mutex_lock(&device_mutex);
+ list_del(&device->dev_list);
+ mutex_unlock(&device_mutex);
+}
+EXPORT_SYMBOL(tls_unregister_device);
+
static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
.name = "tls",
.uid = TCP_ULP_TLS,