Home | History | Annotate | Line # | Download | only in internal
      1 /*
      2  * Copyright 2018-2024 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #if defined(OPENSSL_SYS_LINUX)
     11 #ifndef OPENSSL_NO_KTLS
     12 #include <linux/version.h>
     13 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
     14 #define OPENSSL_NO_KTLS
     15 #ifndef PEDANTIC
     16 #warning "KTLS requires Kernel Headers >= 4.13.0"
     17 #warning "Skipping Compilation of KTLS"
     18 #endif
     19 #endif
     20 #endif
     21 #endif
     22 
     23 #ifndef HEADER_INTERNAL_KTLS
     24 #define HEADER_INTERNAL_KTLS
     25 #pragma once
     26 
     27 #ifndef OPENSSL_NO_KTLS
     28 
     29 #if defined(__FreeBSD__)
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 #include <sys/ktls.h>
     33 #include <netinet/in.h>
     34 #include <netinet/tcp.h>
     35 #include <openssl/ssl3.h>
     36 
     37 #ifndef TCP_RXTLS_ENABLE
     38 #define OPENSSL_NO_KTLS_RX
     39 #endif
     40 #define OPENSSL_KTLS_AES_GCM_128
     41 #define OPENSSL_KTLS_AES_GCM_256
     42 #define OPENSSL_KTLS_TLS13
     43 #ifdef TLS_CHACHA20_IV_LEN
     44 #ifndef OPENSSL_NO_CHACHA
     45 #define OPENSSL_KTLS_CHACHA20_POLY1305
     46 #endif
     47 #endif
     48 
     49 typedef struct tls_enable ktls_crypto_info_t;
     50 
     51 /*
     52  * FreeBSD does not require any additional steps to enable KTLS before
     53  * setting keys.
     54  */
     55 static ossl_inline int ktls_enable(int fd)
     56 {
     57     return 1;
     58 }
     59 
     60 /*
     61  * The TCP_TXTLS_ENABLE socket option marks the outgoing socket buffer
     62  * as using TLS.  If successful, then data sent using this socket will
     63  * be encrypted and encapsulated in TLS records using the tls_en
     64  * provided here.
     65  *
     66  * The TCP_RXTLS_ENABLE socket option marks the incoming socket buffer
     67  * as using TLS.  If successful, then data received for this socket will
     68  * be authenticated and decrypted using the tls_en provided here.
     69  */
     70 static ossl_inline int ktls_start(int fd, ktls_crypto_info_t *tls_en, int is_tx)
     71 {
     72     if (is_tx)
     73         return setsockopt(fd, IPPROTO_TCP, TCP_TXTLS_ENABLE,
     74                    tls_en, sizeof(*tls_en))
     75             ? 0
     76             : 1;
     77 #ifndef OPENSSL_NO_KTLS_RX
     78     return setsockopt(fd, IPPROTO_TCP, TCP_RXTLS_ENABLE, tls_en,
     79                sizeof(*tls_en))
     80         ? 0
     81         : 1;
     82 #else
     83     return 0;
     84 #endif
     85 }
     86 
     87 /* Not supported on FreeBSD */
     88 static ossl_inline int ktls_enable_tx_zerocopy_sendfile(int fd)
     89 {
     90     return 0;
     91 }
     92 
     93 /*
     94  * Send a TLS record using the tls_en provided in ktls_start and use
     95  * record_type instead of the default SSL3_RT_APPLICATION_DATA.
     96  * When the socket is non-blocking, then this call either returns EAGAIN or
     97  * the entire record is pushed to TCP. It is impossible to send a partial
     98  * record using this control message.
     99  */
    100 static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
    101     const void *data, size_t length)
    102 {
    103     struct msghdr msg = { 0 };
    104     int cmsg_len = sizeof(record_type);
    105     struct cmsghdr *cmsg;
    106     char buf[CMSG_SPACE(cmsg_len)];
    107     struct iovec msg_iov; /* Vector of data to send/receive into */
    108 
    109     msg.msg_control = buf;
    110     msg.msg_controllen = sizeof(buf);
    111     cmsg = CMSG_FIRSTHDR(&msg);
    112     cmsg->cmsg_level = IPPROTO_TCP;
    113     cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
    114     cmsg->cmsg_len = CMSG_LEN(cmsg_len);
    115     *((unsigned char *)CMSG_DATA(cmsg)) = record_type;
    116     msg.msg_controllen = cmsg->cmsg_len;
    117 
    118     msg_iov.iov_base = (void *)data;
    119     msg_iov.iov_len = length;
    120     msg.msg_iov = &msg_iov;
    121     msg.msg_iovlen = 1;
    122 
    123     return sendmsg(fd, &msg, 0);
    124 }
    125 
    126 #ifdef OPENSSL_NO_KTLS_RX
    127 
    128 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
    129 {
    130     return -1;
    131 }
    132 
    133 #else /* !defined(OPENSSL_NO_KTLS_RX) */
    134 
    135 /*
    136  * Receive a TLS record using the tls_en provided in ktls_start.  The
    137  * kernel strips any explicit IV and authentication tag, but provides
    138  * the TLS record header via a control message.  If there is an error
    139  * with the TLS record such as an invalid header, invalid padding, or
    140  * authentication failure recvmsg() will fail with an error.
    141  */
    142 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
    143 {
    144     struct msghdr msg = { 0 };
    145     int cmsg_len = sizeof(struct tls_get_record);
    146     struct tls_get_record *tgr;
    147     struct cmsghdr *cmsg;
    148     char buf[CMSG_SPACE(cmsg_len)];
    149     struct iovec msg_iov; /* Vector of data to send/receive into */
    150     int ret;
    151     unsigned char *p = data;
    152     const size_t prepend_length = SSL3_RT_HEADER_LENGTH;
    153 
    154     if (length <= prepend_length) {
    155         errno = EINVAL;
    156         return -1;
    157     }
    158 
    159     msg.msg_control = buf;
    160     msg.msg_controllen = sizeof(buf);
    161 
    162     msg_iov.iov_base = p + prepend_length;
    163     msg_iov.iov_len = length - prepend_length;
    164     msg.msg_iov = &msg_iov;
    165     msg.msg_iovlen = 1;
    166 
    167     ret = recvmsg(fd, &msg, 0);
    168     if (ret <= 0)
    169         return ret;
    170 
    171     if ((msg.msg_flags & (MSG_EOR | MSG_CTRUNC)) != MSG_EOR) {
    172         errno = EMSGSIZE;
    173         return -1;
    174     }
    175 
    176     if (msg.msg_controllen == 0) {
    177         errno = EBADMSG;
    178         return -1;
    179     }
    180 
    181     cmsg = CMSG_FIRSTHDR(&msg);
    182     if (cmsg->cmsg_level != IPPROTO_TCP || cmsg->cmsg_type != TLS_GET_RECORD
    183         || cmsg->cmsg_len != CMSG_LEN(cmsg_len)) {
    184         errno = EBADMSG;
    185         return -1;
    186     }
    187 
    188     tgr = (struct tls_get_record *)CMSG_DATA(cmsg);
    189     p[0] = tgr->tls_type;
    190     p[1] = tgr->tls_vmajor;
    191     p[2] = tgr->tls_vminor;
    192     p[3] = (ret >> 8) & 0xff;
    193     p[4] = ret & 0xff;
    194 
    195     return ret + prepend_length;
    196 }
    197 
    198 #endif /* OPENSSL_NO_KTLS_RX */
    199 
    200 /*
    201  * KTLS enables the sendfile system call to send data from a file over
    202  * TLS.
    203  */
    204 static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off,
    205     size_t size, int flags)
    206 {
    207     off_t sbytes = 0;
    208     int ret;
    209 
    210     ret = sendfile(fd, s, off, size, NULL, &sbytes, flags);
    211     if (ret == -1 && sbytes == 0)
    212         return -1;
    213     return sbytes;
    214 }
    215 
    216 #endif /* __FreeBSD__ */
    217 
    218 #if defined(OPENSSL_SYS_LINUX)
    219 
    220 #include <linux/tls.h>
    221 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
    222 #define OPENSSL_NO_KTLS_RX
    223 #ifndef PEDANTIC
    224 #warning "KTLS requires Kernel Headers >= 4.17.0 for receiving"
    225 #warning "Skipping Compilation of KTLS receive data path"
    226 #endif
    227 #endif
    228 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
    229 #define OPENSSL_NO_KTLS_ZC_TX
    230 #ifndef PEDANTIC
    231 #warning "KTLS requires Kernel Headers >= 5.19.0 for zerocopy sendfile"
    232 #warning "Skipping Compilation of KTLS zerocopy sendfile"
    233 #endif
    234 #endif
    235 #define OPENSSL_KTLS_AES_GCM_128
    236 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
    237 #define OPENSSL_KTLS_AES_GCM_256
    238 #define OPENSSL_KTLS_TLS13
    239 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
    240 #define OPENSSL_KTLS_AES_CCM_128
    241 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
    242 #ifndef OPENSSL_NO_CHACHA
    243 #define OPENSSL_KTLS_CHACHA20_POLY1305
    244 #endif
    245 #endif
    246 #endif
    247 #endif
    248 
    249 #include <sys/sendfile.h>
    250 #include <netinet/tcp.h>
    251 #include <linux/socket.h>
    252 #include <openssl/ssl3.h>
    253 #include <openssl/tls1.h>
    254 #include <openssl/evp.h>
    255 
    256 #ifndef SOL_TLS
    257 #define SOL_TLS 282
    258 #endif
    259 
    260 #ifndef TCP_ULP
    261 #define TCP_ULP 31
    262 #endif
    263 
    264 #ifndef TLS_RX
    265 #define TLS_RX 2
    266 #endif
    267 
    268 struct tls_crypto_info_all {
    269     union {
    270 #ifdef OPENSSL_KTLS_AES_GCM_128
    271         struct tls12_crypto_info_aes_gcm_128 gcm128;
    272 #endif
    273 #ifdef OPENSSL_KTLS_AES_GCM_256
    274         struct tls12_crypto_info_aes_gcm_256 gcm256;
    275 #endif
    276 #ifdef OPENSSL_KTLS_AES_CCM_128
    277         struct tls12_crypto_info_aes_ccm_128 ccm128;
    278 #endif
    279 #ifdef OPENSSL_KTLS_CHACHA20_POLY1305
    280         struct tls12_crypto_info_chacha20_poly1305 chacha20poly1305;
    281 #endif
    282     };
    283     size_t tls_crypto_info_len;
    284 };
    285 
    286 typedef struct tls_crypto_info_all ktls_crypto_info_t;
    287 
    288 /*
    289  * When successful, this socket option doesn't change the behaviour of the
    290  * TCP socket, except changing the TCP setsockopt handler to enable the
    291  * processing of SOL_TLS socket options. All other functionality remains the
    292  * same.
    293  */
    294 static ossl_inline int ktls_enable(int fd)
    295 {
    296     return setsockopt(fd, SOL_TCP, TCP_ULP, "tls", sizeof("tls")) ? 0 : 1;
    297 }
    298 
    299 /*
    300  * The TLS_TX socket option changes the send/sendmsg handlers of the TCP socket.
    301  * If successful, then data sent using this socket will be encrypted and
    302  * encapsulated in TLS records using the crypto_info provided here.
    303  * The TLS_RX socket option changes the recv/recvmsg handlers of the TCP socket.
    304  * If successful, then data received using this socket will be decrypted,
    305  * authenticated and decapsulated using the crypto_info provided here.
    306  */
    307 static ossl_inline int ktls_start(int fd, ktls_crypto_info_t *crypto_info,
    308     int is_tx)
    309 {
    310     /*
    311      * Socket must be in TCP established state to enable KTLS.
    312      * Further calls to enable ktls will return EEXIST
    313      */
    314     ktls_enable(fd);
    315 
    316     return setsockopt(fd, SOL_TLS, is_tx ? TLS_TX : TLS_RX,
    317                crypto_info, crypto_info->tls_crypto_info_len)
    318         ? 0
    319         : 1;
    320 }
    321 
    322 static ossl_inline int ktls_enable_tx_zerocopy_sendfile(int fd)
    323 {
    324 #ifndef OPENSSL_NO_KTLS_ZC_TX
    325     int enable = 1;
    326 
    327     return setsockopt(fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
    328                &enable, sizeof(enable))
    329         ? 0
    330         : 1;
    331 #else
    332     return 0;
    333 #endif
    334 }
    335 
    336 /*
    337  * Send a TLS record using the crypto_info provided in ktls_start and use
    338  * record_type instead of the default SSL3_RT_APPLICATION_DATA.
    339  * When the socket is non-blocking, then this call either returns EAGAIN or
    340  * the entire record is pushed to TCP. It is impossible to send a partial
    341  * record using this control message.
    342  */
    343 static ossl_inline int ktls_send_ctrl_message(int fd, unsigned char record_type,
    344     const void *data, size_t length)
    345 {
    346     struct msghdr msg;
    347     int cmsg_len = sizeof(record_type);
    348     struct cmsghdr *cmsg;
    349     union {
    350         struct cmsghdr hdr;
    351         char buf[CMSG_SPACE(sizeof(unsigned char))];
    352     } cmsgbuf;
    353     struct iovec msg_iov; /* Vector of data to send/receive into */
    354 
    355     memset(&msg, 0, sizeof(msg));
    356     msg.msg_control = cmsgbuf.buf;
    357     msg.msg_controllen = sizeof(cmsgbuf.buf);
    358     cmsg = CMSG_FIRSTHDR(&msg);
    359     cmsg->cmsg_level = SOL_TLS;
    360     cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
    361     cmsg->cmsg_len = CMSG_LEN(cmsg_len);
    362     *((unsigned char *)CMSG_DATA(cmsg)) = record_type;
    363     msg.msg_controllen = cmsg->cmsg_len;
    364 
    365     msg_iov.iov_base = (void *)data;
    366     msg_iov.iov_len = length;
    367     msg.msg_iov = &msg_iov;
    368     msg.msg_iovlen = 1;
    369 
    370     return sendmsg(fd, &msg, 0);
    371 }
    372 
    373 /*
    374  * KTLS enables the sendfile system call to send data from a file over TLS.
    375  * @flags are ignored on Linux. (placeholder for FreeBSD sendfile)
    376  * */
    377 static ossl_inline ossl_ssize_t ktls_sendfile(int s, int fd, off_t off, size_t size, int flags)
    378 {
    379     return sendfile(s, fd, &off, size);
    380 }
    381 
    382 #ifdef OPENSSL_NO_KTLS_RX
    383 
    384 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
    385 {
    386     return -1;
    387 }
    388 
    389 #else /* !defined(OPENSSL_NO_KTLS_RX) */
    390 
    391 /*
    392  * Receive a TLS record using the crypto_info provided in ktls_start.
    393  * The kernel strips the TLS record header, IV and authentication tag,
    394  * returning only the plaintext data or an error on failure.
    395  * We add the TLS record header here to satisfy routines in rec_layer_s3.c
    396  */
    397 static ossl_inline int ktls_read_record(int fd, void *data, size_t length)
    398 {
    399     struct msghdr msg;
    400     struct cmsghdr *cmsg;
    401     union {
    402         struct cmsghdr hdr;
    403         char buf[CMSG_SPACE(sizeof(unsigned char))];
    404     } cmsgbuf;
    405     struct iovec msg_iov;
    406     int ret;
    407     unsigned char *p = data;
    408     const size_t prepend_length = SSL3_RT_HEADER_LENGTH;
    409 
    410     if (length < prepend_length + EVP_GCM_TLS_TAG_LEN) {
    411         errno = EINVAL;
    412         return -1;
    413     }
    414 
    415     memset(&msg, 0, sizeof(msg));
    416     msg.msg_control = cmsgbuf.buf;
    417     msg.msg_controllen = sizeof(cmsgbuf.buf);
    418 
    419     msg_iov.iov_base = p + prepend_length;
    420     msg_iov.iov_len = length - prepend_length - EVP_GCM_TLS_TAG_LEN;
    421     msg.msg_iov = &msg_iov;
    422     msg.msg_iovlen = 1;
    423 
    424     ret = recvmsg(fd, &msg, 0);
    425     if (ret < 0)
    426         return ret;
    427 
    428     if (msg.msg_controllen > 0) {
    429         cmsg = CMSG_FIRSTHDR(&msg);
    430         if (cmsg->cmsg_type == TLS_GET_RECORD_TYPE) {
    431             p[0] = *((unsigned char *)CMSG_DATA(cmsg));
    432             p[1] = TLS1_2_VERSION_MAJOR;
    433             p[2] = TLS1_2_VERSION_MINOR;
    434             /* returned length is limited to msg_iov.iov_len above */
    435             p[3] = (ret >> 8) & 0xff;
    436             p[4] = ret & 0xff;
    437             ret += prepend_length;
    438         }
    439     }
    440 
    441     return ret;
    442 }
    443 
    444 #endif /* OPENSSL_NO_KTLS_RX */
    445 
    446 #endif /* OPENSSL_SYS_LINUX */
    447 #endif /* OPENSSL_NO_KTLS */
    448 #endif /* HEADER_INTERNAL_KTLS */
    449