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