Author: gallatin
Date: Fri Sep 27 19:17:40 2019
New Revision: 352814
URL: https://svnweb.freebsd.org/changeset/base/352814

Log:
  kTLS support for TLS 1.3
  
  TLS 1.3 requires a few changes because 1.3 pretends to be 1.2
  with a record type of application data. The "real" record type is
  then included at the end of the user-supplied plaintext
  data. This required adding a field to the mbuf_ext_pgs struct to
  save the record type, and passing the real record type to the
  sw_encrypt() ktls backend functions.
  
  Reviewed by:  jhb, hselasky
  Sponsored by: Netflix
  Differential Revision:        D21801

Modified:
  head/sys/kern/uipc_ktls.c
  head/sys/net/iflib.c
  head/sys/opencrypto/ktls_ocf.c
  head/sys/sys/ktls.h
  head/sys/sys/mbuf.h

Modified: head/sys/kern/uipc_ktls.c
==============================================================================
--- head/sys/kern/uipc_ktls.c   Fri Sep 27 19:14:03 2019        (r352813)
+++ head/sys/kern/uipc_ktls.c   Fri Sep 27 19:17:40 2019        (r352814)
@@ -389,14 +389,14 @@ ktls_create_session(struct socket *so, struct tls_enab
        if (en->tls_vmajor != TLS_MAJOR_VER_ONE)
                return (EINVAL);
        if (en->tls_vminor < TLS_MINOR_VER_ZERO ||
-           en->tls_vminor > TLS_MINOR_VER_TWO)
+           en->tls_vminor > TLS_MINOR_VER_THREE)
                return (EINVAL);
 
        if (en->auth_key_len < 0 || en->auth_key_len > TLS_MAX_PARAM_SIZE)
                return (EINVAL);
        if (en->cipher_key_len < 0 || en->cipher_key_len > TLS_MAX_PARAM_SIZE)
                return (EINVAL);
-       if (en->iv_len < 0 || en->iv_len > TLS_MAX_PARAM_SIZE)
+       if (en->iv_len < 0 || en->iv_len > sizeof(tls->params.iv))
                return (EINVAL);
 
        /* All supported algorithms require a cipher key. */
@@ -425,7 +425,10 @@ ktls_create_session(struct socket *so, struct tls_enab
                }
                if (en->auth_key_len != 0)
                        return (EINVAL);
-               if (en->iv_len != TLS_AEAD_GCM_LEN)
+               if ((en->tls_vminor == TLS_MINOR_VER_TWO &&
+                       en->iv_len != TLS_AEAD_GCM_LEN) ||
+                   (en->tls_vminor == TLS_MINOR_VER_THREE &&
+                       en->iv_len != TLS_1_3_GCM_IV_LEN))
                        return (EINVAL);
                break;
        case CRYPTO_AES_CBC:
@@ -477,8 +480,22 @@ ktls_create_session(struct socket *so, struct tls_enab
        tls->params.tls_hlen = sizeof(struct tls_record_layer);
        switch (en->cipher_algorithm) {
        case CRYPTO_AES_NIST_GCM_16:
-               tls->params.tls_hlen += 8;
+               /*
+                * TLS 1.2 uses a 4 byte implicit IV with an explicit 8 byte
+                * nonce.  TLS 1.3 uses a 12 byte implicit IV.
+                */
+               if (en->tls_vminor < TLS_MINOR_VER_THREE)
+                       tls->params.tls_hlen += sizeof(uint64_t);
                tls->params.tls_tlen = AES_GMAC_HASH_LEN;
+
+               /*
+                * TLS 1.3 includes optional padding which we
+                * do not support, and also puts the "real" record
+                * type at the end of the encrypted data.
+                */
+               if (en->tls_vminor == TLS_MINOR_VER_THREE)
+                       tls->params.tls_tlen += sizeof(uint8_t);
+
                tls->params.tls_bs = 1;
                break;
        case CRYPTO_AES_CBC:
@@ -539,7 +556,6 @@ ktls_create_session(struct socket *so, struct tls_enab
         * of the IV are generated in ktls_frame() and ktls_seq().
         */
        if (en->iv_len != 0) {
-               MPASS(en->iv_len <= sizeof(tls->params.iv));
                tls->params.iv_len = en->iv_len;
                error = copyin(en->iv, tls->params.iv, en->iv_len);
                if (error)
@@ -1188,8 +1204,21 @@ ktls_frame(struct mbuf *top, struct ktls_session *tls,
                /* Populate the TLS header. */
                tlshdr = (void *)pgs->hdr;
                tlshdr->tls_vmajor = tls->params.tls_vmajor;
-               tlshdr->tls_vminor = tls->params.tls_vminor;
-               tlshdr->tls_type = record_type;
+
+               /*
+                * TLS 1.3 masquarades as TLS 1.2 with a record type
+                * of TLS_RLTYPE_APP.
+                */
+               if (tls->params.tls_vminor == TLS_MINOR_VER_THREE &&
+                   tls->params.tls_vmajor == TLS_MAJOR_VER_ONE) {
+                       tlshdr->tls_vminor = TLS_MINOR_VER_TWO;
+                       tlshdr->tls_type = TLS_RLTYPE_APP;
+                       /* save the real record type for later */
+                       pgs->record_type = record_type;
+               } else {
+                       tlshdr->tls_vminor = tls->params.tls_vminor;
+                       tlshdr->tls_type = record_type;
+               }
                tlshdr->tls_length = htons(m->m_len - sizeof(*tlshdr));
 
                /*
@@ -1365,7 +1394,8 @@ retry_page:
 
                error = (*tls->sw_encrypt)(tls,
                    (const struct tls_record_layer *)pgs->hdr,
-                   pgs->trail, src_iov, dst_iov, i, pgs->seqno);
+                   pgs->trail, src_iov, dst_iov, i, pgs->seqno,
+                   pgs->record_type);
                if (error) {
                        counter_u64_add(ktls_offload_failed_crypto, 1);
                        break;

Modified: head/sys/net/iflib.c
==============================================================================
--- head/sys/net/iflib.c        Fri Sep 27 19:14:03 2019        (r352813)
+++ head/sys/net/iflib.c        Fri Sep 27 19:17:40 2019        (r352814)
@@ -4076,7 +4076,7 @@ iflib_if_qflush(if_t ifp)
 #define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
                     IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
                     IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
-                    IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM)
+                    IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM | IFCAP_NOMAP)
 
 static int
 iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
@@ -4201,7 +4201,7 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
 
                oldmask = if_getcapenable(ifp);
                mask = ifr->ifr_reqcap ^ oldmask;
-               mask &= ctx->ifc_softc_ctx.isc_capabilities;
+               mask &= ctx->ifc_softc_ctx.isc_capabilities | IFCAP_NOMAP;
                setmask = 0;
 #ifdef TCP_OFFLOAD
                setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6);
@@ -4596,8 +4596,10 @@ iflib_device_register(device_t dev, void *sc, if_share
                MPASS(scctx->isc_tx_csum_flags);
 #endif
 
-       if_setcapabilities(ifp, scctx->isc_capabilities | IFCAP_HWSTATS);
-       if_setcapenable(ifp, scctx->isc_capenable | IFCAP_HWSTATS);
+       if_setcapabilities(ifp,
+           scctx->isc_capabilities | IFCAP_HWSTATS | IFCAP_NOMAP);
+       if_setcapenable(ifp,
+           scctx->isc_capenable | IFCAP_HWSTATS | IFCAP_NOMAP);
 
        if (scctx->isc_ntxqsets == 0 || (scctx->isc_ntxqsets_max && 
scctx->isc_ntxqsets_max < scctx->isc_ntxqsets))
                scctx->isc_ntxqsets = scctx->isc_ntxqsets_max;

Modified: head/sys/opencrypto/ktls_ocf.c
==============================================================================
--- head/sys/opencrypto/ktls_ocf.c      Fri Sep 27 19:14:03 2019        
(r352813)
+++ head/sys/opencrypto/ktls_ocf.c      Fri Sep 27 19:17:40 2019        
(r352814)
@@ -86,7 +86,7 @@ ktls_ocf_callback(struct cryptop *crp)
 static int
 ktls_ocf_encrypt(struct ktls_session *tls, const struct tls_record_layer *hdr,
     uint8_t *trailer, struct iovec *iniov, struct iovec *outiov, int iovcnt,
-    uint64_t seqno)
+    uint64_t seqno, uint8_t record_type __unused)
 {
        struct uio uio;
        struct tls_aead_data ad;

Modified: head/sys/sys/ktls.h
==============================================================================
--- head/sys/sys/ktls.h Fri Sep 27 19:14:03 2019        (r352813)
+++ head/sys/sys/ktls.h Fri Sep 27 19:17:40 2019        (r352814)
@@ -43,6 +43,7 @@ struct tls_record_layer {
 #define        TLS_MAX_MSG_SIZE_V10_2  16384
 #define        TLS_MAX_PARAM_SIZE      1024    /* Max key/mac/iv in sockopt */
 #define        TLS_AEAD_GCM_LEN        4
+#define        TLS_1_3_GCM_IV_LEN      12
 #define        TLS_CBC_IMPLICIT_IV_LEN 16
 
 /* Type values for the record layer */
@@ -85,6 +86,7 @@ struct tls_mac_data {
 #define        TLS_MINOR_VER_ZERO      1       /* 3, 1 */
 #define        TLS_MINOR_VER_ONE       2       /* 3, 2 */
 #define        TLS_MINOR_VER_TWO       3       /* 3, 3 */
+#define        TLS_MINOR_VER_THREE     4       /* 3, 4 */
 
 /* For TCP_TXTLS_ENABLE */
 struct tls_enable {
@@ -121,7 +123,7 @@ struct tls_session_params {
 
 #ifdef _KERNEL
 
-#define        KTLS_API_VERSION 5
+#define        KTLS_API_VERSION 6
 
 struct iovec;
 struct ktls_session;
@@ -144,7 +146,7 @@ struct ktls_session {
        int     (*sw_encrypt)(struct ktls_session *tls,
            const struct tls_record_layer *hdr, uint8_t *trailer,
            struct iovec *src, struct iovec *dst, int iovcnt,
-           uint64_t seqno);
+           uint64_t seqno, uint8_t record_type);
        union {
                void *cipher;
                struct m_snd_tag *snd_tag;

Modified: head/sys/sys/mbuf.h
==============================================================================
--- head/sys/sys/mbuf.h Fri Sep 27 19:14:03 2019        (r352813)
+++ head/sys/sys/mbuf.h Fri Sep 27 19:17:40 2019        (r352814)
@@ -359,6 +359,7 @@ struct mbuf_ext_pgs {
        union {
                char    trail[MBUF_PEXT_TRAIL_LEN]; /* TLS trailer */
                struct {
+                       uint8_t record_type;    /* Must be first */
                        struct socket *so;
                        struct mbuf *mbuf;
                        uint64_t seqno;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to