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 : 6972004 : {
133 [ + - ][ + + ]: 6972004 : RESULT_ENSURE_REF(params);
134 [ - + ][ # # ]: 6972003 : RESULT_CHECKED_MEMSET(params, 0, sizeof(struct s2n_psk_parameters));
[ + - ]
135 [ - + ]: 6972003 : RESULT_GUARD(s2n_array_init(¶ms->psk_list, sizeof(struct s2n_psk)));
136 : 6972003 : return S2N_RESULT_OK;
137 : 6972003 : }
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 : 3549645 : {
176 [ + + ][ + - ]: 3549645 : RESULT_ENSURE_REF(params);
177 : :
178 [ + + ]: 3552450 : 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 [ - + ]: 3549644 : RESULT_GUARD_POSIX(s2n_free(¶ms->psk_list.mem));
184 [ - + ]: 3549644 : RESULT_GUARD(s2n_psk_parameters_init(params));
185 : :
186 : 3549644 : return S2N_RESULT_OK;
187 : 3549644 : }
188 : :
189 : : S2N_CLEANUP_RESULT s2n_psk_parameters_wipe_secrets(struct s2n_psk_parameters *params)
190 : 9813 : {
191 [ + + ][ + - ]: 9813 : RESULT_ENSURE_REF(params);
192 : :
193 [ + + ]: 11046 : 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 : 9812 : return S2N_RESULT_OK;
202 : 9812 : }
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 : 143 : {
319 [ + + ][ + - ]: 143 : POSIX_ENSURE_REF(psk_list);
320 [ # # ][ - + ]: 142 : POSIX_ENSURE_REF(psk_list->conn);
321 : :
322 : 142 : struct s2n_psk_parameters *psk_params = &psk_list->conn->psk_params;
323 : 142 : struct s2n_stuffer ticket_stuffer = { 0 };
324 : :
325 [ + + ]: 142 : if (!psk) {
326 : 1 : psk_params->chosen_psk = NULL;
327 : 1 : return S2N_SUCCESS;
328 : 1 : }
329 : :
330 : : /* An offered_psk must have its identity set before being chosen.
331 : : * Without this check, the function would return an internal error
332 : : * later when attempting to match the identity. */
333 [ + - ][ + + ]: 141 : POSIX_ENSURE(psk->identity.data != NULL, S2N_ERR_INVALID_ARGUMENT);
334 : :
335 [ + + ][ + + ]: 140 : if (psk_params->type == S2N_PSK_TYPE_RESUMPTION && psk_list->conn->config->use_tickets) {
336 [ - + ]: 126 : POSIX_GUARD(s2n_stuffer_init(&ticket_stuffer, &psk->identity));
337 [ - + ]: 126 : POSIX_GUARD(s2n_stuffer_skip_write(&ticket_stuffer, psk->identity.size));
338 : :
339 : : /* s2n_resume_decrypt_session appends a new PSK with the decrypted values. */
340 [ + + ]: 126 : POSIX_GUARD_RESULT(s2n_resume_decrypt_session(psk_list->conn, &ticket_stuffer));
341 : 126 : }
342 : :
343 : 130 : struct s2n_psk *chosen_psk = NULL;
344 [ - + ]: 130 : POSIX_GUARD_RESULT(s2n_match_psk_identity(&psk_params->psk_list, &psk->identity, &chosen_psk));
345 [ + + ][ + - ]: 130 : POSIX_ENSURE_REF(chosen_psk);
346 [ + + ]: 122 : POSIX_GUARD_RESULT(s2n_validate_ticket_lifetime(psk_list->conn, psk->obfuscated_ticket_age, chosen_psk->ticket_age_add));
347 : 120 : psk_params->chosen_psk = chosen_psk;
348 : 120 : psk_params->chosen_psk_wire_index = psk->wire_index;
349 : :
350 : 120 : return S2N_SUCCESS;
351 : 122 : }
352 : :
353 : : struct s2n_offered_psk *s2n_offered_psk_new()
354 : 5 : {
355 : 5 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
356 [ - + ]: 5 : PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_offered_psk)));
357 [ - + ]: 5 : PTR_GUARD_POSIX(s2n_blob_zero(&mem));
358 : :
359 : 5 : struct s2n_offered_psk *psk = (struct s2n_offered_psk *) (void *) mem.data;
360 : :
361 : 5 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
362 : 5 : return psk;
363 : 5 : }
364 : :
365 : : int s2n_offered_psk_free(struct s2n_offered_psk **psk)
366 : 6 : {
367 [ + + ]: 6 : if (psk == NULL) {
368 : 1 : return S2N_SUCCESS;
369 : 1 : }
370 : 5 : return s2n_free_object((uint8_t **) psk, sizeof(struct s2n_offered_psk));
371 : 6 : }
372 : :
373 : : int s2n_offered_psk_get_identity(struct s2n_offered_psk *psk, uint8_t **identity, uint16_t *size)
374 : 8 : {
375 [ + + ][ + - ]: 8 : POSIX_ENSURE_REF(psk);
376 [ + + ][ + - ]: 7 : POSIX_ENSURE_REF(psk->identity.data);
377 [ - + ][ # # ]: 4 : POSIX_ENSURE_REF(identity);
378 [ # # ][ - + ]: 4 : POSIX_ENSURE_REF(size);
379 : 4 : *identity = psk->identity.data;
380 : 4 : *size = psk->identity.size;
381 : 4 : return S2N_SUCCESS;
382 : 4 : }
383 : :
384 : : /* The binder hash is computed by hashing the concatenation of the current transcript
385 : : * and a partial ClientHello that does not include the binders themselves.
386 : : */
387 : : int s2n_psk_calculate_binder_hash(struct s2n_connection *conn, s2n_hmac_algorithm hmac_alg,
388 : : const struct s2n_blob *partial_client_hello, struct s2n_blob *output_binder_hash)
389 : 2162 : {
390 [ # # ][ - + ]: 2162 : POSIX_ENSURE_REF(conn);
391 [ # # ][ - + ]: 2162 : POSIX_ENSURE_REF(partial_client_hello);
392 [ - + ][ # # ]: 2162 : POSIX_ENSURE_REF(output_binder_hash);
393 : 2162 : struct s2n_handshake_hashes *hashes = conn->handshake.hashes;
394 [ - + ][ # # ]: 2162 : POSIX_ENSURE_REF(hashes);
395 : :
396 : : /* Retrieve the current transcript.
397 : : * The current transcript will be empty unless this handshake included a HelloRetryRequest. */
398 : 2162 : s2n_hash_algorithm hash_alg = S2N_HASH_NONE;
399 : 2162 : struct s2n_hash_state *hash_state = &hashes->hash_workspace;
400 [ - + ]: 2162 : POSIX_GUARD(s2n_hmac_hash_alg(hmac_alg, &hash_alg));
401 [ - + ]: 2162 : POSIX_GUARD_RESULT(s2n_handshake_copy_hash_state(conn, hash_alg, hash_state));
402 : :
403 : : /* Add the partial client hello to the transcript. */
404 [ - + ]: 2162 : POSIX_GUARD(s2n_hash_update(hash_state, partial_client_hello->data, partial_client_hello->size));
405 : :
406 : : /* Get the transcript digest */
407 [ - + ]: 2162 : POSIX_GUARD(s2n_hash_digest(hash_state, output_binder_hash->data, output_binder_hash->size));
408 : :
409 : 2162 : return S2N_SUCCESS;
410 : 2162 : }
411 : :
412 : : /* The binder is computed in the same way as the Finished message
413 : : * (https://tools.ietf.org/html/rfc8446#section-4.4.4) but with the BaseKey being the binder_key
414 : : * derived via the key schedule from the corresponding PSK which is being offered
415 : : * (https://tools.ietf.org/html/rfc8446#section-7.1)
416 : : */
417 : : int s2n_psk_calculate_binder(struct s2n_psk *psk, const struct s2n_blob *binder_hash,
418 : : struct s2n_blob *output_binder)
419 : 2183 : {
420 [ - + ][ # # ]: 2183 : POSIX_ENSURE_REF(psk);
421 [ - + ][ # # ]: 2183 : POSIX_ENSURE_REF(binder_hash);
422 [ # # ][ - + ]: 2183 : POSIX_ENSURE_REF(output_binder);
423 : :
424 : 2183 : DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free);
425 [ - + ]: 2183 : POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg));
426 [ # # ][ - + ]: 2183 : POSIX_ENSURE_EQ(binder_hash->size, psk_keys.size);
427 [ # # ][ - + ]: 2183 : POSIX_ENSURE_EQ(output_binder->size, psk_keys.size);
428 : :
429 : : /* Derive the binder key */
430 [ - + ]: 2183 : POSIX_GUARD_RESULT(s2n_derive_binder_key(psk, &psk_keys.derive_secret));
431 [ - + ]: 2183 : POSIX_GUARD(s2n_blob_init(&psk_keys.extract_secret, psk->early_secret.data, psk_keys.size));
432 : 2183 : struct s2n_blob *binder_key = &psk_keys.derive_secret;
433 : :
434 : : /* Expand the binder key into the finished key */
435 [ - + ][ # # ]: 2183 : s2n_tls13_key_blob(finished_key, psk_keys.size);
[ - + ]
436 [ - + ]: 2183 : POSIX_GUARD(s2n_tls13_derive_finished_key(&psk_keys, binder_key, &finished_key));
437 : :
438 : : /* HMAC the binder hash with the binder finished key */
439 [ - + ]: 2183 : POSIX_GUARD(s2n_hkdf_extract(&psk_keys.hmac, psk_keys.hmac_algorithm, &finished_key, binder_hash, output_binder));
440 : :
441 : 2183 : return S2N_SUCCESS;
442 : 2183 : }
443 : :
444 : : int s2n_psk_verify_binder(struct s2n_connection *conn, struct s2n_psk *psk,
445 : : const struct s2n_blob *partial_client_hello, struct s2n_blob *binder_to_verify)
446 : 1073 : {
447 [ + - ][ + + ]: 1073 : POSIX_ENSURE_REF(psk);
448 [ # # ][ - + ]: 1072 : POSIX_ENSURE_REF(binder_to_verify);
449 : :
450 : 1072 : DEFER_CLEANUP(struct s2n_tls13_keys psk_keys, s2n_tls13_keys_free);
451 [ - + ]: 1072 : POSIX_GUARD(s2n_tls13_keys_init(&psk_keys, psk->hmac_alg));
452 [ + + ][ + - ]: 1072 : POSIX_ENSURE_EQ(binder_to_verify->size, psk_keys.size);
453 : :
454 : : /* Calculate the binder hash from the transcript */
455 [ - + ][ # # ]: 2142 : s2n_tls13_key_blob(binder_hash, psk_keys.size);
[ - + ]
456 [ - + ]: 1071 : POSIX_GUARD(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, &binder_hash));
457 : :
458 : : /* Calculate the expected binder from the binder hash */
459 [ - + ][ # # ]: 2142 : s2n_tls13_key_blob(expected_binder, psk_keys.size);
[ - + ]
460 [ - + ]: 1071 : POSIX_GUARD(s2n_psk_calculate_binder(psk, &binder_hash, &expected_binder));
461 : :
462 : : /* Verify the expected binder matches the given binder.
463 : : * This operation must be constant time. */
464 [ + + ]: 1071 : POSIX_GUARD(s2n_tls13_mac_verify(&psk_keys, &expected_binder, binder_to_verify));
465 : :
466 : 1069 : return S2N_SUCCESS;
467 : 1071 : }
468 : :
469 : : static S2N_RESULT s2n_psk_write_binder(struct s2n_connection *conn, struct s2n_psk *psk,
470 : : const struct s2n_blob *binder_hash, struct s2n_stuffer *out)
471 : 1097 : {
472 [ - + ][ # # ]: 1097 : RESULT_ENSURE_REF(binder_hash);
473 : :
474 : 1097 : struct s2n_blob binder = { 0 };
475 : 1097 : uint8_t binder_data[S2N_TLS13_SECRET_MAX_LEN] = { 0 };
476 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_blob_init(&binder, binder_data, binder_hash->size));
477 : :
478 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_psk_calculate_binder(psk, binder_hash, &binder));
479 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(out, binder.size));
480 [ - + ]: 1097 : RESULT_GUARD_POSIX(s2n_stuffer_write(out, &binder));
481 : :
482 : 1097 : return S2N_RESULT_OK;
483 : 1097 : }
484 : :
485 : : static S2N_RESULT s2n_psk_write_binder_list(struct s2n_connection *conn, const struct s2n_blob *partial_client_hello,
486 : : struct s2n_stuffer *out)
487 : 1081 : {
488 [ - + ][ # # ]: 1081 : RESULT_ENSURE_REF(conn);
489 [ # # ][ - + ]: 1081 : RESULT_ENSURE_REF(partial_client_hello);
490 [ - + ][ # # ]: 1081 : RESULT_ENSURE_REF(conn->secure);
491 : :
492 : 1081 : struct s2n_psk_parameters *psk_params = &conn->psk_params;
493 : 1081 : struct s2n_array *psk_list = &psk_params->psk_list;
494 : :
495 : : /* Setup memory to hold the binder hashes. We potentially need one for
496 : : * every hash algorithm. */
497 : 1081 : uint8_t binder_hashes_data[S2N_HASH_ALGS_COUNT][S2N_TLS13_SECRET_MAX_LEN] = { 0 };
498 : 1081 : struct s2n_blob binder_hashes[S2N_HASH_ALGS_COUNT] = { 0 };
499 : :
500 : 1081 : struct s2n_stuffer_reservation binder_list_size = { 0 };
501 [ - + ]: 1081 : RESULT_GUARD_POSIX(s2n_stuffer_reserve_uint16(out, &binder_list_size));
502 : :
503 : : /* Write binder for every psk */
504 [ + + ]: 2178 : for (size_t i = 0; i < psk_list->len; i++) {
505 : 1097 : struct s2n_psk *psk = NULL;
506 [ - + ]: 1097 : RESULT_GUARD(s2n_array_get(psk_list, i, (void **) &psk));
507 [ - + ][ # # ]: 1097 : RESULT_ENSURE_REF(psk);
508 : :
509 : : /**
510 : : *= https://www.rfc-editor.org/rfc/rfc8446#section-4.1.4
511 : : *# In addition, in its updated ClientHello, the client SHOULD NOT offer
512 : : *# any pre-shared keys associated with a hash other than that of the
513 : : *# selected cipher suite. This allows the client to avoid having to
514 : : *# compute partial hash transcripts for multiple hashes in the second
515 : : *# ClientHello.
516 : : */
517 [ + + ][ - + ]: 1097 : if (s2n_is_hello_retry_handshake(conn) && conn->secure->cipher_suite->prf_alg != psk->hmac_alg) {
518 : 0 : continue;
519 : 0 : }
520 : :
521 : : /* Retrieve or calculate the binder hash. */
522 : 1097 : struct s2n_blob *binder_hash = &binder_hashes[psk->hmac_alg];
523 [ + + ]: 1097 : if (binder_hash->size == 0) {
524 : 1082 : uint8_t hash_size = 0;
525 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_hmac_digest_size(psk->hmac_alg, &hash_size));
526 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_blob_init(binder_hash, binder_hashes_data[psk->hmac_alg], hash_size));
527 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_psk_calculate_binder_hash(conn, psk->hmac_alg, partial_client_hello, binder_hash));
528 : 1082 : }
529 : :
530 [ - + ]: 1097 : RESULT_GUARD(s2n_psk_write_binder(conn, psk, binder_hash, out));
531 : 1097 : }
532 [ - + ]: 1081 : RESULT_GUARD_POSIX(s2n_stuffer_write_vector_size(&binder_list_size));
533 : :
534 : 1081 : return S2N_RESULT_OK;
535 : 1081 : }
536 : :
537 : : S2N_RESULT s2n_finish_psk_extension(struct s2n_connection *conn)
538 : 7875 : {
539 [ - + ][ # # ]: 7875 : RESULT_ENSURE_REF(conn);
540 : :
541 [ + + ]: 7875 : if (!conn->psk_params.binder_list_size) {
542 : 6793 : return S2N_RESULT_OK;
543 : 6793 : }
544 : :
545 : 1082 : struct s2n_stuffer *client_hello = &conn->handshake.io;
546 : 1082 : struct s2n_psk_parameters *psk_params = &conn->psk_params;
547 : :
548 : : /* Fill in the correct message size. */
549 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_handshake_finish_header(client_hello));
550 : :
551 : : /* Remove the empty space allocated for the binder list.
552 : : * It was originally added to ensure the extension / extension list / message sizes
553 : : * were properly calculated. */
554 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_stuffer_wipe_n(client_hello, psk_params->binder_list_size));
555 : :
556 : : /* Store the partial client hello for use in calculating the binder hash. */
557 : 1082 : struct s2n_blob partial_client_hello = { 0 };
558 [ - + ]: 1082 : RESULT_GUARD_POSIX(s2n_blob_init(&partial_client_hello, client_hello->blob.data,
559 : 1082 : s2n_stuffer_data_available(client_hello)));
560 : :
561 [ - + ]: 1082 : RESULT_GUARD(s2n_psk_write_binder_list(conn, &partial_client_hello, client_hello));
562 : :
563 : : /* Reset binder list size.
564 : : * This is important because the psk extension can be removed during a retry.
565 : : */
566 : 1082 : conn->psk_params.binder_list_size = 0;
567 : :
568 : 1082 : return S2N_RESULT_OK;
569 : 1082 : }
570 : :
571 : : int s2n_psk_set_hmac(struct s2n_psk *psk, s2n_psk_hmac hmac)
572 : 48 : {
573 [ + - ][ + + ]: 48 : POSIX_ENSURE_REF(psk);
574 : 47 : switch (hmac) {
575 [ + + ]: 34 : case S2N_PSK_HMAC_SHA256:
576 : 34 : psk->hmac_alg = S2N_HMAC_SHA256;
577 : 34 : break;
578 [ + + ]: 12 : case S2N_PSK_HMAC_SHA384:
579 : 12 : psk->hmac_alg = S2N_HMAC_SHA384;
580 : 12 : break;
581 [ + + ]: 1 : default:
582 [ + - ]: 1 : POSIX_BAIL(S2N_ERR_HMAC_INVALID_ALGORITHM);
583 : 47 : }
584 : 46 : return S2N_SUCCESS;
585 : 47 : }
586 : :
587 : : S2N_RESULT s2n_connection_set_psk_type(struct s2n_connection *conn, s2n_psk_type type)
588 : 3564005 : {
589 [ - + ][ # # ]: 3564005 : RESULT_ENSURE_REF(conn);
590 [ + + ]: 3564005 : if (conn->psk_params.psk_list.len != 0) {
591 [ + + ][ + - ]: 45 : RESULT_ENSURE(conn->psk_params.type == type, S2N_ERR_PSK_MODE);
592 : 45 : }
593 : 3564001 : conn->psk_params.type = type;
594 : 3564001 : return S2N_RESULT_OK;
595 : 3564005 : }
596 : :
597 : : int s2n_connection_append_psk(struct s2n_connection *conn, struct s2n_psk *input_psk)
598 : 1344 : {
599 [ + + ][ + - ]: 1344 : POSIX_ENSURE_REF(conn);
600 [ + + ][ + - ]: 1343 : POSIX_ENSURE_REF(input_psk);
601 [ + + ]: 1342 : POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, input_psk->type));
602 : :
603 : 1340 : struct s2n_array *psk_list = &conn->psk_params.psk_list;
604 : :
605 : : /* Check for duplicate identities */
606 [ + + ]: 4000 : for (uint32_t j = 0; j < psk_list->len; j++) {
607 : 2661 : struct s2n_psk *existing_psk = NULL;
608 [ - + ]: 2661 : POSIX_GUARD_RESULT(s2n_array_get(psk_list, j, (void **) &existing_psk));
609 [ - + ][ # # ]: 2661 : POSIX_ENSURE_REF(existing_psk);
610 : :
611 [ + + ]: 2661 : bool duplicate = existing_psk->identity.size == input_psk->identity.size
612 [ + + ]: 2661 : && memcmp(existing_psk->identity.data, input_psk->identity.data, existing_psk->identity.size) == 0;
613 [ + + ][ + - ]: 2661 : POSIX_ENSURE(!duplicate, S2N_ERR_DUPLICATE_PSK_IDENTITIES);
614 : 2661 : }
615 : :
616 : : /* Verify the PSK list will fit in the ClientHello pre_shared_key extension */
617 [ + + ]: 1339 : if (conn->mode == S2N_CLIENT) {
618 : 680 : uint32_t list_size = 0;
619 [ - + ]: 680 : POSIX_GUARD_RESULT(s2n_psk_parameters_offered_psks_size(&conn->psk_params, &list_size));
620 : :
621 : 680 : uint32_t psk_size = 0;
622 [ - + ]: 680 : POSIX_GUARD_RESULT(s2n_psk_offered_psk_size(input_psk, &psk_size));
623 : :
624 [ + + ][ + - ]: 680 : POSIX_ENSURE(list_size + psk_size + S2N_EXTENSION_HEADER_LENGTH <= UINT16_MAX, S2N_ERR_OFFERED_PSKS_TOO_LONG);
625 : 680 : }
626 : :
627 : 1337 : DEFER_CLEANUP(struct s2n_psk new_psk = { 0 }, s2n_psk_wipe);
628 [ + + ][ + - ]: 1337 : POSIX_ENSURE(s2n_result_is_ok(s2n_psk_clone(&new_psk, input_psk)), S2N_ERR_INVALID_ARGUMENT);
629 [ - + ]: 1335 : POSIX_GUARD_RESULT(s2n_array_insert_and_copy(psk_list, psk_list->len, &new_psk));
630 : :
631 : 1335 : ZERO_TO_DISABLE_DEFER_CLEANUP(new_psk);
632 : 1335 : return S2N_SUCCESS;
633 : 1335 : }
634 : :
635 : : int s2n_config_set_psk_mode(struct s2n_config *config, s2n_psk_mode mode)
636 : 3 : {
637 [ + - ][ + + ]: 3 : POSIX_ENSURE_REF(config);
638 : 2 : config->psk_mode = mode;
639 : 2 : return S2N_SUCCESS;
640 : 3 : }
641 : :
642 : : int s2n_connection_set_psk_mode(struct s2n_connection *conn, s2n_psk_mode mode)
643 : 3562408 : {
644 [ + - ][ + + ]: 3562408 : POSIX_ENSURE_REF(conn);
645 : 3562407 : s2n_psk_type type = 0;
646 : 3562407 : switch (mode) {
647 [ + + ]: 3562405 : case S2N_PSK_MODE_RESUMPTION:
648 : 3562405 : type = S2N_PSK_TYPE_RESUMPTION;
649 : 3562405 : break;
650 [ + + ]: 2 : case S2N_PSK_MODE_EXTERNAL:
651 : 2 : type = S2N_PSK_TYPE_EXTERNAL;
652 : 2 : break;
653 [ - + ]: 0 : default:
654 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_INVALID_ARGUMENT);
655 : 0 : break;
656 : 3562407 : }
657 [ + + ]: 3562407 : POSIX_GUARD_RESULT(s2n_connection_set_psk_type(conn, type));
658 : 3562406 : conn->psk_mode_overridden = true;
659 : 3562406 : return S2N_SUCCESS;
660 : 3562407 : }
661 : :
662 : : int s2n_connection_get_negotiated_psk_identity_length(struct s2n_connection *conn, uint16_t *identity_length)
663 : 5 : {
664 [ + - ][ + + ]: 5 : POSIX_ENSURE_REF(conn);
665 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(identity_length);
666 : :
667 : 3 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
668 : :
669 [ + + ]: 3 : if (chosen_psk == NULL) {
670 : 1 : *identity_length = 0;
671 : 2 : } else {
672 : 2 : *identity_length = chosen_psk->identity.size;
673 : 2 : }
674 : :
675 : 3 : return S2N_SUCCESS;
676 : 4 : }
677 : :
678 : : int s2n_connection_get_negotiated_psk_identity(struct s2n_connection *conn, uint8_t *identity,
679 : : uint16_t max_identity_length)
680 : 5 : {
681 [ + + ][ + - ]: 5 : POSIX_ENSURE_REF(conn);
682 [ + + ][ + - ]: 4 : POSIX_ENSURE_REF(identity);
683 : :
684 : 3 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
685 : :
686 [ + + ]: 3 : if (chosen_psk == NULL) {
687 : 1 : return S2N_SUCCESS;
688 : 1 : }
689 : :
690 [ + - ][ + + ]: 2 : POSIX_ENSURE(chosen_psk->identity.size <= max_identity_length, S2N_ERR_INSUFFICIENT_MEM_SIZE);
691 [ # # ][ - + ]: 1 : POSIX_CHECKED_MEMCPY(identity, chosen_psk->identity.data, chosen_psk->identity.size);
[ + - ]
692 : :
693 : 1 : return S2N_SUCCESS;
694 : 1 : }
695 : :
696 : : S2N_RESULT s2n_psk_validate_keying_material(struct s2n_connection *conn)
697 : 429 : {
698 [ + + ][ + - ]: 429 : RESULT_ENSURE_REF(conn);
699 : :
700 : 428 : struct s2n_psk *chosen_psk = conn->psk_params.chosen_psk;
701 [ + + ][ + + ]: 428 : if (!chosen_psk || chosen_psk->type != S2N_PSK_TYPE_RESUMPTION) {
702 : 148 : return S2N_RESULT_OK;
703 : 148 : }
704 : :
705 : : /*
706 : : * The minimum ticket lifetime is 1s, because ticket_lifetime is given
707 : : * in seconds and 0 indicates that the ticket should be immediately discarded.
708 : : */
709 : 280 : uint32_t min_lifetime = ONE_SEC_IN_NANOS;
710 : :
711 : 280 : uint64_t current_time = 0;
712 [ - + ]: 280 : RESULT_GUARD(s2n_config_wall_clock(conn->config, ¤t_time));
713 [ + - ][ + + ]: 280 : RESULT_ENSURE(chosen_psk->keying_material_expiration > current_time + min_lifetime, S2N_ERR_KEYING_MATERIAL_EXPIRED);
714 : :
715 : 274 : return S2N_RESULT_OK;
716 : 280 : }
|