Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : /*
17 : : * kTLS is not supported on Windows. Stub implementations are provided so that
18 : : * callers (s2n_send.c, s2n_recv.c, etc.) compile and link without #ifdef guards.
19 : : * These stubs fail gracefully at runtime with S2N_ERR_KTLS_UNSUPPORTED_PLATFORM.
20 : : */
21 : : #ifdef _WIN32
22 : :
23 : : #include "error/s2n_errno.h"
24 : : #include "tls/s2n_connection.h"
25 : : #include "utils/s2n_result.h"
26 : : #include "utils/s2n_safety.h"
27 : :
28 : : bool s2n_ktls_is_supported_on_platform()
29 : : {
30 : : return false;
31 : : }
32 : :
33 : : int s2n_connection_ktls_enable_send(struct s2n_connection *conn)
34 : : {
35 : : POSIX_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
36 : : }
37 : :
38 : : int s2n_connection_ktls_enable_recv(struct s2n_connection *conn)
39 : : {
40 : : POSIX_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
41 : : }
42 : :
43 : : ssize_t s2n_ktls_sendv_with_offset(struct s2n_connection *conn, const struct iovec *bufs,
44 : : ssize_t count, ssize_t offs, s2n_blocked_status *blocked)
45 : : {
46 : : POSIX_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
47 : : }
48 : :
49 : : int s2n_ktls_record_writev(struct s2n_connection *conn, uint8_t content_type,
50 : : const struct iovec *in, int in_count, size_t offs, size_t to_write)
51 : : {
52 : : POSIX_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
53 : : }
54 : :
55 : : int s2n_ktls_read_full_record(struct s2n_connection *conn, uint8_t *record_type)
56 : : {
57 : : POSIX_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
58 : : }
59 : :
60 : : S2N_RESULT s2n_ktls_key_update_process(struct s2n_connection *conn)
61 : : {
62 : : RESULT_BAIL(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
63 : : }
64 : :
65 : : #else
66 : :
67 : : #include "crypto/s2n_ktls_crypto.h"
68 : : #include "crypto/s2n_sequence.h"
69 : : #include "tls/s2n_key_update.h"
70 : : #include "tls/s2n_ktls.h"
71 : : #include "tls/s2n_prf.h"
72 : : #include "tls/s2n_tls.h"
73 : : #include "tls/s2n_tls13_handshake.h"
74 : : #include "tls/s2n_tls13_key_schedule.h"
75 : :
76 : : /* Used for overriding setsockopt calls in testing */
77 : : s2n_setsockopt_fn s2n_setsockopt = setsockopt;
78 : :
79 : : S2N_RESULT s2n_ktls_set_setsockopt_cb(s2n_setsockopt_fn cb)
80 : 24 : {
81 [ - + ][ # # ]: 24 : RESULT_ENSURE(s2n_in_test(), S2N_ERR_NOT_IN_TEST);
82 : 24 : s2n_setsockopt = cb;
83 : 24 : return S2N_RESULT_OK;
84 : 24 : }
85 : :
86 : : bool s2n_ktls_is_supported_on_platform()
87 : 39 : {
88 : 39 : #if defined(S2N_KTLS_SUPPORTED)
89 : 39 : return true;
90 : : #else
91 : : return false;
92 : : #endif
93 : 39 : }
94 : :
95 : : static int s2n_ktls_disabled_read(void *io_context, uint8_t *buf, uint32_t len)
96 : 0 : {
97 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_IO);
98 : 0 : }
99 : :
100 : : static S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
101 : 37 : {
102 [ - + ][ # # ]: 37 : RESULT_ENSURE_REF(conn);
103 : 37 : const struct s2n_config *config = conn->config;
104 [ - + ][ # # ]: 37 : RESULT_ENSURE_REF(config);
105 : :
106 [ # # ][ - + ]: 37 : RESULT_ENSURE(s2n_ktls_is_supported_on_platform(), S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
107 : :
108 : : /* kTLS enable should only be called once the handshake has completed. */
109 [ + - ][ + + ]: 37 : RESULT_ENSURE(is_handshake_complete(conn), S2N_ERR_HANDSHAKE_NOT_COMPLETE);
110 : :
111 : : /* kTLS uses the prf_space to recalculate the keys, but the prf_space may be
112 : : * freed by s2n_connection_free_handshake to reduce the connection size.
113 : : * Explicitly check for prf_space here to avoid a confusing S2N_ERR_NULL later.
114 : : */
115 [ # # ][ - + ]: 35 : RESULT_ENSURE(conn->prf_space, S2N_ERR_INVALID_STATE);
116 : :
117 : : /* For now, only allow TlS1.3 if explicitly enabled.
118 : : *
119 : : * TLS1.3 is potentially more dangerous to enable than TLS1.2, since the kernel
120 : : * does not currently support updating TLS keys and therefore will fail if
121 : : * KeyUpdate messages are encountered.
122 : : */
123 [ + + ]: 35 : bool version_supported = (conn->actual_protocol_version == S2N_TLS12)
124 [ + + ][ + - ]: 35 : || (conn->config->ktls_tls13_enabled && conn->actual_protocol_version == S2N_TLS13);
125 [ + + ][ + - ]: 35 : RESULT_ENSURE(version_supported, S2N_ERR_KTLS_UNSUPPORTED_CONN);
126 : :
127 : : /* Check if the cipher supports kTLS */
128 : 32 : const struct s2n_cipher *cipher = NULL;
129 [ - + ]: 32 : RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
130 [ - + ][ # # ]: 32 : RESULT_ENSURE_REF(cipher);
131 [ + - ][ + + ]: 32 : RESULT_ENSURE(cipher->set_ktls_info, S2N_ERR_KTLS_UNSUPPORTED_CONN);
132 : :
133 : : /* Renegotiation requires updating the keys, which kTLS doesn't currently support.
134 : : *
135 : : * Setting the renegotiation callback doesn't guarantee that a client will
136 : : * attempt to renegotiate. The callback can also be used to send warning alerts
137 : : * signaling that renegotiation was rejected. However, we can provide applications
138 : : * with a clearer signal earlier by preventing them from enabling ktls on a
139 : : * connection that MIGHT require renegotiation. We can relax this restriction
140 : : * later if necessary.
141 : : */
142 : 30 : bool may_receive_hello_request = s2n_result_is_ok(s2n_client_hello_request_validate(conn));
143 [ + + ][ + + ]: 30 : bool may_renegotiate = may_receive_hello_request && config->renegotiate_request_cb;
144 [ + + ][ + - ]: 30 : RESULT_ENSURE(!may_renegotiate, S2N_ERR_KTLS_RENEG);
145 : :
146 : : /* Prevent kTLS from being enabled on connections that might be serialized.
147 : : *
148 : : * The socket takes over tracking sequence numbers when kTLS is enabled.
149 : : * We would need to call getsockopt to retrieve the current sequence numbers for
150 : : * serialization. This would complicate the serialization implementation so
151 : : * for now, do not support kTLS with serialization.
152 : : */
153 [ + - ][ + + ]: 29 : RESULT_ENSURE(config->serialized_connection_version == S2N_SERIALIZED_CONN_NONE,
154 : 28 : S2N_ERR_KTLS_UNSUPPORTED_CONN);
155 : :
156 : : /* kTLS I/O functionality is managed by s2n-tls. kTLS cannot be enabled if the
157 : : * application sets custom I/O (managed_send_io == false means application has
158 : : * set custom I/O).
159 : : */
160 : 28 : switch (ktls_mode) {
161 [ + + ]: 12 : case S2N_KTLS_MODE_SEND:
162 [ + + ][ + - ]: 12 : RESULT_ENSURE(conn->managed_send_io, S2N_ERR_KTLS_MANAGED_IO);
163 : : /* The output stuffer should be empty before enabling kTLS. */
164 [ + + ][ + - ]: 11 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->out), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
165 : 10 : break;
166 [ + + ]: 16 : case S2N_KTLS_MODE_RECV:
167 [ + - ][ + + ]: 16 : RESULT_ENSURE(conn->managed_recv_io, S2N_ERR_KTLS_MANAGED_IO);
168 : : /* The input stuffers should be empty before enabling kTLS. */
169 [ + + ][ + - ]: 15 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->header_in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
170 [ + - ][ + + ]: 14 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
171 [ + - ][ + + ]: 13 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->buffer_in), S2N_ERR_KTLS_UNSUPPORTED_CONN);
172 : 12 : break;
173 [ - + ]: 12 : default:
174 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_SAFETY);
175 : 0 : break;
176 : 28 : }
177 : :
178 : 22 : return S2N_RESULT_OK;
179 : 28 : }
180 : :
181 : : /* Enabling kTLS preserves the original *io_context; making this functions
182 : : * safe to call even after kTLS has been enabled on the connection.
183 : : *
184 : : * Retrieving fd assumes that the connection is using socket IO and has the
185 : : * send_io_context set. While kTLS overrides IO and essentially disables
186 : : * the socket conn->send function callback, it doesn't modify the
187 : : * send_io_context. */
188 : : S2N_RESULT s2n_ktls_get_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd)
189 : 1506 : {
190 [ # # ][ - + ]: 1506 : RESULT_ENSURE_REF(conn);
191 [ - + ][ # # ]: 1506 : RESULT_ENSURE_REF(fd);
192 : :
193 [ + + ]: 1506 : if (ktls_mode == S2N_KTLS_MODE_RECV) {
194 [ - + ]: 12 : RESULT_GUARD_POSIX(s2n_connection_get_read_fd(conn, fd));
195 [ + - ]: 1494 : } else if (ktls_mode == S2N_KTLS_MODE_SEND) {
196 [ - + ]: 1494 : RESULT_GUARD_POSIX(s2n_connection_get_write_fd(conn, fd));
197 : 1494 : }
198 : 1506 : return S2N_RESULT_OK;
199 : 1506 : }
200 : :
201 : : static S2N_RESULT s2n_ktls_get_io_mode(s2n_ktls_mode ktls_mode, int *tls_tx_rx_mode)
202 : 22 : {
203 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(tls_tx_rx_mode);
204 : :
205 [ + + ]: 22 : if (ktls_mode == S2N_KTLS_MODE_SEND) {
206 : 10 : *tls_tx_rx_mode = S2N_TLS_TX;
207 : 12 : } else {
208 : 12 : *tls_tx_rx_mode = S2N_TLS_RX;
209 : 12 : }
210 : 22 : return S2N_RESULT_OK;
211 : 22 : }
212 : :
213 : : static S2N_RESULT s2n_ktls_crypto_info_init(struct s2n_connection *conn, s2n_ktls_mode ktls_mode,
214 : : struct s2n_ktls_crypto_info *crypto_info)
215 : 22 : {
216 [ # # ][ - + ]: 22 : RESULT_ENSURE_REF(conn);
217 : 22 : struct s2n_crypto_parameters *secure = conn->secure;
218 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(secure);
219 : :
220 : : /* In order to avoid storing the encryption keys on the connection, we instead
221 : : * regenerate them when required by ktls.
222 : : *
223 : : * s2n_key_material also includes an IV, but we should use the IV stored
224 : : * on the connection instead. Some record algorithms (like CBC) mutate the
225 : : * "implicit_iv" when writing records, so the IV may change after generation.
226 : : */
227 : 22 : struct s2n_key_material key_material = { 0 };
228 : :
229 : 22 : bool is_sending_key = (ktls_mode == S2N_KTLS_MODE_SEND);
230 [ + + ]: 22 : s2n_mode key_mode = (is_sending_key) ? conn->mode : S2N_PEER_MODE(conn->mode);
231 : :
232 : 22 : switch (conn->actual_protocol_version) {
233 [ + + ]: 21 : case S2N_TLS12:
234 [ - + ]: 21 : RESULT_GUARD(s2n_prf_generate_key_material(conn, &key_material));
235 : 21 : break;
236 [ + + ]: 21 : case S2N_TLS13:
237 [ - + ]: 1 : RESULT_GUARD(s2n_tls13_key_schedule_generate_key_material(
238 : 1 : conn, key_mode, &key_material));
239 : 1 : break;
240 [ - + ]: 1 : default:
241 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_KTLS_UNSUPPORTED_CONN);
242 : 22 : }
243 : :
244 : 22 : struct s2n_ktls_crypto_info_inputs inputs = { 0 };
245 [ + + ]: 22 : if (key_mode == S2N_CLIENT) {
246 : 11 : inputs.key = key_material.client_key;
247 [ - + ]: 11 : RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
248 : 11 : secure->client_implicit_iv, sizeof(secure->client_implicit_iv)));
249 : 11 : } else {
250 : 11 : inputs.key = key_material.server_key;
251 [ - + ]: 11 : RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
252 : 11 : secure->server_implicit_iv, sizeof(secure->server_implicit_iv)));
253 : 11 : }
254 [ - + ]: 22 : RESULT_GUARD(s2n_connection_get_sequence_number(conn, key_mode, &inputs.seq));
255 : :
256 : 22 : const struct s2n_cipher *cipher = NULL;
257 [ - + ]: 22 : RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
258 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(cipher);
259 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(cipher->set_ktls_info);
260 [ - + ]: 22 : RESULT_GUARD(cipher->set_ktls_info(&inputs, crypto_info));
261 : 22 : return S2N_RESULT_OK;
262 : 22 : }
263 : :
264 : : /* This method intentionally returns void because it may NOT perform any fallible
265 : : * operations. See s2n_connection_ktls_enable.
266 : : */
267 : : void s2n_ktls_configure_connection(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
268 : 41 : {
269 [ - + ]: 41 : if (conn == NULL) {
270 : 0 : return;
271 : 0 : }
272 [ + + ]: 41 : if (ktls_mode == S2N_KTLS_MODE_SEND) {
273 : 16 : conn->ktls_send_enabled = true;
274 : 16 : conn->send = s2n_ktls_send_cb;
275 : 25 : } else {
276 : 25 : conn->ktls_recv_enabled = true;
277 : 25 : conn->recv = s2n_ktls_disabled_read;
278 : 25 : }
279 : 41 : }
280 : :
281 : : static S2N_RESULT s2n_connection_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
282 : 37 : {
283 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(conn);
284 [ + + ]: 37 : RESULT_GUARD(s2n_ktls_validate(conn, ktls_mode));
285 : :
286 : 22 : int fd = 0;
287 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, ktls_mode, &fd));
288 : :
289 : : /* This call doesn't actually enable ktls or modify the IO behavior of the socket.
290 : : * Instead, this is just a prerequisite for calling setsockopt with SOL_TLS.
291 : : *
292 : : * We intentionally ignore the result of this call. It may fail because ktls
293 : : * is not supported, but it might also fail because ktls has already been enabled
294 : : * for the socket. If SOL_TLS isn't enabled on the socket, our next call to
295 : : * setsockopt with SOL_TLS will also fail, and we DO check that result.
296 : : */
297 : 22 : s2n_setsockopt(fd, S2N_SOL_TCP, S2N_TCP_ULP, S2N_TLS_ULP_NAME, S2N_TLS_ULP_NAME_SIZE);
298 : :
299 : 22 : int tls_tx_rx_mode = 0;
300 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_get_io_mode(ktls_mode, &tls_tx_rx_mode));
301 : :
302 : 22 : struct s2n_ktls_crypto_info crypto_info = { 0 };
303 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_crypto_info_init(conn, ktls_mode, &crypto_info));
304 : :
305 : : /* If this call succeeds, then ktls is enabled for that io mode and will be offloaded */
306 : 22 : int ret = s2n_setsockopt(fd, S2N_SOL_TLS, tls_tx_rx_mode, crypto_info.value.data, crypto_info.value.size);
307 [ + + ][ + - ]: 22 : RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_ENABLE);
308 : :
309 : : /* At this point, ktls is enabled on the socket for the requested IO mode.
310 : : * No further fallible operations may be performed, or else the caller may
311 : : * incorrectly assume that enabling ktls failed and they should therefore
312 : : * fall back to using application layer TLS.
313 : : *
314 : : * That means no calls to RESULT_ENSURE, RESULT_GUARD, etc. after this point.
315 : : */
316 : :
317 : 18 : s2n_ktls_configure_connection(conn, ktls_mode);
318 : 18 : return S2N_RESULT_OK;
319 : 22 : }
320 : :
321 : : int s2n_connection_ktls_enable_send(struct s2n_connection *conn)
322 : 18 : {
323 [ # # ][ - + ]: 18 : POSIX_ENSURE_REF(conn);
324 : :
325 : : /* If already enabled then return success */
326 [ + + ]: 18 : if (conn->ktls_send_enabled) {
327 : 1 : return S2N_SUCCESS;
328 : 1 : }
329 : :
330 [ + + ]: 17 : POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_SEND));
331 : 8 : return S2N_SUCCESS;
332 : 17 : }
333 : :
334 : : int s2n_connection_ktls_enable_recv(struct s2n_connection *conn)
335 : 21 : {
336 [ - + ][ # # ]: 21 : POSIX_ENSURE_REF(conn);
337 : :
338 : : /* If already enabled then return success */
339 [ + + ]: 21 : if (conn->ktls_recv_enabled) {
340 : 1 : return S2N_SUCCESS;
341 : 1 : }
342 : :
343 [ + + ]: 20 : POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_RECV));
344 : 10 : return S2N_SUCCESS;
345 : 20 : }
346 : :
347 : : int s2n_config_ktls_enable_unsafe_tls13(struct s2n_config *config)
348 : 6 : {
349 [ + - ][ + + ]: 6 : POSIX_ENSURE_REF(config);
350 : 5 : config->ktls_tls13_enabled = true;
351 : 5 : return S2N_SUCCESS;
352 : 6 : }
353 : :
354 : : /* The RFC defines the encryption limits in terms of "full-size records" sent.
355 : : * We can estimate the number of "full-sized records" sent by assuming that
356 : : * all records are full-sized.
357 : : */
358 : : static S2N_RESULT s2n_ktls_estimate_records(size_t bytes, uint64_t *estimate)
359 : 88 : {
360 [ - + ][ # # ]: 88 : RESULT_ENSURE_REF(estimate);
361 : 88 : uint64_t records = bytes / S2N_TLS_MAXIMUM_FRAGMENT_LENGTH;
362 [ + + ]: 88 : if (bytes % S2N_TLS_MAXIMUM_FRAGMENT_LENGTH) {
363 : 70 : records++;
364 : 70 : }
365 : 88 : *estimate = records;
366 : 88 : return S2N_RESULT_OK;
367 : 88 : }
368 : :
369 : : S2N_RESULT s2n_ktls_set_estimated_sequence_number(
370 : : struct s2n_connection *conn, size_t bytes_written)
371 : 50693 : {
372 [ - + ][ # # ]: 50693 : RESULT_ENSURE_REF(conn);
373 [ + + ]: 50693 : if (conn->actual_protocol_version < S2N_TLS13) {
374 : 50655 : return S2N_RESULT_OK;
375 : 50655 : }
376 : :
377 : 38 : uint64_t new_records_sent = 0;
378 [ - + ]: 38 : RESULT_GUARD(s2n_ktls_estimate_records(bytes_written, &new_records_sent));
379 : :
380 : 38 : struct s2n_blob seq_num = { 0 };
381 [ - + ]: 38 : RESULT_GUARD(s2n_connection_get_sequence_number(conn, conn->mode, &seq_num));
382 : :
383 [ + + ]: 97 : for (size_t i = 0; i < new_records_sent; i++) {
384 [ - + ]: 59 : RESULT_GUARD_POSIX(s2n_increment_sequence_number(&seq_num));
385 : 59 : }
386 : 38 : return S2N_RESULT_OK;
387 : 38 : }
388 : :
389 : : /* We need to track when the key encryption limit is reached. We could get the current record
390 : : * sequence number from the kernel with getsockopt, but that requires a surprisingly
391 : : * expensive syscall.
392 : : *
393 : : * Instead, we track the estimated sequence number and enforce the limit based
394 : : * on that estimate.
395 : : */
396 : : S2N_RESULT s2n_ktls_check_estimated_record_limit(struct s2n_connection *conn, size_t bytes_requested)
397 : 50710 : {
398 [ # # ][ - + ]: 50710 : RESULT_ENSURE_REF(conn);
399 [ + + ]: 50710 : if (conn->actual_protocol_version < S2N_TLS13) {
400 : 50660 : return S2N_RESULT_OK;
401 : 50660 : }
402 : :
403 : 50 : uint64_t new_records_sent = 0;
404 [ - + ]: 50 : RESULT_GUARD(s2n_ktls_estimate_records(bytes_requested, &new_records_sent));
405 : :
406 : 50 : uint64_t old_records_sent = 0;
407 : 50 : struct s2n_blob seq_num = { 0 };
408 [ - + ]: 50 : RESULT_GUARD(s2n_connection_get_sequence_number(conn, conn->mode, &seq_num));
409 [ - + ]: 50 : RESULT_GUARD_POSIX(s2n_sequence_number_to_uint64(&seq_num, &old_records_sent));
410 : :
411 [ # # ][ + - ]: 50 : RESULT_ENSURE(S2N_ADD_IS_OVERFLOW_SAFE(old_records_sent, new_records_sent, UINT64_MAX),
[ + - ]
412 : 50 : S2N_ERR_KTLS_KEY_LIMIT);
413 : 50 : uint64_t total_records_sent = old_records_sent + new_records_sent;
414 : :
415 [ - + ][ # # ]: 50 : RESULT_ENSURE_REF(conn->secure);
416 [ - + ][ # # ]: 50 : RESULT_ENSURE_REF(conn->secure->cipher_suite);
417 [ - + ][ # # ]: 50 : RESULT_ENSURE_REF(conn->secure->cipher_suite->record_alg);
418 : 50 : uint64_t encryption_limit = conn->secure->cipher_suite->record_alg->encryption_limit;
419 [ + + ]: 50 : if (total_records_sent > encryption_limit) {
420 [ # # ][ - + ]: 12 : RESULT_ENSURE_REF(conn->config);
421 [ + + ][ + - ]: 12 : RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEY_LIMIT);
422 : :
423 : : /* Check that the data requested for the ktls send call is not going over the encryption limit,
424 : : * as that would require multiple key updates.
425 : : * In TLS1.3, the key limit is 2^24.5 full-size records. (See S2N_TLS13_AES_GCM_MAXIMUM_RECORD_NUMBER)
426 : : * A full-sized record is 2^14 bytes. So essentially 2^24.5 * 2^14 bytes(388 GB) can be sent
427 : : * before you need to key update. We can add logic for multiple key updates in a single ktls
428 : : * send call in the future, but it's not required at the moment. */
429 [ + - ][ + + ]: 5 : RESULT_ENSURE(new_records_sent <= encryption_limit, S2N_ERR_INVALID_ARGUMENT);
430 : 2 : s2n_atomic_flag_set(&conn->key_update_pending);
431 : 2 : }
432 : :
433 : 40 : return S2N_RESULT_OK;
434 : 50 : }
435 : :
436 : : S2N_RESULT s2n_ktls_key_update_send(struct s2n_connection *conn, size_t bytes_requested)
437 : 50703 : {
438 [ - + ][ # # ]: 50703 : RESULT_ENSURE_REF(conn);
439 [ + + ]: 50703 : RESULT_GUARD(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
440 : :
441 [ - + ]: 50696 : if (s2n_atomic_flag_test(&conn->key_update_pending)) {
442 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(conn->config);
443 [ # # ][ # # ]: 0 : RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEYUPDATE);
444 : :
445 : 0 : uint8_t key_update_data[S2N_KEY_UPDATE_MESSAGE_SIZE];
446 : 0 : struct s2n_blob key_update_blob = { 0 };
447 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_blob_init(&key_update_blob, key_update_data, sizeof(key_update_data)));
448 : :
449 : : /* Write Keyupdate message */
450 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_key_update_write(&key_update_blob));
451 : :
452 : : /* Send Keyupdate message */
453 : 0 : const struct iovec iov = {
454 : 0 : .iov_base = (void *) (uintptr_t) key_update_data,
455 : 0 : .iov_len = sizeof(key_update_data),
456 : 0 : };
457 : 0 : s2n_blocked_status blocked = S2N_NOT_BLOCKED;
458 : 0 : size_t bytes_written = 0;
459 [ # # ]: 0 : RESULT_GUARD(s2n_ktls_sendmsg(conn->send_io_context, TLS_HANDSHAKE, &iov, 1, &blocked, &bytes_written));
460 [ # # ][ # # ]: 0 : RESULT_ENSURE_EQ(bytes_written, sizeof(key_update_data));
461 : :
462 : : /* Create new encryption key */
463 [ # # ]: 0 : RESULT_GUARD_POSIX(s2n_update_application_traffic_keys(conn, conn->mode, SENDING));
464 : :
465 : 0 : struct s2n_ktls_crypto_info crypto_info = { 0 };
466 [ # # ]: 0 : RESULT_GUARD(s2n_ktls_crypto_info_init(conn, S2N_KTLS_MODE_SEND, &crypto_info));
467 : :
468 : 0 : int fd = 0;
469 [ # # ]: 0 : RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, S2N_KTLS_MODE_SEND, &fd));
470 : :
471 : : /* Update the socket with new key */
472 : 0 : int ret = s2n_setsockopt(fd, S2N_SOL_TLS, S2N_TLS_TX, crypto_info.value.data, crypto_info.value.size);
473 [ # # ][ # # ]: 0 : RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_SOCKOPT);
474 : :
475 : 0 : s2n_atomic_flag_clear(&conn->key_update_pending);
476 : 0 : }
477 : 50696 : return S2N_RESULT_OK;
478 : 50696 : }
479 : :
480 : : S2N_RESULT s2n_ktls_key_update_process(struct s2n_connection *conn)
481 : 1 : {
482 [ # # ][ - + ]: 1 : RESULT_ENSURE_REF(conn);
483 [ - + ][ # # ]: 1 : RESULT_ENSURE_REF(conn->config);
484 [ + - ][ + - ]: 1 : RESULT_ENSURE(conn->config->ktls_tls13_enabled, S2N_ERR_KTLS_KEYUPDATE);
485 : :
486 : 0 : struct s2n_ktls_crypto_info crypto_info = { 0 };
487 [ # # ]: 0 : RESULT_GUARD(s2n_ktls_crypto_info_init(conn, S2N_KTLS_MODE_RECV, &crypto_info));
488 : :
489 : 0 : int fd = 0;
490 [ # # ]: 0 : RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, S2N_KTLS_MODE_RECV, &fd));
491 : :
492 : : /* Update the socket with new key */
493 : 0 : int ret = s2n_setsockopt(fd, S2N_SOL_TLS, S2N_TLS_RX, crypto_info.value.data, crypto_info.value.size);
494 [ # # ][ # # ]: 0 : RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_SOCKOPT);
495 : :
496 : 0 : return S2N_RESULT_OK;
497 : 0 : }
498 : :
499 : : #endif
|