aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/tcp.438
-rw-r--r--sys/dev/cxgbe/tom/t4_tom.c8
-rw-r--r--sys/kern/uipc_ktls.c79
-rw-r--r--sys/kern/uipc_socket.c22
-rw-r--r--sys/netinet/tcp.h3
-rw-r--r--sys/netinet/tcp_offload.c5
-rw-r--r--sys/netinet/tcp_offload.h2
-rw-r--r--sys/netinet/tcp_usrreq.c13
-rw-r--r--sys/netinet/toecore.c2
-rw-r--r--sys/netinet/toecore.h2
-rw-r--r--sys/sys/ktls.h19
11 files changed, 175 insertions, 18 deletions
diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index 7fc1ccb29928..915b8d0b6bf5 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -34,7 +34,7 @@
.\" From: @(#)tcp.4 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd April 16, 2020
+.Dd April 27, 2020
.Dt TCP 4
.Os
.Sh NAME
@@ -319,14 +319,11 @@ control message.
The payload of this control message is a single byte holding the desired
TLS record type.
.Pp
-Data read from this socket will still be encrypted and must be parsed by
-a TLS-aware consumer.
-.Pp
-At present, only a single key may be set on a socket.
+At present, only a single transmit key may be set on a socket.
As such, users of this option must disable rekeying.
.It Dv TCP_TXTLS_MODE
-The integer argument can be used to get or set the current TLS mode of a
-socket.
+The integer argument can be used to get or set the current TLS transmit mode
+of a socket.
Setting the mode can only used to toggle between software and NIC TLS after
TLS has been initially enabled via the
.Dv TCP_TXTLS_ENABLE
@@ -344,6 +341,33 @@ TLS records are encrypted by the network interface card (NIC).
.It Dv TCP_TLS_MODE_TOE
TLS records are encrypted by the NIC using a TCP offload engine (TOE).
.El
+.It Dv TCP_RXTLS_ENABLE
+Enable in-kernel TLS for data read from this socket.
+The
+.Vt struct tls_so_enable
+argument defines the encryption and authentication algorithms and keys
+used to decrypt the socket data.
+.Pp
+Each received TLS record must be read from the socket using
+.Xr recvmsg 2 .
+Each received TLS record will contain a
+.Dv TLS_GET_RECORD
+control message along with the decrypted payload.
+The control message contains a
+.Vt struct tls_get_record
+which includes fields from the TLS record header.
+If a corrupted TLS record is received,
+recvmsg 2
+will fail with
+.Dv EBADMSG .
+.Pp
+At present, only a single receive key may be set on a socket.
+As such, users of this option must disable rekeying.
+.It Dv TCP_RXTLS_MODE
+The integer argument can be used to get the current TLS receive mode
+of a socket.
+The available modes are the same as for
+.Dv TCP_TXTLS_MODE .
.El
.Pp
The option level for the
diff --git a/sys/dev/cxgbe/tom/t4_tom.c b/sys/dev/cxgbe/tom/t4_tom.c
index b253bf3c786e..71770c549218 100644
--- a/sys/dev/cxgbe/tom/t4_tom.c
+++ b/sys/dev/cxgbe/tom/t4_tom.c
@@ -40,6 +40,9 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
+#ifdef KERN_TLS
+#include <sys/ktls.h>
+#endif
#include <sys/lock.h>
#include <sys/limits.h>
#include <sys/module.h>
@@ -814,13 +817,16 @@ t4_tcp_info(struct toedev *tod, struct tcpcb *tp, struct tcp_info *ti)
#ifdef KERN_TLS
static int
t4_alloc_tls_session(struct toedev *tod, struct tcpcb *tp,
- struct ktls_session *tls)
+ struct ktls_session *tls, int direction)
{
struct toepcb *toep = tp->t_toe;
INP_WLOCK_ASSERT(tp->t_inpcb);
MPASS(tls != NULL);
+ if (direction != KTLS_TX)
+ return (EOPNOTSUPP);
+
return (tls_alloc_ktls(toep, tls));
}
#endif
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
index 3d14d67e9f10..6b6bf6df831f 100644
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -702,7 +702,7 @@ ktls_cleanup(struct ktls_session *tls)
#ifdef TCP_OFFLOAD
static int
-ktls_try_toe(struct socket *so, struct ktls_session *tls)
+ktls_try_toe(struct socket *so, struct ktls_session *tls, int direction)
{
struct inpcb *inp;
struct tcpcb *tp;
@@ -728,7 +728,7 @@ ktls_try_toe(struct socket *so, struct ktls_session *tls)
return (EOPNOTSUPP);
}
- error = tcp_offload_alloc_tls_session(tp, tls);
+ error = tcp_offload_alloc_tls_session(tp, tls, direction);
INP_WUNLOCK(inp);
if (error == 0) {
tls->mode = TCP_TLS_MODE_TOE;
@@ -901,6 +901,60 @@ ktls_try_sw(struct socket *so, struct ktls_session *tls)
}
int
+ktls_enable_rx(struct socket *so, struct tls_enable *en)
+{
+ struct ktls_session *tls;
+ int error;
+
+ if (!ktls_offload_enable)
+ return (ENOTSUP);
+
+ counter_u64_add(ktls_offload_enable_calls, 1);
+
+ /*
+ * This should always be true since only the TCP socket option
+ * invokes this function.
+ */
+ if (so->so_proto->pr_protocol != IPPROTO_TCP)
+ return (EINVAL);
+
+ /*
+ * XXX: Don't overwrite existing sessions. We should permit
+ * this to support rekeying in the future.
+ */
+ if (so->so_rcv.sb_tls_info != NULL)
+ return (EALREADY);
+
+ if (en->cipher_algorithm == CRYPTO_AES_CBC && !ktls_cbc_enable)
+ return (ENOTSUP);
+
+ error = ktls_create_session(so, en, &tls);
+ if (error)
+ return (error);
+
+ /* TLS RX offload is only supported on TOE currently. */
+#ifdef TCP_OFFLOAD
+ error = ktls_try_toe(so, tls, KTLS_RX);
+#else
+ error = EOPNOTSUPP;
+#endif
+
+ if (error) {
+ ktls_cleanup(tls);
+ return (error);
+ }
+
+ /* Mark the socket as using TLS offload. */
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_rcv.sb_tls_info = tls;
+ SOCKBUF_UNLOCK(&so->so_rcv);
+
+ counter_u64_add(ktls_offload_total, 1);
+
+ return (0);
+}
+
+int
ktls_enable_tx(struct socket *so, struct tls_enable *en)
{
struct ktls_session *tls;
@@ -938,7 +992,7 @@ ktls_enable_tx(struct socket *so, struct tls_enable *en)
/* Prefer TOE -> ifnet TLS -> software TLS. */
#ifdef TCP_OFFLOAD
- error = ktls_try_toe(so, tls);
+ error = ktls_try_toe(so, tls, KTLS_TX);
if (error)
#endif
error = ktls_try_ifnet(so, tls, false);
@@ -970,6 +1024,25 @@ ktls_enable_tx(struct socket *so, struct tls_enable *en)
}
int
+ktls_get_rx_mode(struct socket *so)
+{
+ struct ktls_session *tls;
+ struct inpcb *inp;
+ int mode;
+
+ inp = so->so_pcb;
+ INP_WLOCK_ASSERT(inp);
+ SOCKBUF_LOCK(&so->so_rcv);
+ tls = so->so_rcv.sb_tls_info;
+ if (tls == NULL)
+ mode = TCP_TLS_MODE_NONE;
+ else
+ mode = tls->mode;
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ return (mode);
+}
+
+int
ktls_get_tx_mode(struct socket *so)
{
struct ktls_session *tls;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index ada337426be8..dd86c9050924 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -2372,12 +2372,34 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
sb = &so->so_rcv;
+#ifdef KERN_TLS
+ /*
+ * KTLS store TLS records as records with a control message to
+ * describe the framing.
+ *
+ * We check once here before acquiring locks to optimize the
+ * common case.
+ */
+ if (sb->sb_tls_info != NULL)
+ return (soreceive_generic(so, psa, uio, mp0, controlp,
+ flagsp));
+#endif
+
/* Prevent other readers from entering the socket. */
error = sblock(sb, SBLOCKWAIT(flags));
if (error)
return (error);
SOCKBUF_LOCK(sb);
+#ifdef KERN_TLS
+ if (sb->sb_tls_info != NULL) {
+ SOCKBUF_UNLOCK(sb);
+ sbunlock(sb);
+ return (soreceive_generic(so, psa, uio, mp0, controlp,
+ flagsp));
+ }
+#endif
+
/* Easy one, no space to copyout anything. */
if (uio->uio_resid == 0) {
error = EINVAL;
diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h
index b5f01b3bcf21..5dc13eca217d 100644
--- a/sys/netinet/tcp.h
+++ b/sys/netinet/tcp.h
@@ -178,6 +178,8 @@ struct tcphdr {
device */
#define TCP_TXTLS_ENABLE 39 /* TLS framing and encryption for transmit */
#define TCP_TXTLS_MODE 40 /* Transmit TLS mode */
+#define TCP_RXTLS_ENABLE 41 /* TLS framing and encryption for receive */
+#define TCP_RXTLS_MODE 42 /* Receive TLS mode */
#define TCP_CONGESTION 64 /* get/set congestion control algorithm */
#define TCP_CCALGOOPT 65 /* get/set cc algorithm specific options */
#define TCP_DELACK 72 /* socket option for delayed ack */
@@ -388,6 +390,7 @@ struct tcp_function_set {
* TCP Control message types
*/
#define TLS_SET_RECORD_TYPE 1
+#define TLS_GET_RECORD 2
/*
* TCP specific variables of interest for tp->t_stats stats(9) accounting.
diff --git a/sys/netinet/tcp_offload.c b/sys/netinet/tcp_offload.c
index 651a2ab6a845..ba190f0303f1 100644
--- a/sys/netinet/tcp_offload.c
+++ b/sys/netinet/tcp_offload.c
@@ -198,14 +198,15 @@ tcp_offload_tcp_info(struct tcpcb *tp, struct tcp_info *ti)
}
int
-tcp_offload_alloc_tls_session(struct tcpcb *tp, struct ktls_session *tls)
+tcp_offload_alloc_tls_session(struct tcpcb *tp, struct ktls_session *tls,
+ int direction)
{
struct toedev *tod = tp->tod;
KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp));
INP_WLOCK_ASSERT(tp->t_inpcb);
- return (tod->tod_alloc_tls_session(tod, tp, tls));
+ return (tod->tod_alloc_tls_session(tod, tp, tls, direction));
}
void
diff --git a/sys/netinet/tcp_offload.h b/sys/netinet/tcp_offload.h
index b89a367cd62e..19c120ccdd7d 100644
--- a/sys/netinet/tcp_offload.h
+++ b/sys/netinet/tcp_offload.h
@@ -46,7 +46,7 @@ int tcp_offload_output(struct tcpcb *);
void tcp_offload_rcvd(struct tcpcb *);
void tcp_offload_ctloutput(struct tcpcb *, int, int);
void tcp_offload_tcp_info(struct tcpcb *, struct tcp_info *);
-int tcp_offload_alloc_tls_session(struct tcpcb *, struct ktls_session *);
+int tcp_offload_alloc_tls_session(struct tcpcb *, struct ktls_session *, int);
void tcp_offload_detach(struct tcpcb *);
#endif
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 670345d62346..d1eb34e49ec4 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -2080,6 +2080,14 @@ unlock_and_done:
error = ktls_set_tx_mode(so, ui);
INP_WUNLOCK(inp);
break;
+ case TCP_RXTLS_ENABLE:
+ INP_WUNLOCK(inp);
+ error = sooptcopyin(sopt, &tls, sizeof(tls),
+ sizeof(tls));
+ if (error)
+ break;
+ error = ktls_enable_rx(so, &tls);
+ break;
#endif
case TCP_KEEPIDLE:
@@ -2418,6 +2426,11 @@ unhold:
INP_WUNLOCK(inp);
error = sooptcopyout(sopt, &optval, sizeof(optval));
break;
+ case TCP_RXTLS_MODE:
+ optval = ktls_get_rx_mode(so);
+ INP_WUNLOCK(inp);
+ error = sooptcopyout(sopt, &optval, sizeof(optval));
+ break;
#endif
default:
INP_WUNLOCK(inp);
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index c3c40a8436a3..5b4e85cca0a3 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -193,7 +193,7 @@ toedev_tcp_info(struct toedev *tod __unused, struct tcpcb *tp __unused,
static int
toedev_alloc_tls_session(struct toedev *tod __unused, struct tcpcb *tp __unused,
- struct ktls_session *tls __unused)
+ struct ktls_session *tls __unused, int direction __unused)
{
return (EINVAL);
diff --git a/sys/netinet/toecore.h b/sys/netinet/toecore.h
index 6df89663fe7d..36493abf7149 100644
--- a/sys/netinet/toecore.h
+++ b/sys/netinet/toecore.h
@@ -113,7 +113,7 @@ struct toedev {
/* Create a TLS session */
int (*tod_alloc_tls_session)(struct toedev *, struct tcpcb *,
- struct ktls_session *);
+ struct ktls_session *, int);
};
typedef void (*tcp_offload_listen_start_fn)(void *, struct tcpcb *);
diff --git a/sys/sys/ktls.h b/sys/sys/ktls.h
index 94d5a976274a..bb7d41a7fa5c 100644
--- a/sys/sys/ktls.h
+++ b/sys/sys/ktls.h
@@ -98,7 +98,7 @@ struct tls_mac_data {
#define TLS_MINOR_VER_TWO 3 /* 3, 3 */
#define TLS_MINOR_VER_THREE 4 /* 3, 4 */
-/* For TCP_TXTLS_ENABLE */
+/* For TCP_TXTLS_ENABLE and TCP_RXTLS_ENABLE. */
#ifdef _KERNEL
struct tls_enable_v0 {
const uint8_t *cipher_key;
@@ -130,6 +130,17 @@ struct tls_enable {
uint8_t rec_seq[8];
};
+/* Structure for TLS_GET_RECORD. */
+struct tls_get_record {
+ /* TLS record header. */
+ uint8_t tls_type;
+ uint8_t tls_vmajor;
+ uint8_t tls_vminor;
+ uint16_t tls_length;
+};
+
+#ifdef _KERNEL
+
struct tls_session_params {
uint8_t *cipher_key;
uint8_t *auth_key;
@@ -148,7 +159,9 @@ struct tls_session_params {
uint8_t flags;
};
-#ifdef _KERNEL
+/* Used in APIs to request RX vs TX sessions. */
+#define KTLS_TX 1
+#define KTLS_RX 2
#define KTLS_API_VERSION 6
@@ -192,6 +205,7 @@ struct ktls_session {
int ktls_crypto_backend_register(struct ktls_crypto_backend *be);
int ktls_crypto_backend_deregister(struct ktls_crypto_backend *be);
+int ktls_enable_rx(struct socket *so, struct tls_enable *en);
int ktls_enable_tx(struct socket *so, struct tls_enable *en);
void ktls_destroy(struct ktls_session *tls);
void ktls_frame(struct mbuf *m, struct ktls_session *tls, int *enqueue_cnt,
@@ -199,6 +213,7 @@ void ktls_frame(struct mbuf *m, struct ktls_session *tls, int *enqueue_cnt,
void ktls_seq(struct sockbuf *sb, struct mbuf *m);
void ktls_enqueue(struct mbuf *m, struct socket *so, int page_count);
void ktls_enqueue_to_free(struct mbuf_ext_pgs *pgs);
+int ktls_get_rx_mode(struct socket *so);
int ktls_set_tx_mode(struct socket *so, int mode);
int ktls_get_tx_mode(struct socket *so);
int ktls_output_eagain(struct inpcb *inp, struct ktls_session *tls);