Date: Mon, 29 Sep 2025 15:22:33 GMT From: Navdeep Parhar <np@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 5b9dc22c9106 - main - cxgbe: Extend NIC TLS to support TLS 1.3. Message-ID: <202509291522.58TFMX69011980@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by np: URL: https://cgit.FreeBSD.org/src/commit/?id=5b9dc22c91068e206fb6cc18ee0cef27067223df commit 5b9dc22c91068e206fb6cc18ee0cef27067223df Author: John Baldwin <jhb@FreeBSD.org> AuthorDate: 2025-09-29 15:04:44 +0000 Commit: Navdeep Parhar <np@FreeBSD.org> CommitDate: 2025-09-29 15:19:12 +0000 cxgbe: Extend NIC TLS to support TLS 1.3. One unusual quirk is that the crypto engine requires the driver to provide an 8 byte placeholder as input before the AAD that is replaced with the middle 8 bytes of the nonce generated from the sequence number and key context. MFC after: 3 days Sponsored by: Chelsio Communications --- sys/dev/cxgbe/crypto/t7_kern_tls.c | 101 ++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/sys/dev/cxgbe/crypto/t7_kern_tls.c b/sys/dev/cxgbe/crypto/t7_kern_tls.c index 402b2cab20ba..5063648b2ba9 100644 --- a/sys/dev/cxgbe/crypto/t7_kern_tls.c +++ b/sys/dev/cxgbe/crypto/t7_kern_tls.c @@ -74,6 +74,7 @@ struct tlspcb { int tx_key_addr; bool inline_key; + bool tls13; unsigned char enc_mode; struct tls_scmd scmd0; @@ -131,14 +132,14 @@ t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, struct vi_info *vi; struct inpcb *inp; struct sge_txq *txq; - int error, explicit_iv_size, keyid, mac_first; + int error, iv_size, keyid, mac_first; tls = params->tls.tls; - /* Only TLS 1.1 and TLS 1.2 are currently supported. */ + /* TLS 1.1 through TLS 1.3 are currently supported. */ if (tls->params.tls_vmajor != TLS_MAJOR_VER_ONE || tls->params.tls_vminor < TLS_MINOR_VER_ONE || - tls->params.tls_vminor > TLS_MINOR_VER_TWO) + tls->params.tls_vminor > TLS_MINOR_VER_THREE) return (EPROTONOSUPPORT); /* Sanity check values in *tls. */ @@ -161,12 +162,10 @@ t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, default: return (EPROTONOSUPPORT); } - explicit_iv_size = AES_BLOCK_LEN; + iv_size = AES_BLOCK_LEN; mac_first = 1; break; case CRYPTO_AES_NIST_GCM_16: - if (tls->params.iv_len != SALT_SIZE) - return (EINVAL); switch (tls->params.cipher_key_len) { case 128 / 8: case 192 / 8: @@ -175,7 +174,13 @@ t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, default: return (EINVAL); } - explicit_iv_size = 8; + + /* + * The IV size for TLS 1.2 is the explicit IV in the + * record header. For TLS 1.3 it is the size of the + * sequence number. + */ + iv_size = 8; mac_first = 0; break; default: @@ -186,6 +191,7 @@ t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, sc = vi->adapter; tlsp = alloc_tlspcb(ifp, vi, M_WAITOK); + tlsp->tls13 = tls->params.tls_vminor == TLS_MINOR_VER_THREE; if (sc->tlst.inline_keys) keyid = -1; @@ -224,14 +230,19 @@ t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, tlsp->tx_key_info_size = t4_tls_key_info_size(tls); /* The SCMD fields used when encrypting a full TLS record. */ - tlsp->scmd0.seqno_numivs = htobe32(V_SCMD_SEQ_NO_CTRL(3) | + if (tlsp->tls13) + tlsp->scmd0.seqno_numivs = V_SCMD_SEQ_NO_CTRL(0); + else + tlsp->scmd0.seqno_numivs = V_SCMD_SEQ_NO_CTRL(3); + tlsp->scmd0.seqno_numivs |= V_SCMD_PROTO_VERSION(t4_tls_proto_ver(tls)) | V_SCMD_ENC_DEC_CTRL(SCMD_ENCDECCTRL_ENCRYPT) | V_SCMD_CIPH_AUTH_SEQ_CTRL((mac_first == 0)) | V_SCMD_CIPH_MODE(tlsp->enc_mode) | V_SCMD_AUTH_MODE(t4_tls_auth_mode(tls)) | V_SCMD_HMAC_CTRL(t4_tls_hmac_ctrl(tls)) | - V_SCMD_IV_SIZE(explicit_iv_size / 2) | V_SCMD_NUM_IVS(1)); + V_SCMD_IV_SIZE(iv_size / 2) | V_SCMD_NUM_IVS(1); + tlsp->scmd0.seqno_numivs = htobe32(tlsp->scmd0.seqno_numivs); tlsp->scmd0.ivgen_hdrlen = V_SCMD_IV_GEN_CTRL(0) | V_SCMD_TLS_FRAG_ENABLE(0); @@ -390,20 +401,29 @@ ktls_is_short_record(struct tlspcb *tlsp, struct mbuf *m_tls, u_int *leading_waste, u_int *trailing_waste) { const struct tls_record_layer *hdr; - u_int new_tlen, rlen; + u_int new_tlen, trailer_len, rlen; MPASS(tlen > m_tls->m_epg_hdrlen); hdr = (void *)m_tls->m_epg_hdr; rlen = TLS_HEADER_LENGTH + ntohs(hdr->tls_length); + /* + * For TLS 1.3 treat the inner record type stored as the first + * byte of the trailer as part of the payload rather than part + * of the trailer. + */ + trailer_len = m_tls->m_epg_trllen; + if (tlsp->tls13) + trailer_len--; + /* * Default to sending the full record as input to the crypto * engine and relying on SplitMode to drop any waste. */ *header_len = m_tls->m_epg_hdrlen; *offset = 0; - *plen = rlen - (m_tls->m_epg_hdrlen + m_tls->m_epg_trllen); + *plen = rlen - (m_tls->m_epg_hdrlen + trailer_len); *leading_waste = mtod(m_tls, vm_offset_t); *trailing_waste = rlen - tlen; if (!tlsp->sc->tlst.short_records) @@ -420,7 +440,7 @@ ktls_is_short_record(struct tlspcb *tlsp, struct mbuf *m_tls, */ new_tlen = TLS_HEADER_LENGTH + roundup2(tlen - TLS_HEADER_LENGTH, AES_BLOCK_LEN); - if (rlen - new_tlen < m_tls->m_epg_trllen) + if (rlen - new_tlen < trailer_len) return (false); *trailing_waste = new_tlen - tlen; @@ -431,7 +451,7 @@ ktls_is_short_record(struct tlspcb *tlsp, struct mbuf *m_tls, * the end overlaps with the trailer. Otherwise, we * can use AES-CTR to encrypt a partial PDU. */ - if (rlen - tlen < m_tls->m_epg_trllen) + if (rlen - tlen < trailer_len) return (false); /* @@ -512,11 +532,14 @@ ktls_wr_len(struct tlspcb *tlsp, struct mbuf *m, struct mbuf *m_tls, /* * Headers (including the TLS header) are always sent as * immediate data. Short records include a raw AES IV as - * immediate data. + * immediate data. TLS 1.3 non-short records include a + * placeholder for the sequence number as immediate data. */ imm_len = m->m_len + header_len; if (short_record) imm_len += AES_BLOCK_LEN; + else if (tlsp->tls13) + imm_len += sizeof(uint64_t); wr_len += roundup2(imm_len, 16); /* TLS record payload via DSGL. */ @@ -1044,6 +1067,8 @@ ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq, imm_len = m->m_len + header_len; if (short_record) imm_len += AES_BLOCK_LEN; + else if (tlsp->tls13) + imm_len += sizeof(uint64_t); wr_len += roundup2(imm_len, 16); wr_len += ktls_sgl_size(nsegs); @@ -1141,15 +1166,25 @@ ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq, txq->kern_tls_short++; } else { /* - * AAD is TLS header. IV is after AAD. The cipher region - * starts after the IV. See comments in ccr_authenc() and - * ccr_gmac() in t4_crypto.c regarding cipher and auth - * start/stop values. + * AAD is TLS header. IV is after AAD for TLS < 1.3. + * For TLS 1.3, a placeholder for the TLS sequence + * number is provided as an IV before the AAD. The + * cipher region starts after the AAD and IV. See + * comments in ccr_authenc() and ccr_gmac() in + * t4_crypto.c regarding cipher and auth start/stop + * values. */ - aad_start = 1; - aad_stop = TLS_HEADER_LENGTH; - iv_offset = TLS_HEADER_LENGTH + 1; - cipher_start = m_tls->m_epg_hdrlen + 1; + if (tlsp->tls13) { + iv_offset = 1; + aad_start = 1 + sizeof(uint64_t); + aad_stop = sizeof(uint64_t) + TLS_HEADER_LENGTH; + cipher_start = aad_stop + 1; + } else { + aad_start = 1; + aad_stop = TLS_HEADER_LENGTH; + iv_offset = TLS_HEADER_LENGTH + 1; + cipher_start = m_tls->m_epg_hdrlen + 1; + } if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM) { cipher_stop = 0; auth_start = cipher_start; @@ -1162,7 +1197,8 @@ ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq, auth_insert = 0; } - sec_pdu->pldlen = htobe32(m_tls->m_epg_hdrlen + plen); + sec_pdu->pldlen = htobe32((tlsp->tls13 ? sizeof(uint64_t) : 0) + + m_tls->m_epg_hdrlen + plen); /* These two flits are actually a CPL_TLS_TX_SCMD_FMT. */ sec_pdu->seqno_numivs = tlsp->scmd0.seqno_numivs; @@ -1256,6 +1292,15 @@ ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq, newtcp->th_flags = tcp->th_flags & ~(TH_PUSH | TH_FIN); out += m->m_len; + /* + * Insert placeholder for sequence number as IV for TLS 1.3 + * non-short records. + */ + if (tlsp->tls13 && !short_record) { + memset(out, 0, sizeof(uint64_t)); + out += sizeof(uint64_t); + } + /* Populate the TLS header */ memcpy(out, m_tls->m_epg_hdr, header_len); out += header_len; @@ -1265,7 +1310,15 @@ ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq, iv = out; if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM) { memcpy(iv, tlsp->keyctx.u.txhdr.txsalt, SALT_SIZE); - memcpy(iv + 4, hdr + 1, 8); + if (tlsp->tls13) { + uint64_t value; + + value = be64dec(tlsp->keyctx.u.txhdr.txsalt + + 4); + value ^= m_tls->m_epg_seqno; + be64enc(iv + 4, value); + } else + memcpy(iv + 4, hdr + 1, 8); be32enc(iv + 12, 2 + offset / AES_BLOCK_LEN); } else memcpy(iv, hdr + 1, AES_BLOCK_LEN);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509291522.58TFMX69011980>