ktls: Add software support for AES-CBC decryption for TLS 1.1+.
This is mainly intended to provide a fallback for TOE TLS which may need to use software decryption for an initial record at the start of a connection. Reviewed by: markj Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D37370
This commit is contained in:
parent
b97ee269ea
commit
9a673b7158
@ -149,7 +149,7 @@ SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, enable, CTLFLAG_RWTUN,
|
||||
static bool ktls_cbc_enable = true;
|
||||
SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, cbc_enable, CTLFLAG_RWTUN,
|
||||
&ktls_cbc_enable, 1,
|
||||
"Enable Support of AES-CBC crypto for kernel TLS");
|
||||
"Enable support of AES-CBC crypto for kernel TLS");
|
||||
|
||||
static bool ktls_sw_buffer_cache = true;
|
||||
SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, sw_buffer_cache, CTLFLAG_RDTUN,
|
||||
@ -2444,8 +2444,10 @@ ktls_decrypt(struct socket *so)
|
||||
sb->sb_ccc -= tls_len;
|
||||
sb->sb_tlsdcc = 0;
|
||||
|
||||
if (error != EMSGSIZE)
|
||||
error = EBADMSG;
|
||||
CURVNET_SET(so->so_vnet);
|
||||
so->so_error = EBADMSG;
|
||||
so->so_error = error;
|
||||
sorwakeup_locked(so);
|
||||
CURVNET_RESTORE();
|
||||
|
||||
|
@ -101,6 +101,11 @@ SYSCTL_COUNTER_U64(_kern_ipc_tls_stats_ocf, OID_AUTO, tls10_cbc_encrypts,
|
||||
CTLFLAG_RD, &ocf_tls10_cbc_encrypts,
|
||||
"Total number of OCF TLS 1.0 CBC encryption operations");
|
||||
|
||||
static COUNTER_U64_DEFINE_EARLY(ocf_tls11_cbc_decrypts);
|
||||
SYSCTL_COUNTER_U64(_kern_ipc_tls_stats_ocf, OID_AUTO, tls11_cbc_decrypts,
|
||||
CTLFLAG_RD, &ocf_tls11_cbc_decrypts,
|
||||
"Total number of OCF TLS 1.1/1.2 CBC decryption operations");
|
||||
|
||||
static COUNTER_U64_DEFINE_EARLY(ocf_tls11_cbc_encrypts);
|
||||
SYSCTL_COUNTER_U64(_kern_ipc_tls_stats_ocf, OID_AUTO, tls11_cbc_encrypts,
|
||||
CTLFLAG_RD, &ocf_tls11_cbc_encrypts,
|
||||
@ -416,8 +421,129 @@ ktls_ocf_tls_cbc_encrypt(struct ktls_ocf_encrypt_state *state,
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
check_padding(void *arg, void *data, u_int len)
|
||||
{
|
||||
uint8_t pad = *(uint8_t *)arg;
|
||||
const char *cp = data;
|
||||
|
||||
while (len > 0) {
|
||||
if (*cp != pad)
|
||||
return (EBADMSG);
|
||||
cp++;
|
||||
len--;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ktls_ocf_tls_cbc_decrypt(struct ktls_session *tls,
|
||||
const struct tls_record_layer *hdr, struct mbuf *m, uint64_t seqno,
|
||||
int *trailer_len)
|
||||
{
|
||||
struct tls_mac_data ad;
|
||||
struct cryptop crp;
|
||||
struct uio uio;
|
||||
struct ktls_ocf_session *os;
|
||||
struct iovec *iov;
|
||||
struct mbuf *n;
|
||||
u_int iovcnt;
|
||||
int i, error, skip;
|
||||
uint16_t tls_len, tls_comp_len;
|
||||
uint8_t pad;
|
||||
|
||||
os = tls->ocf_session;
|
||||
|
||||
/*
|
||||
* Ensure record is a multiple of the cipher block size and
|
||||
* contains at least an explicit IV, MAC, and at least one
|
||||
* padding byte.
|
||||
*/
|
||||
tls_len = ntohs(hdr->tls_length);
|
||||
if (tls_len % AES_BLOCK_LEN != 0 ||
|
||||
tls_len < AES_BLOCK_LEN + roundup2(os->mac_len + 1, AES_BLOCK_LEN))
|
||||
return (EMSGSIZE);
|
||||
|
||||
/* First, decrypt the record. */
|
||||
crypto_initreq(&crp, os->sid);
|
||||
crp.crp_iv_start = sizeof(*hdr);
|
||||
crp.crp_payload_start = tls->params.tls_hlen;
|
||||
crp.crp_payload_length = tls_len - AES_BLOCK_LEN;
|
||||
crypto_use_mbuf(&crp, m);
|
||||
crp.crp_op = CRYPTO_OP_DECRYPT;
|
||||
crp.crp_flags = CRYPTO_F_CBIMM;
|
||||
|
||||
counter_u64_add(ocf_tls11_cbc_decrypts, 1);
|
||||
|
||||
error = ktls_ocf_dispatch(os, &crp);
|
||||
crypto_destroyreq(&crp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Verify the padding. */
|
||||
m_copydata(m, sizeof(*hdr) + tls_len - 1, 1, &pad);
|
||||
*trailer_len = os->mac_len + pad + 1;
|
||||
if (AES_BLOCK_LEN + *trailer_len > tls_len)
|
||||
return (EBADMSG);
|
||||
error = m_apply(m, sizeof(*hdr) + tls_len - (pad + 1), pad + 1,
|
||||
check_padding, &pad);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Verify the MAC. */
|
||||
tls_comp_len = tls_len - (AES_BLOCK_LEN + *trailer_len);
|
||||
memset(&uio, 0, sizeof(uio));
|
||||
|
||||
/*
|
||||
* Allocate and populate the iov. Have to skip over the TLS
|
||||
* header in 'm' as it is not part of the MAC input.
|
||||
*/
|
||||
iovcnt = 1;
|
||||
for (n = m; n != NULL; n = n->m_next)
|
||||
iovcnt++;
|
||||
iov = malloc(iovcnt * sizeof(*iov), M_KTLS_OCF, M_WAITOK);
|
||||
iov[0].iov_base = &ad;
|
||||
iov[0].iov_len = sizeof(ad);
|
||||
skip = sizeof(*hdr) + AES_BLOCK_LEN;
|
||||
for (i = 1, n = m; n != NULL; i++, n = n->m_next) {
|
||||
if (n->m_len < skip) {
|
||||
skip -= n->m_len;
|
||||
continue;
|
||||
}
|
||||
iov[i].iov_base = mtod(n, char *) + skip;
|
||||
iov[i].iov_len = n->m_len - skip;
|
||||
skip = 0;
|
||||
}
|
||||
uio.uio_iov = iov;
|
||||
uio.uio_iovcnt = i;
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_td = curthread;
|
||||
uio.uio_resid = sizeof(ad) + tls_len - AES_BLOCK_LEN;
|
||||
|
||||
/* Initialize the AAD. */
|
||||
ad.seq = htobe64(seqno);
|
||||
ad.type = hdr->tls_type;
|
||||
ad.tls_vmajor = hdr->tls_vmajor;
|
||||
ad.tls_vminor = hdr->tls_vminor;
|
||||
ad.tls_length = htons(tls_comp_len);
|
||||
|
||||
crypto_initreq(&crp, os->mac_sid);
|
||||
crp.crp_payload_start = 0;
|
||||
crp.crp_payload_length = sizeof(ad) + tls_comp_len;
|
||||
crp.crp_digest_start = crp.crp_payload_length;
|
||||
crp.crp_op = CRYPTO_OP_VERIFY_DIGEST;
|
||||
crp.crp_flags = CRYPTO_F_CBIMM;
|
||||
crypto_use_uio(&crp, &uio);
|
||||
error = ktls_ocf_dispatch(os, &crp);
|
||||
|
||||
crypto_destroyreq(&crp);
|
||||
free(iov, M_KTLS_OCF);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static const struct ktls_ocf_sw ktls_ocf_tls_cbc_sw = {
|
||||
.encrypt = ktls_ocf_tls_cbc_encrypt
|
||||
.encrypt = ktls_ocf_tls_cbc_encrypt,
|
||||
.decrypt = ktls_ocf_tls_cbc_decrypt
|
||||
};
|
||||
|
||||
static int
|
||||
@ -912,8 +1038,9 @@ ktls_ocf_try(struct socket *so, struct ktls_session *tls, int direction)
|
||||
tls->params.tls_vminor > TLS_MINOR_VER_TWO)
|
||||
return (EPROTONOSUPPORT);
|
||||
|
||||
/* AES-CBC is not supported for receive. */
|
||||
if (direction == KTLS_RX)
|
||||
/* AES-CBC is not supported for receive for TLS 1.0. */
|
||||
if (direction == KTLS_RX &&
|
||||
tls->params.tls_vminor == TLS_MINOR_VER_ZERO)
|
||||
return (EPROTONOSUPPORT);
|
||||
|
||||
csp.csp_flags |= CSP_F_SEPARATE_OUTPUT;
|
||||
|
Loading…
Reference in New Issue
Block a user