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 "crypto/s2n_tls13_keys.h"
17 : : #include "tls/extensions/s2n_extension_type.h"
18 : : #include "tls/s2n_handshake.h"
19 : : #include "tls/s2n_tls.h"
20 : : #include "tls/s2n_tls13_handshake.h"
21 : : #include "tls/s2n_tls13_secrets.h"
22 : : #include "utils/s2n_array.h"
23 : : #include "utils/s2n_mem.h"
24 : : #include "utils/s2n_safety.h"
25 : :
26 : : S2N_RESULT s2n_psk_init(struct s2n_psk *psk, s2n_psk_type type)
27 : 1817 : {
28 [ + + ][ + - ]: 1817 : RESULT_ENSURE_MUT(psk);
29 : :
30 [ - + ][ # # ]: 1816 : RESULT_CHECKED_MEMSET(psk, 0, sizeof(struct s2n_psk));
[ + - ]
31 : 1816 : psk->hmac_alg = S2N_HMAC_SHA256;
32 : 1816 : psk->type = type;
33 : :
34 : 1816 : return S2N_RESULT_OK;
35 : 1816 : }
36 : :
37 : : struct s2n_psk *s2n_external_psk_new()
38 : 163 : {
39 : 163 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
40 [ - + ]: 163 : PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_psk)));
41 : :
42 : 163 : struct s2n_psk *psk = (struct s2n_psk *) (void *) mem.data;
43 [ - + ]: 163 : PTR_GUARD_RESULT(s2n_psk_init(psk, S2N_PSK_TYPE_EXTERNAL));
44 : :
45 : 163 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
46 : 163 : return psk;
47 : 163 : }
48 : :
49 : : int s2n_psk_set_identity(struct s2n_psk *psk, const uint8_t *identity, uint16_t identity_size)
50 : 3194 : {
51 [ + + ][ + - ]: 3194 : POSIX_ENSURE_REF(psk);
52 [ + + ][ + - ]: 3193 : POSIX_ENSURE_REF(identity);
53 [ + + ][ + - ]: 3191 : POSIX_ENSURE(identity_size != 0, S2N_ERR_INVALID_ARGUMENT);
54 : :
55 [ - + ]: 3190 : POSIX_GUARD(s2n_realloc(&psk->identity, identity_size));
56 [ - + ][ # # ]: 3190 : POSIX_CHECKED_MEMCPY(psk->identity.data, identity, identity_size);
[ + - ]
57 : :
58 : 3190 : return S2N_SUCCESS;
59 : 3190 : }
60 : :
61 : : int s2n_psk_set_secret(struct s2n_psk *psk, const uint8_t *secret, uint16_t secret_size)
62 : 1810 : {
63 [ + - ][ + + ]: 1810 : POSIX_ENSURE_REF(psk);
64 [ + - ][ + + ]: 1809 : POSIX_ENSURE_REF(secret);
65 [ + + ][ + - ]: 1807 : POSIX_ENSURE(secret_size != 0, S2N_ERR_INVALID_ARGUMENT);
66 : :
67 : : /* There are a number of application level errors that might result in an
68 : : * all-zero secret accidentally getting used. Error if that happens.
69 : : */
70 : 1806 : bool secret_is_all_zero = true;
71 [ + + ]: 33478 : for (uint16_t i = 0; i < secret_size; i++) {
72 [ + + ][ + + ]: 31672 : secret_is_all_zero = secret_is_all_zero && secret[i] == 0;
73 : 31672 : }
74 [ + - ][ + + ]: 1806 : POSIX_ENSURE(!secret_is_all_zero, S2N_ERR_INVALID_ARGUMENT);
75 : :
76 [ - + ]: 1805 : POSIX_GUARD(s2n_realloc(&psk->secret, secret_size));
77 [ - + ][ # # ]: 1805 : POSIX_CHECKED_MEMCPY(psk->secret.data, secret, secret_size);
[ + - ]
78 : :
79 : 1805 : return S2N_SUCCESS;
80 : 1805 : }
81 : :
82 : : S2N_RESULT s2n_psk_clone(struct s2n_psk *new_psk, struct s2n_psk *original_psk)
83 : 1339 : {
84 [ - + ]: 1339 : if (original_psk == NULL) {
85 : 0 : return S2N_RESULT_OK;
86 : 0 : }
87 [ - + ][ # # ]: 1339 : RESULT_ENSURE_REF(new_psk);
88 : :
89 : 1339 : struct s2n_psk psk_copy = *new_psk;
90 : :
91 : : /* Copy all fields from the old_config EXCEPT the blobs, which we need to reallocate. */
92 : 1339 : *new_psk = *original_psk;
93 : 1339 : new_psk->identity = psk_copy.identity;
94 : 1339 : new_psk->secret = psk_copy.secret;
95 : 1339 : new_psk->early_secret = psk_copy.early_secret;
96 : 1339 : new_psk->early_data_config = psk_copy.early_data_config;
97 : :
98 : : /* Clone / realloc blobs */
99 [ + + ]: 1339 : RESULT_GUARD_POSIX(s2n_psk_set_identity(new_psk, original_psk->identity.data, original_psk->identity.size));
100 [ + + ]: 1338 : RESULT_GUARD_POSIX(s2n_psk_set_secret(new_psk, original_psk->secret.data, original_psk->secret.size));
101 [ - + ]: 1337 : RESULT_GUARD_POSIX(s2n_realloc(&new_psk->early_secret, original_psk->early_secret.size));
102 [ - + ][ # # ]: 1337 : RESULT_CHECKED_MEMCPY(new_psk->early_secret.data, original_psk->early_secret.data, original_psk->early_secret.size);
[ + + ]
103 [ - + ]: 1337 : RESULT_GUARD(s2n_early_data_config_clone(new_psk, &original_psk->early_data_config));
104 : :
105 : 1337 : return S2N_RESULT_OK;
106 : 1337 : }
107 : :
108 : : S2N_CLEANUP_RESULT s2n_psk_wipe(struct s2n_psk *psk)
109 : 4657 : {
110 [ + + ]: 4657 : if (psk == NULL) {
111 : 90 : return S2N_RESULT_OK;
112 : 90 : }
113 : :
114 [ - + ]: 4567 : RESULT_GUARD_POSIX(s2n_free(&psk->early_secret));
115 [ - + ]: 4567 : RESULT_GUARD_POSIX(s2n_free(&psk->identity));
116 [ - + ]: 4567 : RESULT_GUARD_POSIX(s2n_free(&psk->secret));
117 [ - + ]: 4567 : RESULT_GUARD(s2n_early_data_config_free(&psk->early_data_config));
118 : :
119 : 4567 : return S2N_RESULT_OK;
120 : 4567 : }
121 : :
122 : : int s2n_psk_free(struct s2n_psk **psk)
123 : 254 : {
124 [ + + ]: 254 : if (psk == NULL) {
125 : 1 : return S2N_SUCCESS;
126 : 1 : }
127 [ - + ]: 253 : POSIX_GUARD_RESULT(s2n_psk_wipe(*psk));
128 : 253 : return s2n_free_object((uint8_t **) psk, sizeof(struct s2n_psk));
129 : 253 : }
130 : :
131 : : S2N_RESULT s2n_psk_parameters_init(struct s2n_psk_parameters *params)
132 : 6970933 : {
133 [ + - ][ + + ]: 6970933 : RESULT_ENSURE_REF(params);
134 [ - + ][ # # ]: 6970932 : RESULT_CHECKED_MEMSET(params, 0, sizeof(struct s2n_psk_parameters));
[ + - ]
135 [ - + ]: 6970932 : RESULT_GUARD(s2n_array_init(¶ms->psk_list, sizeof(struct s2n_psk)));
136 : 6970932 : return S2N_RESULT_OK;
137 : 6970932 : }
138 : :
139 : : static S2N_RESULT s2n_psk_offered_psk_size(struct s2n_psk *psk, uint32_t *size)
140 : 691 : {
141 : 691 : *size = sizeof(uint16_t) /* identity size */
142 : 691 : + sizeof(uint32_t) /* obfuscated ticket age */
143 : 691 : + sizeof(uint8_t); /* binder size */
144 : :
145 [ - + ]: 691 : RESULT_GUARD_POSIX(s2n_add_overflow(*size, psk->identity.size, size));
146 : :
147 : 691 : uint8_t binder_size = 0;
148 [ - + ]: 691 : RESULT_GUARD_POSIX(s2n_hmac_digest_size(psk->hmac_alg, &binder_size));
149 [ - + ]: 691 : RESULT_GUARD_POSIX(s2n_add_overflow(*size, binder_size, size));
150 : :
151 : 691 : return S2N_RESULT_OK;
152 : 691 : }
153 : :
154 : : S2N_RESULT s2n_psk_parameters_offered_psks_size(struct s2n_psk_parameters *params, uint32_t *size)
155 : 1994 : {
156 [ - + ][ # # ]: 1994 : RESULT_ENSURE_REF(params);
157 [ - + ][ # # ]: 1994 : RESULT_ENSURE_REF(size);
158 : :
159 : 1994 : *size = sizeof(uint16_t) /* identity list size */
160 : 1994 : + sizeof(uint16_t) /* binder list size */;
161 : :
162 [ + + ]: 864654 : for (uint32_t i = 0; i < params->psk_list.len; i++) {
163 : 862660 : struct s2n_psk *psk = NULL;
164 [ - + ]: 862660 : RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void **) &psk));
165 [ # # ][ - + ]: 862660 : RESULT_ENSURE_REF(psk);
166 : :
167 : 862660 : uint32_t psk_size = 0;
168 [ - + ]: 862660 : RESULT_GUARD(s2n_psk_offered_psk_size(psk, &psk_size));
169 [ - + ]: 862660 : RESULT_GUARD_POSIX(s2n_add_overflow(*size, psk_size, size));
170 : 862660 : }
171 : 1994 : return S2N_RESULT_OK;
172 : 1994 : }
173 : :
174 : : S2N_CLEANUP_RESULT s2n_psk_parameters_wipe(struct s2n_psk_parameters *params)
175 : 3548931 : {
176 [ + + ][ + - ]: 3548931 : RESULT_ENSURE_REF(params);
177 : :
178 [ + + ]: 3551736 : for (size_t i = 0; i < params->psk_list.len; i++) {
179 : 2806 : struct s2n_psk *psk = NULL;
180 [ - + ]: 2806 : RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void **) &psk));
181 [ - + ]: 2806 : RESULT_GUARD(s2n_psk_wipe(psk));
182 : 2806 : }
183 [ - + ]: 3548930 : RESULT_GUARD_POSIX(s2n_free(¶ms->psk_list.mem));
184 [ - + ]: 3548930 : RESULT_GUARD(s2n_psk_parameters_init(params));
185 : :
186 : 3548930 : return S2N_RESULT_OK;
187 : 3548930 : }
188 : :
189 : : S2N_CLEANUP_RESULT s2n_psk_parameters_wipe_secrets(struct s2n_psk_parameters *params)
190 : 9477 : {
191 [ + + ][ + - ]: 9477 : RESULT_ENSURE_REF(params);
192 : :
193 [ + + ]: 10710 : for (size_t i = 0; i < params->psk_list.len; i++) {
194 : 1234 : struct s2n_psk *psk = NULL;
195 [ - + ]: 1234 : RESULT_GUARD(s2n_array_get(¶ms->psk_list, i, (void **) &psk));
196 [ # # ][ - + ]: 1234 : RESULT_ENSURE_REF(psk);
197 [ - + ]: 1234 : RESULT_GUARD_POSIX(s2n_free(&psk->early_secret));
198 [ - + ]: 1234 : RESULT_GUARD_POSIX(s2n_free(&psk->secret));
199 : 1234 : }
200 : :
201 : 9476 : return S2N_RESULT_OK;
202 : 9476 : }
203 : :
204 : : bool s2n_offered_psk_list_has_next(struct s2n_offered_psk_list *psk_list)
205 : 3643 : {
206 [ + + ][ + + ]: 3643 : return psk_list != NULL && s2n_stuffer_data_available(&psk_list->wire_data) > 0;
207 : 3643 : }
208 : :
209 : : S2N_RESULT s2n_offered_psk_list_read_next(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk)
210 : 1300 : {
211 [ + + ][ + - ]: 1300 : RESULT_ENSURE_REF(psk_list);
212 [ + - ][ + + ]: 1299 : RESULT_ENSURE_REF(psk_list->conn);
213 [ # # ][ - + ]: 1296 : RESULT_ENSURE_MUT(psk);
214 : :
215 : 1296 : uint16_t identity_size = 0;
216 [ - + ]: 1296 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&psk_list->wire_data, &identity_size));
217 [ - + ][ # # ]: 1296 : RESULT_ENSURE_GT(identity_size, 0);
218 : :
219 : 1296 : uint8_t *identity_data = NULL;
220 : 1296 : identity_data = s2n_stuffer_raw_read(&psk_list->wire_data, identity_size);
221 [ # # ][ - + ]: 1296 : RESULT_ENSURE_REF(identity_data);
222 : :
223 : : /**
224 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
225 : : *# For identities established externally, an obfuscated_ticket_age of 0 SHOULD be
226 : : *# used, and servers MUST ignore the value.
227 : : */
228 [ + + ]: 1296 : if (psk_list->conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) {
229 [ - + ]: 1160 : RESULT_GUARD_POSIX(s2n_stuffer_skip_read(&psk_list->wire_data, sizeof(uint32_t)));
230 : 1160 : } else {
231 [ - + ]: 136 : RESULT_GUARD_POSIX(s2n_stuffer_read_uint32(&psk_list->wire_data, &psk->obfuscated_ticket_age));
232 : 136 : }
233 : :
234 [ - + ]: 1296 : RESULT_GUARD_POSIX(s2n_blob_init(&psk->identity, identity_data, identity_size));
235 : 1296 : psk->wire_index = psk_list->wire_index;
236 : :
237 [ - + ][ # # ]: 1296 : RESULT_ENSURE(psk_list->wire_index < UINT16_MAX, S2N_ERR_INTEGER_OVERFLOW);
238 : 1296 : psk_list->wire_index++;
239 : 1296 : return S2N_RESULT_OK;
240 : 1296 : }
241 : :
242 : : int s2n_offered_psk_list_next(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk)
243 : 1304 : {
244 [ + + ][ + - ]: 1304 : POSIX_ENSURE_REF(psk_list);
245 [ + - ][ + + ]: 1303 : POSIX_ENSURE_REF(psk);
246 : 1302 : *psk = (struct s2n_offered_psk){ 0 };
247 [ + - ][ + + ]: 1302 : POSIX_ENSURE(s2n_offered_psk_list_has_next(psk_list), S2N_ERR_STUFFER_OUT_OF_DATA);
248 [ + + ][ + - ]: 1296 : POSIX_ENSURE(s2n_result_is_ok(s2n_offered_psk_list_read_next(psk_list, psk)), S2N_ERR_BAD_MESSAGE);
249 : 1294 : return S2N_SUCCESS;
250 : 1296 : }
251 : :
252 : : int s2n_offered_psk_list_reread(struct s2n_offered_psk_list *psk_list)
253 : 1042 : {
254 [ + + ][ + - ]: 1042 : POSIX_ENSURE_REF(psk_list);
255 : 1041 : psk_list->wire_index = 0;
256 : 1041 : return s2n_stuffer_reread(&psk_list->wire_data);
257 : 1042 : }
258 : :
259 : : /* Match a PSK identity received from the client against the server's known PSK identities.
260 : : * This method compares a single client identity to all server identities.
261 : : *
262 : : * While both the client's offered identities and whether a match was found are public, we should make an attempt
263 : : * to keep the server's known identities a secret. We will make comparisons to the server's identities constant
264 : : * time (to hide partial matches) and not end the search early when a match is found (to hide the ordering).
265 : : *
266 : : * Keeping these comparisons constant time is not high priority. There's no known attack using these timings,
267 : : * and an attacker could probably guess the server's known identities just by observing the public identities
268 : : * sent by clients.
269 : : */
270 : : static S2N_RESULT s2n_match_psk_identity(struct s2n_array *known_psks, const struct s2n_blob *wire_identity,
271 : : struct s2n_psk **match)
272 : 121 : {
273 [ - + ][ # # ]: 121 : RESULT_ENSURE_REF(match);
274 [ - + ][ # # ]: 121 : RESULT_ENSURE_REF(wire_identity);
275 [ # # ][ - + ]: 121 : RESULT_ENSURE_REF(known_psks);
276 : 121 : *match = NULL;
277 [ + + ]: 240 : for (size_t i = 0; i < known_psks->len; i++) {
278 : 119 : struct s2n_psk *psk = NULL;
279 [ - + ]: 119 : RESULT_GUARD(s2n_array_get(known_psks, i, (void **) &psk));
280 [ - + ][ # # ]: 119 : RESULT_ENSURE_REF(psk);
281 [ - + ][ # # ]: 119 : RESULT_ENSURE_REF(psk->identity.data);
282 [ - + ][ # # ]: 119 : RESULT_ENSURE_REF(wire_identity->data);
283 [ - + ]: 119 : uint32_t compare_size = S2N_MIN(wire_identity->size, psk->identity.size);
284 [ + + ]: 119 : if (s2n_constant_time_equals(psk->identity.data, wire_identity->data, compare_size)
285 : 119 : & (psk->identity.size == wire_identity->size) & (!*match)) {
286 : 116 : *match = psk;
287 : 116 : }
288 : 119 : }
289 : 121 : return S2N_RESULT_OK;
290 : 121 : }
291 : :
292 : : /**
293 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.10
294 : : *# For PSKs provisioned via NewSessionTicket, a server MUST validate
295 : : *# that the ticket age for the selected PSK identity (computed by
296 : : *# subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age
297 : : *# modulo 2^32) is within a small tolerance of the time since the ticket
298 : : *# was issued (see Section 8).
299 : : **/
300 : : static S2N_RESULT s2n_validate_ticket_lifetime(struct s2n_connection *conn, uint32_t obfuscated_ticket_age, uint32_t ticket_age_add)
301 : 116 : {
302 [ - + ][ # # ]: 116 : RESULT_ENSURE_REF(conn);
303 : :
304 [ + + ]: 116 : if (conn->psk_params.type == S2N_PSK_TYPE_EXTERNAL) {
305 : 2 : return S2N_RESULT_OK;
306 : 2 : }
307 : :
308 : : /* Subtract the ticket_age_add value from the ticket age in milliseconds. The resulting uint32_t value
309 : : * may wrap, resulting in the modulo 2^32 operation. */
310 : 114 : uint32_t ticket_age_in_millis = obfuscated_ticket_age - ticket_age_add;
311 : 114 : uint32_t session_lifetime_in_millis = conn->config->session_state_lifetime_in_nanos / ONE_MILLISEC_IN_NANOS;
312 [ + - ][ + + ]: 114 : RESULT_ENSURE(ticket_age_in_millis < session_lifetime_in_millis, S2N_ERR_INVALID_SESSION_TICKET);
313 : :
314 : 113 : return S2N_RESULT_OK;
315 : 114 : }
316 : :
317 : : int s2n_offered_psk_list_choose_psk(struct s2n_offered_psk_list *psk_list, struct s2n_offered_psk *psk)
318 : 142 : {
319 [ + + ][ + - ]: 142 : POSIX_ENSURE_REF(psk_list);
320 [ # # ][ - + ]: 141 : POSIX_ENSURE_REF(psk_list->conn);
321 : :
322 : 141 : struct s2n_psk_parameters *psk_params = &psk_list->conn->psk_params;
323 : 141 : struct s2n_stuffer ticket_stuffer = { 0 };
324 : :
325 [ + + ]: 141 : if (!psk) {
326 : 1 : psk_params->chosen_psk = NULL;
327 : 1 : return S2N_SUCCESS;
328 : 1 : }
329 : :
330 [ + + ][ + + ]: 140 : if (psk_params->type == S2N_PSK_TYPE_RESUMPTION && psk_list->conn->config->use_tickets) {
331 [ - + ]: 126 : POSIX_GUARD(s2n_stuffer_init(&ticket_stuffer, &psk->identity));
332 [ - + ]: 126 : POSIX_GUARD(s2n_stuffer_skip_write(&ticket_stuffer, psk->identity.size));
333 : :
334 : : /* s2n_resume_decrypt_session appends a new PSK with the decrypted values. */
335 [ + + ]: 126 : POSIX_GUARD_RESULT(s2n_resume_decrypt_session(psk_list->conn, &ticket_stuffer));
336 : 126 : }
337 : :
338 : 130 : struct s2n_psk *chosen_psk = NULL;
339 [ - + ]: 130 : POSIX_GUARD_RESULT(s2n_match_psk_identity(&psk_params->psk_list, &psk->identity, &chosen_psk));
340 [ + + ][ + - ]: 130 : POSIX_ENSURE_REF(chosen_psk);
341 [ + + ]: 122 : POSIX_GUARD_RESULT(s2n_validate_ticket_lifetime(psk_list->conn, psk->obfuscated_ticket_age, chosen_psk->ticket_age_add));
342 : 120 : psk_params->chosen_psk = chosen_psk;
343 : 120 : psk_params->chosen_psk_wire_index = psk->wire_index;
344 : :
345 : 120 : return S2N_SUCCESS;
346 : 122 : }
347 : :
348 : : struct s2n_offered_psk *s2n_offered_psk_new()
349 : 4 : {
350 : 4 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
351 [ - + ]: 4 : PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_offered_psk)));
352 [ - + ]: 4 : PTR_GUARD_POSIX(s2n_blob_zero(&mem));
353 : :
354 : 4 : struct s2n_offered_psk *psk = (struct s2n_offered_psk *) (void *) mem.data;
355 : :
356 : 4 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
357 : 4 : return psk;
358 : 4 : }
359 : :
360 : : int s2n_offered_psk_free(struct s2n_offered_psk **psk)
361 : 5 : {
362 [ + + ]: 5 : if (psk == NULL) {
363 : 1 : return S2N_SUCCESS;
364 : 1 : }
365 : 4 : return s2n_free_object((uint8_t **) psk, sizeof(struct s2n_offered_psk));
366 : 5 : }
367 : :
368 : : int s2n_offered_psk_get_identity(struct s2n_offered_psk *psk, uint8_t **identity, uint16_t *size)
369 : 8 : {
370 [ + - ][ + + ]: 8 : POSIX_ENSURE_REF(psk);
371 [ + - ][ + + ]: 7 : POSIX_ENSURE_REF(psk->identity.data);
372 [ - + ][ # # ]: 4 : POSIX_ENSURE_REF(identity);
373 [ - + ][ # # ]: 4 : POSIX_ENSURE_REF(size);
374 : 4 : *identity = psk->identity.data;
375 : 4 : *size = psk->identity.size;
376 : 4 : return S2N_SUCCESS;
377 : 4 : }
378 : :
379 : : /* The binder hash is computed by hashing the concatenation of the current transcript
380 : : * and a partial ClientHello that does not include the binders themselves.
381 : : */
382 : : int s2n_psk_calculate_binder_hash(struct s2n_connection *conn, s2n_hmac_algorithm hmac_alg,
383 : : const struct s2n_blob *partial_client_hello, struct s2n_blob *output_binder_hash)
384 : 2162 : {
385 [ # # ][ - + ]: 2162 : POSIX_ENSURE_REF(conn);
386 [ # # ][ - + ]: 2162 : POSIX_ENSURE_REF(partial_client_hello);
387 [ # # ][ - + ]: 2162 : POSIX_ENSURE_REF(output_binder_hash);
388 : 2162 : struct s2n_handshake_hashes *hashes = conn->handshake.hashes;
389 [ - + ][ # # ]: 2162 : POSIX_ENSURE_REF(hashes);
390 : :
391 : : /* Retrieve the current transcript.
392 : : * The current transcript will be empty unless this handshake included a HelloRetryRequest. */
393 : 2162 : s2n_hash_algorithm hash_alg = S2N_HASH_NONE;
394 : 2162 : struct s2n_hash_state *hash_state = &hashes->hash_workspace;
395 [ - + ]: 2162 : POSIX_GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg));
396 [ - + ]: 2162 : POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, hash_alg, hash_state));
397 : :
398 : : /* Add the partial client hello to the transcript. */
399 [ - + ]: 2162 : POSIX_GUARD(s2n_hash_update(hash_state, partial_client_hello->data, partial_client_hello->size));
400 : :
401 : : /* Get the transcript digest */
402 [ - + ]: 2162 : POSIX_GUARD(s2n_hash_digest(hash_state, output_binder_hash->data, output_binder_hash->size));
403 : :
404 : 2162 : return S2N_SUCCESS;
405 : 2162 : }
406 : :
407 : : /* The binder is computed in the same way as the Finished message
408 : : * (https://tools.ietf.org/html/rfc8446#section-4.4.4) but with the BaseKey being the binder_key
409 : : * derived via the key schedule from the corresponding PSK which is being offered
410 : : * (https://tools.ietf.org/html/rfc8446#section-7.1)
411 : : */
412 : : int s2n_psk_calculate_binder(struct s2n_psk *psk, const struct s2n_blob *binder_hash,
413 : : struct s2n_blob *output_binder)
414 : 2183 : {
415 [ - + ][ # # ]: 2183 : POSIX_ENSURE_REF(psk);
416 [ - + ][ # # ]: 2183 : POSIX_ENSURE_REF(binder_hash);
417 [ - + ][ # # ]: 2183 : POSIX_ENSURE_REF(output_binder);
418 : :
419 : 2183 : DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free);
420 [ - + ]: 2183 : POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg));
421 [ - + ][ # # ]: 2183 : POSIX_ENSURE_EQ(binder_hash->size, psk_keys.size);
422 [ # # ][ - + ]: 2183 : POSIX_ENSURE_EQ(output_binder->size, psk_keys.size);
423 : :
424 : : /* Derive the binder key */
425 [ - + ]: 2183 : POSIX_GUARD_RESULT(s2n_derive_binder_key(psk, &psk_keys.derive_secret));
426 [ - + ]: 2183 : POSIX_GUARD(s2n_blob_init(&psk_keys.extract_secret, psk->early_secret.data, psk_keys.size));
427 : 2183 : struct s2n_blob *binder_key = &psk_keys.derive_secret;
428 : :
429 : : /* Expand the binder key into the finished key */
430 [ - + ][ # # ]: 2183 : s2n_tls13_key_blob(finished_key, psk_keys.size);
[ - + ]
431 [ - + ]: 2183 : POSIX_GUARD(s2n_tls13_derive_finished_key(&psk_keys, binder_key, &finished_key));
432 : :
433 : : /* HMAC the binder hash with the binder finished key */
434 [ - + ]: 2183 : POSIX_GUARD(s2n_hkdf_extract(&psk_keys.hmac, psk_keys.hmac_algorithm, &finished_key, binder_hash, output_binder));
435 : :
436 : 2183 : return S2N_SUCCESS;
437 : 2183 : }
438 : :
439 : : int s2n_psk_verify_binder(struct s2n_connection *conn, struct s2n_psk *psk,
440 : : const struct s2n_blob *partial_client_hello, struct s2n_blob *binder_to_verify)
441 : 1073 : {
442 [ + - ][ + + ]: 1073 : POSIX_ENSURE_REF(psk);
443 [ # # ][ - + ]: 1072 : POSIX_ENSURE_REF(binder_to_verify);
444 : :
445 : 1072 : DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free);
446 [ - + ]: 1072 : POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg));
447 [ + - ][ + + ]: 1072 : POSIX_ENSURE_EQ(binder_to_verify->size, psk_keys.size);
448 : :
449 : : /* Calculate the binder hash from the transcript */
450 [ # # ][ - + ]: 2142 : s2n_tls13_key_blob(binder_hash, psk_keys.size);
[ - + ]
451 [ - + ]: 1071 : POSIX_GUARD(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, &binder_hash));
452 : :
453 : : /* Calculate the expected binder from the binder hash */
454 [ - + ][ # # ]: 2142 : s2n_tls13_key_blob(expected_binder, psk_keys.size);
[ - + ]
455 [ - + ]: 1071 : POSIX_GUARD(s2n_psk_calculate_binder(psk, &binder_hash, &expected_binder));
456 : :
457 : : /* Verify the expected binder matches the given binder.
458 : : * This operation must be constant time. */
459 [ + + ]: 1071 : POSIX_GUARD(s2n_tls13_mac_verify(&psk_keys, &expected_binder, binder_to_verify));
460 : :
461 : 1069 : return S2N_SUCCESS;
462 : 1071 : }
463 : :
464 : : static S2N_RESULT s2n_psk_write_binder(struct s2n_connection *conn, struct s2n_psk *psk,
465 : : const struct s2n_blob *binder_hash, struct s2n_stuffer *out)
466 : 1097 : {
467 [ # # ][ - + ]: 1097 : RESULT_ENSURE_REF(binder_hash);
468 : :
469 : 1097 : struct s2n_blob binder = { 0 };
470 : 1097 : uint8_t binder_data[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
471 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_blob_init(&binder, binder_data, binder_hash->size));
472 : :
473 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_psk_calculate_binder(psk, binder_hash, &binder));
474 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, binder.size));
475 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_stuffer_write(out, &binder));
476 : :
477 : 1097 : return S2N_RESULT_OK;
478 : 1097 : }
479 : :
480 : : static S2N_RESULT s2n_psk_write_binder_list(struct s2n_connection *conn, const struct s2n_blob *partial_client_hello,
481 : : struct s2n_stuffer *out)
482 : 1081 : {
483 [ - + ][ # # ]: 1081 : RESULT_ENSURE_REF(conn);
484 [ # # ][ - + ]: 1081 : RESULT_ENSURE_REF(partial_client_hello);
485 [ - + ][ # # ]: 1081 : RESULT_ENSURE_REF(conn->secure);
486 : :
487 : 1081 : struct s2n_psk_parameters *psk_params = &conn->psk_params;
488 : 1081 : struct s2n_array *psk_list = &psk_params->psk_list;
489 : :
490 : : /* Setup memory to hold the binder hashes. We potentially need one for
491 : : * every hash algorithm. */
492 : 1081 : uint8_t binder_hashes_data[S2N_HASH_ALGS_COUNT][S2N_TLS13_SECRET_MAX_LEN] = { 0 };
493 : 1081 : struct s2n_blob binder_hashes[S2N_HASH_ALGS_COUNT] = { 0 };
494 : :
495 : 1081 : struct s2n_stuffer_reservation binder_list_size = { 0 };
496 [ - + ]: 1081 : RESULT_GUARD_POSIX(s2n_stuffer_reserve_uint16(out, &binder_list_size));
497 : :
498 : : /* Write binder for every psk */
499 [ + + ]: 2178 : for (size_t i = 0; i < psk_list->len; i++) {
500 : 1097 : struct s2n_psk *psk = NULL;
501 [ - + ]: 1097 : RESULT_GUARD(s2n_array_get(psk_list, i, (void **) &psk));
502 [ - + ][ # # ]: 1097 : RESULT_ENSURE_REF(psk);
503 : :
504 : : /**
505 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.1.4
506 : : *# In addition, in its updated ClientHello, the client SHOULD NOT offer
507 : : *# any pre-shared keys associated with a hash other than that of the
508 : : *# selected cipher suite. This allows the client to avoid having to
509 : : *# compute partial hash transcripts for multiple hashes in the second
510 : : *# ClientHello.
511 : : */
512 [ + + ][ - + ]: 1097 : if (s2n_is_hello_retry_handshake(conn) && conn->secure->cipher_suite->prf_alg != psk->hmac_alg) {
513 : 0 : continue;
514 : 0 : }
515 : :
516 : : /* Retrieve or calculate the binder hash. */
517 : 1097 : struct s2n_blob *binder_hash = &binder_hashes[psk->hmac_alg];
518 [ + + ]: 1097 : if (binder_hash->size == 0) {
519 : 1082 : uint8_t hash_size = 0;
520 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_hmac_digest_size(psk->hmac_alg, &hash_size));
521 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_blob_init(binder_hash, binder_hashes_data[psk->hmac_alg], hash_size));
522 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, binder_hash));
523 : 1082 : }
524 : :
525 [ - + ]: 1097 : RESULT_GUARD(s2n_psk_write_binder(conn, psk, binder_hash, out));
526 : 1097 : }
527 [ - + ]: 1081 : RESULT_GUARD_POSIX(s2n_stuffer_write_vector_size(&binder_list_size));
528 : :
529 : 1081 : return S2N_RESULT_OK;
530 : 1081 : }
531 : :
532 : : S2N_RESULT s2n_finish_psk_extension(struct s2n_connection *conn)
533 : 7721 : {
534 [ - + ][ # # ]: 7721 : RESULT_ENSURE_REF(conn);
535 : :
536 [ + + ]: 7721 : if (!conn->psk_params.binder_list_size) {
537 : 6639 : return S2N_RESULT_OK;
538 : 6639 : }
539 : :
540 : 1082 : struct s2n_stuffer *client_hello = &conn->handshake.io;
541 : 1082 : struct s2n_psk_parameters *psk_params = &conn->psk_params;
542 : :
543 : : /* Fill in the correct message size. */
544 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_handshake_finish_header(client_hello));
545 : :
546 : : /* Remove the empty space allocated for the binder list.
547 : : * It was originally added to ensure the extension / extension list / message sizes
548 : : * were properly calculated. */
549 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_stuffer_wipe_n(client_hello, psk_params->binder_list_size));
550 : :
551 : : /* Store the partial client hello for use in calculating the binder hash. */
552 : 1082 : struct s2n_blob partial_client_hello = { 0 };
553 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_blob_init(&partial_client_hello, client_hello->blob.data,
554 : 1082 : s2n_stuffer_data_available(client_hello)));
555 : :
556 [ - + ]: 1082 : RESULT_GUARD(s2n_psk_write_binder_list(conn, &partial_client_hello, client_hello));
557 : :
558 : : /* Reset binder list size.
559 : : * This is important because the psk extension can be removed during a retry.
560 : : */
561 : 1082 : conn->psk_params.binder_list_size = 0;
562 : :
563 : 1082 : return S2N_RESULT_OK;
564 : 1082 : }
565 : :
566 : : int s2n_psk_set_hmac(struct s2n_psk *psk, s2n_psk_hmac hmac)
567 : 48 : {
568 [ + - ][ + + ]: 48 : POSIX_ENSURE_REF(psk);
569 : 47 : switch (hmac) {
570 [ + + ]: 34 : case S2N_PSK_HMAC_SHA256:
571 : 34 : psk->hmac_alg = S2N_HMAC_SHA256;
572 : 34 : break;
573 [ + + ]: 12 : case S2N_PSK_HMAC_SHA384:
574 : 12 : psk->hmac_alg = S2N_HMAC_SHA384;
575 : 12 : break;
576 [ + + ]: 1 : default:
577 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_HMAC_INVALID_ALGORITHM);
578 : 47 : }
579 : 46 : return S2N_SUCCESS;
580 : 47 : }
581 : :
582 : : S2N_RESULT s2n_connection_set_psk_type(struct s2n_connection *conn, s2n_psk_type type)
583 : 3562938 : {
584 [ - + ][ # # ]: 3562938 : RESULT_ENSURE_REF(conn);
585 [ + + ]: 3562938 : if (conn->psk_params.psk_list.len != 0) {
586 [ + + ][ + - ]: 45 : RESULT_ENSURE(conn->psk_params.type == type, S2N_ERR_PSK_MODE);
587 : 45 : }
588 : 3562934 : conn->psk_params.type = type;
589 : 3562934 : return S2N_RESULT_OK;
590 : 3562938 : }
591 : :
592 : : int s2n_connection_append_psk(struct s2n_connection *conn, struct s2n_psk *input_psk)
593 : 1344 : {
594 [ + + ][ + - ]: 1344 : POSIX_ENSURE_REF(conn);
595 [ + + ][ + - ]: 1343 : POSIX_ENSURE_REF(input_psk);
596 [ + + ]: 1342 : POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, input_psk->type));
597 : :
598 : 1340 : struct s2n_array *psk_list = &conn->psk_params.psk_list;
599 : :
600 : : /* Check for duplicate identities */
601 [ + + ]: 4000 : for (uint32_t j = 0; j < psk_list->len; j++) {
602 : 2661 : struct s2n_psk *existing_psk = NULL;
603 [ - + ]: 2661 : POSIX_GUARD_RESULT(s2n_array_get(psk_list, j, (void **) &existing_psk));
604 [ - + ][ # # ]: 2661 : POSIX_ENSURE_REF(existing_psk);
605 : :
606 [ + + ]: 2661 : bool duplicate = existing_psk->identity.size == input_psk->identity.size
607 [ + + ]: 2661 : && memcmp(existing_psk->identity.data, input_psk->identity.data, existing_psk->identity.size) == 0;
608 [ + + ][ + - ]: 2661 : POSIX_ENSURE(!duplicate, S2N_ERR_DUPLICATE_PSK_IDENTITIES);
609 : 2661 : }
610 : :
611 : : /* Verify the PSK list will fit in the ClientHello pre_shared_key extension */
612 [ + + ]: 1339 : if (conn->mode == S2N_CLIENT) {
613 : 680 : uint32_t list_size = 0;
614 [ - + ]: 680 : POSIX_GUARD_RESULT(s2n_psk_parameters_offered_psks_size(&conn->psk_params, &list_size));
615 : :
616 : 680 : uint32_t psk_size = 0;
617 [ - + ]: 680 : POSIX_GUARD_RESULT(s2n_psk_offered_psk_size(input_psk, &psk_size));
618 : :
619 [ + + ][ + - ]: 680 : POSIX_ENSURE(list_size + psk_size + S2N_EXTENSION_HEADER_LENGTH <= UINT16_MAX, S2N_ERR_OFFERED_PSKS_TOO_LONG);
620 : 680 : }
621 : :
622 : 1337 : DEFER_CLEANUP(struct s2n_psk new_psk = { 0 }, s2n_psk_wipe);
623 [ + + ][ + - ]: 1337 : POSIX_ENSURE(s2n_result_is_ok(s2n_psk_clone(&new_psk, input_psk)), S2N_ERR_INVALID_ARGUMENT);
624 [ - + ]: 1335 : POSIX_GUARD_RESULT(s2n_array_insert_and_copy(psk_list, psk_list->len, &new_psk));
625 : :
626 : 1335 : ZERO_TO_DISABLE_DEFER_CLEANUP(new_psk);
627 : 1335 : return S2N_SUCCESS;
628 : 1335 : }
629 : :
630 : : int s2n_config_set_psk_mode(struct s2n_config *config, s2n_psk_mode mode)
631 : 3 : {
632 [ + - ][ + + ]: 3 : POSIX_ENSURE_REF(config);
633 : 2 : config->psk_mode = mode;
634 : 2 : return S2N_SUCCESS;
635 : 3 : }
636 : :
637 : : int s2n_connection_set_psk_mode(struct s2n_connection *conn, s2n_psk_mode mode)
638 : 3561341 : {
639 [ + - ][ + + ]: 3561341 : POSIX_ENSURE_REF(conn);
640 : 3561340 : s2n_psk_type type = 0;
641 : 3561340 : switch (mode) {
642 [ + + ]: 3561338 : case S2N_PSK_MODE_RESUMPTION:
643 : 3561338 : type = S2N_PSK_TYPE_RESUMPTION;
644 : 3561338 : break;
645 [ + + ]: 2 : case S2N_PSK_MODE_EXTERNAL:
646 : 2 : type = S2N_PSK_TYPE_EXTERNAL;
647 : 2 : break;
648 [ - + ]: 0 : default:
649 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT);
650 : 0 : break;
651 : 3561340 : }
652 [ + + ]: 3561340 : POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, type));
653 : 3561339 : conn->psk_mode_overridden = true;
654 : 3561339 : return S2N_SUCCESS;
655 : 3561340 : }
656 : :
657 : : int s2n_connection_get_negotiated_psk_identity_length(struct s2n_connection *conn, uint16_t *identity_length)
658 : 5 : {
659 [ + - ][ + + ]: 5 : POSIX_ENSURE_REF(conn);
660 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(identity_length);
661 : :
662 : 3 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
663 : :
664 [ + + ]: 3 : if (chosen_psk == NULL) {
665 : 1 : *identity_length = 0;
666 : 2 : } else {
667 : 2 : *identity_length = chosen_psk->identity.size;
668 : 2 : }
669 : :
670 : 3 : return S2N_SUCCESS;
671 : 4 : }
672 : :
673 : : int s2n_connection_get_negotiated_psk_identity(struct s2n_connection *conn, uint8_t *identity,
674 : : uint16_t max_identity_length)
675 : 5 : {
676 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(conn);
677 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(identity);
678 : :
679 : 3 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
680 : :
681 [ + + ]: 3 : if (chosen_psk == NULL) {
682 : 1 : return S2N_SUCCESS;
683 : 1 : }
684 : :
685 [ + - ][ + + ]: 2 : POSIX_ENSURE(chosen_psk->identity.size <= max_identity_length, S2N_ERR_INSUFFICIENT_MEM_SIZE);
686 [ # # ][ - + ]: 1 : POSIX_CHECKED_MEMCPY(identity, chosen_psk->identity.data, chosen_psk->identity.size);
[ + - ]
687 : :
688 : 1 : return S2N_SUCCESS;
689 : 1 : }
690 : :
691 : : S2N_RESULT s2n_psk_validate_keying_material(struct s2n_connection *conn)
692 : 428 : {
693 [ + + ][ + - ]: 428 : RESULT_ENSURE_REF(conn);
694 : :
695 : 427 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
696 [ + + ][ + + ]: 427 : if (!chosen_psk || chosen_psk->type != S2N_PSK_TYPE_RESUMPTION) {
697 : 147 : return S2N_RESULT_OK;
698 : 147 : }
699 : :
700 : : /*
701 : : * The minimum ticket lifetime is 1s, because ticket_lifetime is given
702 : : * in seconds and 0 indicates that the ticket should be immediately discarded.
703 : : */
704 : 280 : uint32_t min_lifetime = ONE_SEC_IN_NANOS;
705 : :
706 : 280 : uint64_t current_time = 0;
707 [ - + ]: 280 : RESULT_GUARD(s2n_config_wall_clock(conn->config, ¤t_time));
708 [ + - ][ + + ]: 280 : RESULT_ENSURE(chosen_psk->keying_material_expiration > current_time + min_lifetime, S2N_ERR_KEYING_MATERIAL_EXPIRED);
709 : :
710 : 274 : return S2N_RESULT_OK;
711 : 280 : }
|