diff options
Diffstat (limited to 'sys/kern/uipc_ktls.c')
-rw-r--r-- | sys/kern/uipc_ktls.c | 72 |
1 files changed, 65 insertions, 7 deletions
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c index 9762e35a9a20..5b37daf7d73b 100644 --- a/sys/kern/uipc_ktls.c +++ b/sys/kern/uipc_ktls.c @@ -1185,11 +1185,6 @@ ktls_enable_rx(struct socket *so, struct tls_enable *en) if (en->cipher_algorithm == CRYPTO_AES_CBC && !ktls_cbc_enable) return (ENOTSUP); - /* TLS 1.3 is not yet supported. */ - if (en->tls_vmajor == TLS_MAJOR_VER_ONE && - en->tls_vminor == TLS_MINOR_VER_THREE) - return (ENOTSUP); - error = ktls_create_session(so, en, &tls); if (error) return (error); @@ -1903,6 +1898,53 @@ out: return (top); } +/* + * Determine the length of the trailing zero padding and find the real + * record type in the byte before the padding. + * + * Walking the mbuf chain backwards is clumsy, so another option would + * be to scan forwards remembering the last non-zero byte before the + * trailer. However, it would be expensive to scan the entire record. + * Instead, find the last non-zero byte of each mbuf in the chain + * keeping track of the relative offset of that nonzero byte. + * + * trail_len is the size of the MAC/tag on input and is set to the + * size of the full trailer including padding and the record type on + * return. + */ +static int +tls13_find_record_type(struct ktls_session *tls, struct mbuf *m, int tls_len, + int *trailer_len, uint8_t *record_typep) +{ + char *cp; + u_int digest_start, last_offset, m_len, offset; + uint8_t record_type; + + digest_start = tls_len - *trailer_len; + last_offset = 0; + offset = 0; + for (; m != NULL && offset < digest_start; + offset += m->m_len, m = m->m_next) { + /* Don't look for padding in the tag. */ + m_len = min(digest_start - offset, m->m_len); + cp = mtod(m, char *); + + /* Find last non-zero byte in this mbuf. */ + while (m_len > 0 && cp[m_len - 1] == 0) + m_len--; + if (m_len > 0) { + record_type = cp[m_len - 1]; + last_offset = offset + m_len; + } + } + if (last_offset < tls->params.tls_hlen) + return (EBADMSG); + + *record_typep = record_type; + *trailer_len = tls_len - last_offset + 1; + return (0); +} + static void ktls_decrypt(struct socket *so) { @@ -1914,6 +1956,8 @@ ktls_decrypt(struct socket *so) struct mbuf *control, *data, *m; uint64_t seqno; int error, remain, tls_len, trail_len; + bool tls13; + uint8_t vminor, record_type; hdr = (struct tls_record_layer *)tls_header; sb = &so->so_rcv; @@ -1924,6 +1968,11 @@ ktls_decrypt(struct socket *so) tls = sb->sb_tls_info; MPASS(tls != NULL); + tls13 = (tls->params.tls_vminor == TLS_MINOR_VER_THREE); + if (tls13) + vminor = TLS_MINOR_VER_TWO; + else + vminor = tls->params.tls_vminor; for (;;) { /* Is there enough queued for a TLS header? */ if (sb->sb_tlscc < tls->params.tls_hlen) @@ -1933,7 +1982,9 @@ ktls_decrypt(struct socket *so) tls_len = sizeof(*hdr) + ntohs(hdr->tls_length); if (hdr->tls_vmajor != tls->params.tls_vmajor || - hdr->tls_vminor != tls->params.tls_vminor) + hdr->tls_vminor != vminor) + error = EINVAL; + else if (tls13 && hdr->tls_type != TLS_RLTYPE_APP) error = EINVAL; else if (tls_len < tls->params.tls_hlen || tls_len > tls->params.tls_hlen + TLS_MAX_MSG_SIZE_V10_2 + @@ -1976,6 +2027,13 @@ ktls_decrypt(struct socket *so) SOCKBUF_UNLOCK(sb); error = tls->sw_decrypt(tls, hdr, data, seqno, &trail_len); + if (error == 0) { + if (tls13) + error = tls13_find_record_type(tls, data, + tls_len, &trail_len, &record_type); + else + record_type = hdr->tls_type; + } if (error) { counter_u64_add(ktls_offload_failed_crypto, 1); @@ -2008,7 +2066,7 @@ ktls_decrypt(struct socket *so) } /* Allocate the control mbuf. */ - tgr.tls_type = hdr->tls_type; + tgr.tls_type = record_type; tgr.tls_vmajor = hdr->tls_vmajor; tgr.tls_vminor = hdr->tls_vminor; tgr.tls_length = htobe16(tls_len - tls->params.tls_hlen - |