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 : : #include "tls/s2n_ktls.h"
17 : :
18 : : #include "crypto/s2n_ktls_crypto.h"
19 : : #include "tls/s2n_prf.h"
20 : : #include "tls/s2n_tls.h"
21 : : #include "tls/s2n_tls13_key_schedule.h"
22 : :
23 : : /* Used for overriding setsockopt calls in testing */
24 : : s2n_setsockopt_fn s2n_setsockopt = setsockopt;
25 : :
26 : : S2N_RESULT s2n_ktls_set_setsockopt_cb(s2n_setsockopt_fn cb)
27 : 24 : {
28 [ - + ][ # # ]: 24 : RESULT_ENSURE(s2n_in_test(), S2N_ERR_NOT_IN_TEST);
29 : 24 : s2n_setsockopt = cb;
30 : 24 : return S2N_RESULT_OK;
31 : 24 : }
32 : :
33 : : bool s2n_ktls_is_supported_on_platform()
34 : 39 : {
35 : 39 : #if defined(S2N_KTLS_SUPPORTED)
36 : 39 : return true;
37 : : #else
38 : : return false;
39 : : #endif
40 : 39 : }
41 : :
42 : : static int s2n_ktls_disabled_read(void *io_context, uint8_t *buf, uint32_t len)
43 : 0 : {
44 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_IO);
45 : 0 : }
46 : :
47 : : static S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
48 : 37 : {
49 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(conn);
50 : 37 : const struct s2n_config *config = conn->config;
51 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(config);
52 : :
53 [ - + ][ # # ]: 37 : RESULT_ENSURE(s2n_ktls_is_supported_on_platform(), S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
54 : :
55 : : /* kTLS enable should only be called once the handshake has completed. */
56 [ + + ][ + - ]: 37 : RESULT_ENSURE(is_handshake_complete(conn), S2N_ERR_HANDSHAKE_NOT_COMPLETE);
57 : :
58 : : /* kTLS uses the prf_space to recalculate the keys, but the prf_space may be
59 : : * freed by s2n_connection_free_handshake to reduce the connection size.
60 : : * Explicitly check for prf_space here to avoid a confusing S2N_ERR_NULL later.
61 : : */
62 [ - + ][ # # ]: 35 : RESULT_ENSURE(conn->prf_space, S2N_ERR_INVALID_STATE);
63 : :
64 : : /* For now, only allow TlS1.3 if explicitly enabled.
65 : : *
66 : : * TLS1.3 is potentially more dangerous to enable than TLS1.2, since the kernel
67 : : * does not currently support updating TLS keys and therefore will fail if
68 : : * KeyUpdate messages are encountered.
69 : : */
70 [ + + ]: 35 : bool version_supported = (conn->actual_protocol_version == S2N_TLS12)
71 [ + + ][ + - ]: 35 : || (conn->config->ktls_tls13_enabled && conn->actual_protocol_version == S2N_TLS13);
72 [ + - ][ + + ]: 35 : RESULT_ENSURE(version_supported, S2N_ERR_KTLS_UNSUPPORTED_CONN);
73 : :
74 : : /* Check if the cipher supports kTLS */
75 : 32 : const struct s2n_cipher *cipher = NULL;
76 [ - + ]: 32 : RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
77 [ - + ][ # # ]: 32 : RESULT_ENSURE_REF(cipher);
78 [ + - ][ + + ]: 32 : RESULT_ENSURE(cipher->set_ktls_info, S2N_ERR_KTLS_UNSUPPORTED_CONN);
79 : :
80 : : /* Renegotiation requires updating the keys, which kTLS doesn't currently support.
81 : : *
82 : : * Setting the renegotiation callback doesn't guarantee that a client will
83 : : * attempt to renegotiate. The callback can also be used to send warning alerts
84 : : * signaling that renegotiation was rejected. However, we can provide applications
85 : : * with a clearer signal earlier by preventing them from enabling ktls on a
86 : : * connection that MIGHT require renegotiation. We can relax this restriction
87 : : * later if necessary.
88 : : */
89 : 30 : bool may_receive_hello_request = s2n_result_is_ok(s2n_client_hello_request_validate(conn));
90 [ + + ][ + + ]: 30 : bool may_renegotiate = may_receive_hello_request && config->renegotiate_request_cb;
91 [ + - ][ + + ]: 30 : RESULT_ENSURE(!may_renegotiate, S2N_ERR_KTLS_RENEG);
92 : :
93 : : /* Prevent kTLS from being enabled on connections that might be serialized.
94 : : *
95 : : * The socket takes over tracking sequence numbers when kTLS is enabled.
96 : : * We would need to call getsockopt to retrieve the current sequence numbers for
97 : : * serialization. This would complicate the serialization implementation so
98 : : * for now, do not support kTLS with serialization.
99 : : */
100 [ + + ][ + - ]: 29 : RESULT_ENSURE(config->serialized_connection_version == S2N_SERIALIZED_CONN_NONE,
101 : 28 : S2N_ERR_KTLS_UNSUPPORTED_CONN);
102 : :
103 : : /* kTLS I/O functionality is managed by s2n-tls. kTLS cannot be enabled if the
104 : : * application sets custom I/O (managed_send_io == false means application has
105 : : * set custom I/O).
106 : : */
107 : 28 : switch (ktls_mode) {
108 [ + + ]: 12 : case S2N_KTLS_MODE_SEND:
109 [ + + ][ + - ]: 12 : RESULT_ENSURE(conn->managed_send_io, S2N_ERR_KTLS_MANAGED_IO);
110 : : /* The output stuffer should be empty before enabling kTLS. */
111 [ + + ][ + - ]: 11 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->out), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
112 : 10 : break;
113 [ + + ]: 16 : case S2N_KTLS_MODE_RECV:
114 [ + + ][ + - ]: 16 : RESULT_ENSURE(conn->managed_recv_io, S2N_ERR_KTLS_MANAGED_IO);
115 : : /* The input stuffers should be empty before enabling kTLS. */
116 [ + - ][ + + ]: 15 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->header_in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
117 [ + + ][ + - ]: 14 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->in), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
118 [ + + ][ + - ]: 13 : RESULT_ENSURE(s2n_stuffer_is_consumed(&conn->buffer_in), S2N_ERR_KTLS_UNSUPPORTED_CONN);
119 : 12 : break;
120 [ - + ]: 12 : default:
121 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_SAFETY);
122 : 0 : break;
123 : 28 : }
124 : :
125 : 22 : return S2N_RESULT_OK;
126 : 28 : }
127 : :
128 : : /* Enabling kTLS preserves the original *io_context; making this functions
129 : : * safe to call even after kTLS has been enabled on the connection.
130 : : *
131 : : * Retrieving fd assumes that the connection is using socket IO and has the
132 : : * send_io_context set. While kTLS overrides IO and essentially disables
133 : : * the socket conn->send function callback, it doesn't modify the
134 : : * send_io_context. */
135 : : S2N_RESULT s2n_ktls_get_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd)
136 : 1506 : {
137 [ - + ][ # # ]: 1506 : RESULT_ENSURE_REF(conn);
138 [ - + ][ # # ]: 1506 : RESULT_ENSURE_REF(fd);
139 : :
140 [ + + ]: 1506 : if (ktls_mode == S2N_KTLS_MODE_RECV) {
141 [ - + ]: 12 : RESULT_GUARD_POSIX(s2n_connection_get_read_fd(conn, fd));
142 [ + - ]: 1494 : } else if (ktls_mode == S2N_KTLS_MODE_SEND) {
143 [ - + ]: 1494 : RESULT_GUARD_POSIX(s2n_connection_get_write_fd(conn, fd));
144 : 1494 : }
145 : 1506 : return S2N_RESULT_OK;
146 : 1506 : }
147 : :
148 : : static S2N_RESULT s2n_ktls_get_io_mode(s2n_ktls_mode ktls_mode, int *tls_tx_rx_mode)
149 : 22 : {
150 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(tls_tx_rx_mode);
151 : :
152 [ + + ]: 22 : if (ktls_mode == S2N_KTLS_MODE_SEND) {
153 : 10 : *tls_tx_rx_mode = S2N_TLS_TX;
154 : 12 : } else {
155 : 12 : *tls_tx_rx_mode = S2N_TLS_RX;
156 : 12 : }
157 : 22 : return S2N_RESULT_OK;
158 : 22 : }
159 : :
160 : : static S2N_RESULT s2n_ktls_crypto_info_init(struct s2n_connection *conn, s2n_ktls_mode ktls_mode,
161 : : struct s2n_ktls_crypto_info *crypto_info)
162 : 22 : {
163 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(conn);
164 : 22 : struct s2n_crypto_parameters *secure = conn->secure;
165 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(secure);
166 : :
167 : : /* In order to avoid storing the encryption keys on the connection, we instead
168 : : * regenerate them when required by ktls.
169 : : *
170 : : * s2n_key_material also includes an IV, but we should use the IV stored
171 : : * on the connection instead. Some record algorithms (like CBC) mutate the
172 : : * "implicit_iv" when writing records, so the IV may change after generation.
173 : : */
174 : 22 : struct s2n_key_material key_material = { 0 };
175 : :
176 : 22 : bool is_sending_key = (ktls_mode == S2N_KTLS_MODE_SEND);
177 [ + + ]: 22 : s2n_mode key_mode = (is_sending_key) ? conn->mode : S2N_PEER_MODE(conn->mode);
178 : :
179 : 22 : switch (conn->actual_protocol_version) {
180 [ + + ]: 21 : case S2N_TLS12:
181 [ - + ]: 21 : RESULT_GUARD(s2n_prf_generate_key_material(conn, &key_material));
182 : 21 : break;
183 [ + + ]: 21 : case S2N_TLS13:
184 [ - + ]: 1 : RESULT_GUARD(s2n_tls13_key_schedule_generate_key_material(
185 : 1 : conn, key_mode, &key_material));
186 : 1 : break;
187 [ - + ]: 1 : default:
188 [ # # ]: 0 : RESULT_BAIL(S2N_ERR_KTLS_UNSUPPORTED_CONN);
189 : 22 : }
190 : :
191 : 22 : struct s2n_ktls_crypto_info_inputs inputs = { 0 };
192 [ + + ]: 22 : if (key_mode == S2N_CLIENT) {
193 : 11 : inputs.key = key_material.client_key;
194 [ - + ]: 11 : RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
195 : 11 : secure->client_implicit_iv, sizeof(secure->client_implicit_iv)));
196 : 11 : } else {
197 : 11 : inputs.key = key_material.server_key;
198 [ - + ]: 11 : RESULT_GUARD_POSIX(s2n_blob_init(&inputs.iv,
199 : 11 : secure->server_implicit_iv, sizeof(secure->server_implicit_iv)));
200 : 11 : }
201 [ - + ]: 22 : RESULT_GUARD(s2n_connection_get_sequence_number(conn, key_mode, &inputs.seq));
202 : :
203 : 22 : const struct s2n_cipher *cipher = NULL;
204 [ - + ]: 22 : RESULT_GUARD(s2n_connection_get_secure_cipher(conn, &cipher));
205 [ - + ][ # # ]: 22 : RESULT_ENSURE_REF(cipher);
206 [ # # ][ - + ]: 22 : RESULT_ENSURE_REF(cipher->set_ktls_info);
207 [ - + ]: 22 : RESULT_GUARD(cipher->set_ktls_info(&inputs, crypto_info));
208 : 22 : return S2N_RESULT_OK;
209 : 22 : }
210 : :
211 : : /* This method intentionally returns void because it may NOT perform any fallible
212 : : * operations. See s2n_connection_ktls_enable.
213 : : */
214 : : void s2n_ktls_configure_connection(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
215 : 41 : {
216 [ - + ]: 41 : if (conn == NULL) {
217 : 0 : return;
218 : 0 : }
219 [ + + ]: 41 : if (ktls_mode == S2N_KTLS_MODE_SEND) {
220 : 16 : conn->ktls_send_enabled = true;
221 : 16 : conn->send = s2n_ktls_send_cb;
222 : 25 : } else {
223 : 25 : conn->ktls_recv_enabled = true;
224 : 25 : conn->recv = s2n_ktls_disabled_read;
225 : 25 : }
226 : 41 : }
227 : :
228 : : static S2N_RESULT s2n_connection_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
229 : 37 : {
230 [ # # ][ - + ]: 37 : RESULT_ENSURE_REF(conn);
231 [ + + ]: 37 : RESULT_GUARD(s2n_ktls_validate(conn, ktls_mode));
232 : :
233 : 22 : int fd = 0;
234 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_get_file_descriptor(conn, ktls_mode, &fd));
235 : :
236 : : /* This call doesn't actually enable ktls or modify the IO behavior of the socket.
237 : : * Instead, this is just a prerequisite for calling setsockopt with SOL_TLS.
238 : : *
239 : : * We intentionally ignore the result of this call. It may fail because ktls
240 : : * is not supported, but it might also fail because ktls has already been enabled
241 : : * for the socket. If SOL_TLS isn't enabled on the socket, our next call to
242 : : * setsockopt with SOL_TLS will also fail, and we DO check that result.
243 : : */
244 : 22 : s2n_setsockopt(fd, S2N_SOL_TCP, S2N_TCP_ULP, S2N_TLS_ULP_NAME, S2N_TLS_ULP_NAME_SIZE);
245 : :
246 : 22 : int tls_tx_rx_mode = 0;
247 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_get_io_mode(ktls_mode, &tls_tx_rx_mode));
248 : :
249 : 22 : struct s2n_ktls_crypto_info crypto_info = { 0 };
250 [ - + ]: 22 : RESULT_GUARD(s2n_ktls_crypto_info_init(conn, ktls_mode, &crypto_info));
251 : :
252 : : /* If this call succeeds, then ktls is enabled for that io mode and will be offloaded */
253 : 22 : int ret = s2n_setsockopt(fd, S2N_SOL_TLS, tls_tx_rx_mode, crypto_info.value.data, crypto_info.value.size);
254 [ + - ][ + + ]: 22 : RESULT_ENSURE(ret == 0, S2N_ERR_KTLS_ENABLE);
255 : :
256 : : /* At this point, ktls is enabled on the socket for the requested IO mode.
257 : : * No further fallible operations may be performed, or else the caller may
258 : : * incorrectly assume that enabling ktls failed and they should therefore
259 : : * fall back to using application layer TLS.
260 : : *
261 : : * That means no calls to RESULT_ENSURE, RESULT_GUARD, etc. after this point.
262 : : */
263 : :
264 : 18 : s2n_ktls_configure_connection(conn, ktls_mode);
265 : 18 : return S2N_RESULT_OK;
266 : 22 : }
267 : :
268 : : int s2n_connection_ktls_enable_send(struct s2n_connection *conn)
269 : 18 : {
270 [ - + ][ # # ]: 18 : POSIX_ENSURE_REF(conn);
271 : :
272 : : /* If already enabled then return success */
273 [ + + ]: 18 : if (conn->ktls_send_enabled) {
274 : 1 : return S2N_SUCCESS;
275 : 1 : }
276 : :
277 [ + + ]: 17 : POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_SEND));
278 : 8 : return S2N_SUCCESS;
279 : 17 : }
280 : :
281 : : int s2n_connection_ktls_enable_recv(struct s2n_connection *conn)
282 : 21 : {
283 [ # # ][ - + ]: 21 : POSIX_ENSURE_REF(conn);
284 : :
285 : : /* If already enabled then return success */
286 [ + + ]: 21 : if (conn->ktls_recv_enabled) {
287 : 1 : return S2N_SUCCESS;
288 : 1 : }
289 : :
290 [ + + ]: 20 : POSIX_GUARD_RESULT(s2n_connection_ktls_enable(conn, S2N_KTLS_MODE_RECV));
291 : 10 : return S2N_SUCCESS;
292 : 20 : }
293 : :
294 : : int s2n_config_ktls_enable_unsafe_tls13(struct s2n_config *config)
295 : 5 : {
296 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(config);
297 : 4 : config->ktls_tls13_enabled = true;
298 : 4 : return S2N_SUCCESS;
299 : 5 : }
|