aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/uipc_ktls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/uipc_ktls.c')
-rw-r--r--sys/kern/uipc_ktls.c72
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 -