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_renegotiate.h"
17 : :
18 : : #include "error/s2n_errno.h"
19 : : #include "stuffer/s2n_stuffer.h"
20 : : #include "tls/s2n_connection.h"
21 : : #include "utils/s2n_safety.h"
22 : :
23 : : /* We don't want to introduce a new blocked status for renegotiation
24 : : * because that would potentially require applications to update their
25 : : * blocked status handling logic for no reason.
26 : : *
27 : : * It is impossible to use both early data and renegotiation for the same handshake,
28 : : * and both are just application data received during the handshake.
29 : : * Therefore, we will alias S2N_BLOCKED_ON_EARLY_DATA for reuse with renegotiation.
30 : : */
31 : : const s2n_blocked_status S2N_BLOCKED_ON_APPLICATION_DATA = S2N_BLOCKED_ON_EARLY_DATA;
32 : :
33 : : S2N_RESULT s2n_renegotiate_validate(struct s2n_connection *conn)
34 : 103 : {
35 [ - + ][ # # ]: 103 : RESULT_ENSURE_REF(conn);
36 [ - + ][ # # ]: 103 : RESULT_ENSURE(conn->mode == S2N_CLIENT, S2N_ERR_NO_RENEGOTIATION);
37 [ - + ][ # # ]: 103 : RESULT_ENSURE(conn->secure_renegotiation, S2N_ERR_NO_RENEGOTIATION);
38 [ - + ][ # # ]: 103 : RESULT_ENSURE(conn->handshake.renegotiation, S2N_ERR_INVALID_STATE);
39 [ - + ][ # # ]: 103 : RESULT_ENSURE(!conn->ktls_send_enabled, S2N_ERR_KTLS_RENEG);
40 [ - + ][ # # ]: 103 : RESULT_ENSURE(!conn->ktls_recv_enabled, S2N_ERR_KTLS_RENEG);
41 : 103 : return S2N_RESULT_OK;
42 : 103 : }
43 : :
44 : : /*
45 : : * Prepare a connection to be reused for a second handshake.
46 : : *
47 : : * s2n-tls was not originally designed to support renegotiation.
48 : : * s2n_connection is a very large structure with configuration fields set by the application
49 : : * mixed in with internal state fields set by the handshake.
50 : : * Ensuring all existing internal state fields (and any new fields added) are safe to reuse for
51 : : * a renegotiated handshake would be extremely prone to errors.
52 : : * For safety, we instead wipe the entire connection and only restore fields we know we need
53 : : * in order to continue sending and receiving encrypted data.
54 : : *
55 : : * Any configuration fields set by the application will need to be set by the application again.
56 : : */
57 : : int s2n_renegotiate_wipe(struct s2n_connection *conn)
58 : 525 : {
59 [ - + ][ # # ]: 525 : POSIX_ENSURE_REF(conn);
60 : :
61 : : /* We use this method to reset both clients and servers when testing.
62 : : * However, outside of tests, it should only be called for client connections
63 : : * because we only support renegotiation for clients.
64 : : */
65 [ # # ][ + + ]: 525 : POSIX_ENSURE(conn->mode == S2N_CLIENT || s2n_in_unit_test(), S2N_ERR_NO_RENEGOTIATION);
[ + - ]
66 : :
67 : : /* Best effort check for pending input or output data.
68 : : * This method should not be called until the application has stopped sending and receiving.
69 : : * Saving partial read or parital write state would complicate this problem.
70 : : */
71 [ + + ][ + - ]: 525 : POSIX_ENSURE(s2n_stuffer_data_available(&conn->header_in) == 0, S2N_ERR_INVALID_STATE);
72 [ - + ][ # # ]: 524 : POSIX_ENSURE(s2n_stuffer_data_available(&conn->in) == 0, S2N_ERR_INVALID_STATE);
73 [ + + ][ + - ]: 524 : POSIX_ENSURE(s2n_stuffer_data_available(&conn->out) == 0, S2N_ERR_INVALID_STATE);
74 : :
75 : : /* buffer_in might contain data needed to read the next records. */
76 : 523 : DEFER_CLEANUP(struct s2n_stuffer buffer_in = conn->buffer_in, s2n_stuffer_free);
77 : 523 : conn->buffer_in = (struct s2n_stuffer){ 0 };
78 [ - + ]: 523 : POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->buffer_in, 0));
79 : :
80 : : /* Save the crypto parameters.
81 : : * We need to continue encrypting / decrypting with the old secure parameters.
82 : : */
83 : 523 : DEFER_CLEANUP(struct s2n_crypto_parameters *secure_crypto_params = conn->secure,
84 : 523 : s2n_crypto_parameters_free);
85 : 523 : conn->secure = NULL;
86 : :
87 : : /* Save the fragment length so we continue properly fragmenting our records
88 : : * until a new fragment length is chosen.
89 : : */
90 : 523 : uint16_t max_frag_len = conn->max_outgoing_fragment_length;
91 : :
92 : : /* Save the protocol versions.
93 : : * Various checks when sending and receiving records rely on the protocol version. */
94 : 523 : uint8_t actual_protocol_version = conn->actual_protocol_version;
95 : 523 : uint8_t server_protocol_version = conn->server_protocol_version;
96 : 523 : uint8_t client_protocol_version = conn->client_protocol_version;
97 [ + + ][ + - ]: 523 : POSIX_ENSURE(actual_protocol_version < S2N_TLS13, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
98 : :
99 : : /* Save byte tracking.
100 : : * This isn't strictly necessary, but potentially useful. */
101 : 522 : uint64_t wire_bytes_in = conn->wire_bytes_in;
102 : 522 : uint64_t wire_bytes_out = conn->wire_bytes_out;
103 : :
104 : : /* Save io settings */
105 : 522 : bool send_managed = conn->managed_send_io;
106 : 522 : s2n_send_fn *send_fn = conn->send;
107 : 522 : void *send_ctx = conn->send_io_context;
108 : 522 : bool recv_managed = conn->managed_recv_io;
109 : 522 : s2n_recv_fn *recv_fn = conn->recv;
110 : 522 : void *recv_ctx = conn->recv_io_context;
111 : : /* Treat IO as unmanaged, since we don't want to clean it up yet */
112 : 522 : conn->managed_send_io = false;
113 : 522 : conn->managed_recv_io = false;
114 : :
115 : : /* Save the secure_renegotiation flag.
116 : : * This flag should always be true, since we don't support insecure renegotiation,
117 : : * but copying its value seems safer than just setting it to 'true'.
118 : : */
119 : 522 : bool secure_renegotiation = conn->secure_renegotiation;
120 [ + + ][ + - ]: 522 : POSIX_ENSURE(secure_renegotiation, S2N_ERR_NO_RENEGOTIATION);
121 : :
122 : : /* Save the finished data.
123 : : * This is required for the renegotiate_info extension on the new handshake.
124 : : */
125 : 521 : uint8_t finished_len = conn->handshake.finished_len;
126 : 521 : uint8_t client_finished[sizeof(conn->handshake.client_finished)] = { 0 };
127 [ # # ][ - + ]: 521 : POSIX_CHECKED_MEMCPY(client_finished, conn->handshake.client_finished, finished_len);
[ + + ]
128 : 521 : uint8_t server_finished[sizeof(conn->handshake.server_finished)] = { 0 };
129 [ - + ][ # # ]: 521 : POSIX_CHECKED_MEMCPY(server_finished, conn->handshake.server_finished, finished_len);
[ + + ]
130 : :
131 [ - + ]: 521 : POSIX_GUARD(s2n_connection_wipe(conn));
132 : :
133 : : /* Setup the new crypto parameters.
134 : : * The new handshake will negotiate new secure crypto parameters,
135 : : * so the current secure crypto parameters become the initial crypto parameters.
136 : : */
137 [ - + ]: 521 : POSIX_GUARD_RESULT(s2n_crypto_parameters_free(&conn->initial));
138 : 521 : conn->initial = secure_crypto_params;
139 : 521 : ZERO_TO_DISABLE_DEFER_CLEANUP(secure_crypto_params);
140 : 521 : conn->client = conn->initial;
141 : 521 : conn->server = conn->initial;
142 : :
143 : : /* Restore saved values */
144 [ - + ]: 521 : POSIX_GUARD_RESULT(s2n_connection_set_max_fragment_length(conn, max_frag_len));
145 [ - + ][ # # ]: 521 : POSIX_CHECKED_MEMCPY(conn->handshake.client_finished, client_finished, finished_len);
[ + + ]
146 [ - + ][ # # ]: 521 : POSIX_CHECKED_MEMCPY(conn->handshake.server_finished, server_finished, finished_len);
[ + + ]
147 : 521 : conn->handshake.finished_len = finished_len;
148 : 521 : conn->actual_protocol_version = actual_protocol_version;
149 : 521 : conn->server_protocol_version = server_protocol_version;
150 : 521 : conn->client_protocol_version = client_protocol_version;
151 : 521 : conn->wire_bytes_in = wire_bytes_in;
152 : 521 : conn->wire_bytes_out = wire_bytes_out;
153 : 521 : conn->managed_send_io = send_managed;
154 : 521 : conn->send = send_fn;
155 : 521 : conn->send_io_context = send_ctx;
156 : 521 : conn->managed_recv_io = recv_managed;
157 : 521 : conn->recv = recv_fn;
158 : 521 : conn->recv_io_context = recv_ctx;
159 : 521 : conn->secure_renegotiation = secure_renegotiation;
160 : 521 : conn->buffer_in = buffer_in;
161 : 521 : ZERO_TO_DISABLE_DEFER_CLEANUP(buffer_in);
162 : :
163 : 521 : conn->handshake.renegotiation = true;
164 : 521 : return S2N_SUCCESS;
165 : 521 : }
166 : :
167 : : static S2N_RESULT s2n_renegotiate_read_app_data(struct s2n_connection *conn, uint8_t *app_data_buf, ssize_t app_data_buf_size,
168 : : ssize_t *app_data_size, s2n_blocked_status *blocked)
169 : 21 : {
170 [ - + ][ # # ]: 21 : RESULT_ENSURE_REF(blocked);
171 : :
172 : 21 : ssize_t r = s2n_recv(conn, app_data_buf, app_data_buf_size, blocked);
173 [ - + ]: 21 : RESULT_GUARD_POSIX(r);
174 : 21 : *app_data_size = r;
175 : :
176 : 21 : *blocked = S2N_BLOCKED_ON_APPLICATION_DATA;
177 [ + - ]: 21 : RESULT_BAIL(S2N_ERR_APP_DATA_BLOCKED);
178 : 21 : }
179 : :
180 : : int s2n_renegotiate(struct s2n_connection *conn, uint8_t *app_data_buf, ssize_t app_data_buf_size,
181 : : ssize_t *app_data_size, s2n_blocked_status *blocked)
182 : 78 : {
183 [ - + ]: 78 : POSIX_GUARD_RESULT(s2n_renegotiate_validate(conn));
184 : :
185 [ - + ][ # # ]: 78 : POSIX_ENSURE_REF(app_data_size);
186 : 78 : *app_data_size = 0;
187 : :
188 : : /* If there is outstanding application data, pass it back to the application.
189 : : * We can't read the next handshake record until we drain the buffer.
190 : : */
191 [ + + ]: 78 : if (s2n_peek(conn) > 0) {
192 [ + - ]: 1 : POSIX_GUARD_RESULT(s2n_renegotiate_read_app_data(conn,
193 : 1 : app_data_buf, app_data_buf_size, app_data_size, blocked));
194 : 1 : }
195 : :
196 : 77 : int result = s2n_negotiate(conn, blocked);
197 : :
198 : : /* If we encounter application data while reading handshake records,
199 : : * pass it back to the application.
200 : : */
201 [ + + ][ + + ]: 77 : if (result != S2N_SUCCESS && s2n_errno == S2N_ERR_APP_DATA_BLOCKED) {
202 [ + - ]: 20 : POSIX_GUARD_RESULT(s2n_renegotiate_read_app_data(conn,
203 : 20 : app_data_buf, app_data_buf_size, app_data_size, blocked));
204 : 20 : }
205 : :
206 : 57 : return result;
207 : 77 : }
|