Path: blob/main/crypto/openssl/include/internal/ktls.h
34879 views
/*1* Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#if defined(OPENSSL_SYS_LINUX)10# ifndef OPENSSL_NO_KTLS11# include <linux/version.h>12# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)13# define OPENSSL_NO_KTLS14# ifndef PEDANTIC15# warning "KTLS requires Kernel Headers >= 4.13.0"16# warning "Skipping Compilation of KTLS"17# endif18# endif19# endif20#endif2122#ifndef HEADER_INTERNAL_KTLS23# define HEADER_INTERNAL_KTLS24# pragma once2526# ifndef OPENSSL_NO_KTLS2728# if defined(__FreeBSD__)29# include <sys/types.h>30# include <sys/socket.h>31# include <sys/ktls.h>32# include <netinet/in.h>33# include <netinet/tcp.h>34# include <openssl/ssl3.h>3536# ifndef TCP_RXTLS_ENABLE37# define OPENSSL_NO_KTLS_RX38# endif39# define OPENSSL_KTLS_AES_GCM_12840# define OPENSSL_KTLS_AES_GCM_25641# define OPENSSL_KTLS_TLS1342# ifdef TLS_CHACHA20_IV_LEN43# ifndef OPENSSL_NO_CHACHA44# define OPENSSL_KTLS_CHACHA20_POLY130545# endif46# endif4748typedef struct tls_enable ktls_crypto_info_t;4950/*51* FreeBSD does not require any additional steps to enable KTLS before52* setting keys.53*/54static ossl_inline int ktls_enable(int fd)55{56return 1;57}5859/*60* The TCP_TXTLS_ENABLE socket option marks the outgoing socket buffer61* as using TLS. If successful, then data sent using this socket will62* be encrypted and encapsulated in TLS records using the tls_en63* provided here.64*65* The TCP_RXTLS_ENABLE socket option marks the incoming socket buffer66* as using TLS. If successful, then data received for this socket will67* be authenticated and decrypted using the tls_en provided here.68*/69static ossl_inline int ktls_start(int fd, ktls_crypto_info_t *tls_en, int is_tx)70{71if (is_tx)72return setsockopt(fd, IPPROTO_TCP, TCP_TXTLS_ENABLE,73tls_en, sizeof(*tls_en)) ? 0 : 1;74# ifndef OPENSSL_NO_KTLS_RX75return setsockopt(fd, IPPROTO_TCP, TCP_RXTLS_ENABLE, tls_en,76sizeof(*tls_en)) ? 0 : 1;77# else78return 0;79# endif80}8182/* Not supported on FreeBSD */83static ossl_inline int ktls_enable_tx_zerocopy_sendfile(int fd)84{85return 0;86}8788/*89* Send a TLS record using the tls_en provided in ktls_start and use90* record_type instead of the default SSL3_RT_APPLICATION_DATA.91* When the socket is non-blocking, then this call either returns EAGAIN or92* the entire record is pushed to TCP. It is impossible to send a partial93* record using this control message.94*/95static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,96const void *data, size_t length)97{98struct msghdr msg = { 0 };99int cmsg_len = sizeof(record_type);100struct cmsghdr *cmsg;101char buf[CMSG_SPACE(cmsg_len)];102struct iovec msg_iov; /* Vector of data to send/receive into */103104msg.msg_control = buf;105msg.msg_controllen = sizeof(buf);106cmsg = CMSG_FIRSTHDR(&msg);107cmsg->cmsg_level = IPPROTO_TCP;108cmsg->cmsg_type = TLS_SET_RECORD_TYPE;109cmsg->cmsg_len = CMSG_LEN(cmsg_len);110*((unsigned char *)CMSG_DATA(cmsg)) = record_type;111msg.msg_controllen = cmsg->cmsg_len;112113msg_iov.iov_base = (void *)data;114msg_iov.iov_len = length;115msg.msg_iov = &msg_iov;116msg.msg_iovlen = 1;117118return sendmsg(fd, &msg, 0);119}120121# ifdef OPENSSL_NO_KTLS_RX122123static ossl_inline int ktls_read_record(int fd, void *data, size_t length)124{125return -1;126}127128# else /* !defined(OPENSSL_NO_KTLS_RX) */129130/*131* Receive a TLS record using the tls_en provided in ktls_start. The132* kernel strips any explicit IV and authentication tag, but provides133* the TLS record header via a control message. If there is an error134* with the TLS record such as an invalid header, invalid padding, or135* authentication failure recvmsg() will fail with an error.136*/137static ossl_inline int ktls_read_record(int fd, void *data, size_t length)138{139struct msghdr msg = { 0 };140int cmsg_len = sizeof(struct tls_get_record);141struct tls_get_record *tgr;142struct cmsghdr *cmsg;143char buf[CMSG_SPACE(cmsg_len)];144struct iovec msg_iov; /* Vector of data to send/receive into */145int ret;146unsigned char *p = data;147const size_t prepend_length = SSL3_RT_HEADER_LENGTH;148149if (length <= prepend_length) {150errno = EINVAL;151return -1;152}153154msg.msg_control = buf;155msg.msg_controllen = sizeof(buf);156157msg_iov.iov_base = p + prepend_length;158msg_iov.iov_len = length - prepend_length;159msg.msg_iov = &msg_iov;160msg.msg_iovlen = 1;161162ret = recvmsg(fd, &msg, 0);163if (ret <= 0)164return ret;165166if ((msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) != MSG_EOR) {167errno = EMSGSIZE;168return -1;169}170171if (msg.msg_controllen == 0) {172errno = EBADMSG;173return -1;174}175176cmsg = CMSG_FIRSTHDR(&msg);177if (cmsg->cmsg_level != IPPROTO_TCP || cmsg->cmsg_type != TLS_GET_RECORD178|| cmsg->cmsg_len != CMSG_LEN(cmsg_len)) {179errno = EBADMSG;180return -1;181}182183tgr = (struct tls_get_record *)CMSG_DATA(cmsg);184p[0] = tgr->tls_type;185p[1] = tgr->tls_vmajor;186p[2] = tgr->tls_vminor;187*(uint16_t *)(p + 3) = htons(ret);188189return ret + prepend_length;190}191192# endif /* OPENSSL_NO_KTLS_RX */193194/*195* KTLS enables the sendfile system call to send data from a file over196* TLS.197*/198static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off,199size_t size, int flags)200{201off_t sbytes = 0;202int ret;203204ret = sendfile(fd, s, off, size, NULL, &sbytes, flags);205if (ret == -1 && sbytes == 0)206return -1;207return sbytes;208}209210# endif /* __FreeBSD__ */211212# if defined(OPENSSL_SYS_LINUX)213214# include <linux/tls.h>215# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)216# define OPENSSL_NO_KTLS_RX217# ifndef PEDANTIC218# warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"219# warning "Skipping Compilation of KTLS receive data path"220# endif221# endif222# if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)223# define OPENSSL_NO_KTLS_ZC_TX224# ifndef PEDANTIC225# warning "KTLS requires Kernel Headers >= 5.19.0 for zerocopy sendfile"226# warning "Skipping Compilation of KTLS zerocopy sendfile"227# endif228# endif229# define OPENSSL_KTLS_AES_GCM_128230# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)231# define OPENSSL_KTLS_AES_GCM_256232# define OPENSSL_KTLS_TLS13233# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)234# define OPENSSL_KTLS_AES_CCM_128235# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)236# ifndef OPENSSL_NO_CHACHA237# define OPENSSL_KTLS_CHACHA20_POLY1305238# endif239# endif240# endif241# endif242243# include <sys/sendfile.h>244# include <netinet/tcp.h>245# include <linux/socket.h>246# include <openssl/ssl3.h>247# include <openssl/tls1.h>248# include <openssl/evp.h>249250# ifndef SOL_TLS251# define SOL_TLS 282252# endif253254# ifndef TCP_ULP255# define TCP_ULP 31256# endif257258# ifndef TLS_RX259# define TLS_RX 2260# endif261262struct tls_crypto_info_all {263union {264# ifdef OPENSSL_KTLS_AES_GCM_128265struct tls12_crypto_info_aes_gcm_128 gcm128;266# endif267# ifdef OPENSSL_KTLS_AES_GCM_256268struct tls12_crypto_info_aes_gcm_256 gcm256;269# endif270# ifdef OPENSSL_KTLS_AES_CCM_128271struct tls12_crypto_info_aes_ccm_128 ccm128;272# endif273# ifdef OPENSSL_KTLS_CHACHA20_POLY1305274struct tls12_crypto_info_chacha20_poly1305 chacha20poly1305;275# endif276};277size_t tls_crypto_info_len;278};279280typedef struct tls_crypto_info_all ktls_crypto_info_t;281282/*283* When successful, this socket option doesn't change the behaviour of the284* TCP socket, except changing the TCP setsockopt handler to enable the285* processing of SOL_TLS socket options. All other functionality remains the286* same.287*/288static ossl_inline int ktls_enable(int fd)289{290return setsockopt(fd, SOL_TCP, TCP_ULP, "tls", sizeof("tls")) ? 0 : 1;291}292293/*294* The TLS_TX socket option changes the send/sendmsg handlers of the TCP socket.295* If successful, then data sent using this socket will be encrypted and296* encapsulated in TLS records using the crypto_info provided here.297* The TLS_RX socket option changes the recv/recvmsg handlers of the TCP socket.298* If successful, then data received using this socket will be decrypted,299* authenticated and decapsulated using the crypto_info provided here.300*/301static ossl_inline int ktls_start(int fd, ktls_crypto_info_t *crypto_info,302int is_tx)303{304return setsockopt(fd, SOL_TLS, is_tx ? TLS_TX : TLS_RX,305crypto_info, crypto_info->tls_crypto_info_len) ? 0 : 1;306}307308static ossl_inline int ktls_enable_tx_zerocopy_sendfile(int fd)309{310#ifndef OPENSSL_NO_KTLS_ZC_TX311int enable = 1;312313return setsockopt(fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,314&enable, sizeof(enable)) ? 0 : 1;315#else316return 0;317#endif318}319320/*321* Send a TLS record using the crypto_info provided in ktls_start and use322* record_type instead of the default SSL3_RT_APPLICATION_DATA.323* When the socket is non-blocking, then this call either returns EAGAIN or324* the entire record is pushed to TCP. It is impossible to send a partial325* record using this control message.326*/327static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,328const void *data, size_t length)329{330struct msghdr msg;331int cmsg_len = sizeof(record_type);332struct cmsghdr *cmsg;333union {334struct cmsghdr hdr;335char buf[CMSG_SPACE(sizeof(unsigned char))];336} cmsgbuf;337struct iovec msg_iov; /* Vector of data to send/receive into */338339memset(&msg, 0, sizeof(msg));340msg.msg_control = cmsgbuf.buf;341msg.msg_controllen = sizeof(cmsgbuf.buf);342cmsg = CMSG_FIRSTHDR(&msg);343cmsg->cmsg_level = SOL_TLS;344cmsg->cmsg_type = TLS_SET_RECORD_TYPE;345cmsg->cmsg_len = CMSG_LEN(cmsg_len);346*((unsigned char *)CMSG_DATA(cmsg)) = record_type;347msg.msg_controllen = cmsg->cmsg_len;348349msg_iov.iov_base = (void *)data;350msg_iov.iov_len = length;351msg.msg_iov = &msg_iov;352msg.msg_iovlen = 1;353354return sendmsg(fd, &msg, 0);355}356357/*358* KTLS enables the sendfile system call to send data from a file over TLS.359* @flags are ignored on Linux. (placeholder for FreeBSD sendfile)360* */361static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)362{363return sendfile(s, fd, &off, size);364}365366# ifdef OPENSSL_NO_KTLS_RX367368369static ossl_inline int ktls_read_record(int fd, void *data, size_t length)370{371return -1;372}373374# else /* !defined(OPENSSL_NO_KTLS_RX) */375376/*377* Receive a TLS record using the crypto_info provided in ktls_start.378* The kernel strips the TLS record header, IV and authentication tag,379* returning only the plaintext data or an error on failure.380* We add the TLS record header here to satisfy routines in rec_layer_s3.c381*/382static ossl_inline int ktls_read_record(int fd, void *data, size_t length)383{384struct msghdr msg;385struct cmsghdr *cmsg;386union {387struct cmsghdr hdr;388char buf[CMSG_SPACE(sizeof(unsigned char))];389} cmsgbuf;390struct iovec msg_iov;391int ret;392unsigned char *p = data;393const size_t prepend_length = SSL3_RT_HEADER_LENGTH;394395if (length < prepend_length + EVP_GCM_TLS_TAG_LEN) {396errno = EINVAL;397return -1;398}399400memset(&msg, 0, sizeof(msg));401msg.msg_control = cmsgbuf.buf;402msg.msg_controllen = sizeof(cmsgbuf.buf);403404msg_iov.iov_base = p + prepend_length;405msg_iov.iov_len = length - prepend_length - EVP_GCM_TLS_TAG_LEN;406msg.msg_iov = &msg_iov;407msg.msg_iovlen = 1;408409ret = recvmsg(fd, &msg, 0);410if (ret < 0)411return ret;412413if (msg.msg_controllen > 0) {414cmsg = CMSG_FIRSTHDR(&msg);415if (cmsg->cmsg_type == TLS_GET_RECORD_TYPE) {416p[0] = *((unsigned char *)CMSG_DATA(cmsg));417p[1] = TLS1_2_VERSION_MAJOR;418p[2] = TLS1_2_VERSION_MINOR;419/* returned length is limited to msg_iov.iov_len above */420p[3] = (ret >> 8) & 0xff;421p[4] = ret & 0xff;422ret += prepend_length;423}424}425426return ret;427}428429# endif /* OPENSSL_NO_KTLS_RX */430431# endif /* OPENSSL_SYS_LINUX */432# endif /* OPENSSL_NO_KTLS */433#endif /* HEADER_INTERNAL_KTLS */434435436