/src/gnutls/lib/constate.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2012 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2017 Red Hat, Inc. |
4 | | * |
5 | | * Author: Nikos Mavrogiannopoulos |
6 | | * |
7 | | * This file is part of GnuTLS. |
8 | | * |
9 | | * The GnuTLS is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public License |
11 | | * as published by the Free Software Foundation; either version 2.1 of |
12 | | * the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, but |
15 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
21 | | * |
22 | | */ |
23 | | |
24 | | /* Functions that are supposed to run after the handshake procedure is |
25 | | * finished. These functions activate the established security parameters. |
26 | | */ |
27 | | |
28 | | #include "gnutls_int.h" |
29 | | #include <constate.h> |
30 | | #include "errors.h" |
31 | | #include "fips.h" |
32 | | #include <kx.h> |
33 | | #include <algorithms.h> |
34 | | #include <num.h> |
35 | | #include <datum.h> |
36 | | #include <state.h> |
37 | | #include <hello_ext.h> |
38 | | #include <buffers.h> |
39 | | #include "dtls.h" |
40 | | #include "secrets.h" |
41 | | #include "handshake.h" |
42 | | #include "crypto-api.h" |
43 | | #include "locks.h" |
44 | | |
45 | | static const char keyexp[] = "key expansion"; |
46 | | static const int keyexp_length = sizeof(keyexp) - 1; |
47 | | |
48 | | static int |
49 | | _tls13_init_record_state(gnutls_cipher_algorithm_t algo, |
50 | | record_state_st * state); |
51 | | |
52 | | /* This function is to be called after handshake, when master_secret, |
53 | | * client_random and server_random have been initialized. |
54 | | * This function creates the keys and stores them into pending session. |
55 | | * (session->cipher_specs) |
56 | | */ |
57 | | static int |
58 | | _gnutls_set_keys(gnutls_session_t session, record_parameters_st * params, |
59 | | unsigned hash_size, unsigned IV_size, unsigned key_size) |
60 | 0 | { |
61 | 0 | uint8_t rnd[2 * GNUTLS_RANDOM_SIZE]; |
62 | 0 | int pos, ret; |
63 | 0 | int block_size; |
64 | 0 | char buf[4 * MAX_HASH_SIZE + 4 * MAX_CIPHER_KEY_SIZE + |
65 | 0 | 4 * MAX_CIPHER_BLOCK_SIZE]; |
66 | | /* avoid using malloc */ |
67 | 0 | uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE + |
68 | 0 | 2 * MAX_CIPHER_BLOCK_SIZE]; |
69 | 0 | record_state_st *client_write, *server_write; |
70 | |
|
71 | 0 | if (session->security_parameters.entity == GNUTLS_CLIENT) { |
72 | 0 | client_write = ¶ms->write; |
73 | 0 | server_write = ¶ms->read; |
74 | 0 | } else { |
75 | 0 | client_write = ¶ms->read; |
76 | 0 | server_write = ¶ms->write; |
77 | 0 | } |
78 | |
|
79 | 0 | block_size = 2 * hash_size + 2 * key_size; |
80 | 0 | block_size += 2 * IV_size; |
81 | |
|
82 | 0 | memcpy(rnd, session->security_parameters.server_random, |
83 | 0 | GNUTLS_RANDOM_SIZE); |
84 | 0 | memcpy(&rnd[GNUTLS_RANDOM_SIZE], |
85 | 0 | session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); |
86 | |
|
87 | 0 | _gnutls_memory_mark_defined(session->security_parameters.master_secret, |
88 | 0 | GNUTLS_MASTER_SIZE); |
89 | | #ifdef ENABLE_SSL3 |
90 | | if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3 */ |
91 | | ret = |
92 | | _gnutls_ssl3_generate_random |
93 | | (session->security_parameters.master_secret, |
94 | | GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, |
95 | | block_size, key_block); |
96 | | } else /* TLS 1.0+ */ |
97 | | #endif |
98 | 0 | ret = |
99 | 0 | _gnutls_PRF(session, |
100 | 0 | session->security_parameters.master_secret, |
101 | 0 | GNUTLS_MASTER_SIZE, keyexp, keyexp_length, |
102 | 0 | rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, |
103 | 0 | key_block); |
104 | |
|
105 | 0 | if (ret < 0) { |
106 | 0 | _gnutls_memory_mark_undefined(session-> |
107 | 0 | security_parameters.master_secret, |
108 | 0 | GNUTLS_MASTER_SIZE); |
109 | 0 | return gnutls_assert_val(ret); |
110 | 0 | } |
111 | | |
112 | 0 | _gnutls_hard_log("INT: KEY BLOCK[%d]: %s\n", block_size, |
113 | 0 | _gnutls_bin2hex(key_block, block_size, buf, |
114 | 0 | sizeof(buf), NULL)); |
115 | |
|
116 | 0 | pos = 0; |
117 | 0 | if (hash_size > 0) { |
118 | 0 | assert(hash_size <= sizeof(client_write->mac_key)); |
119 | 0 | client_write->mac_key_size = hash_size; |
120 | 0 | memcpy(client_write->mac_key, &key_block[pos], hash_size); |
121 | |
|
122 | 0 | pos += hash_size; |
123 | |
|
124 | 0 | server_write->mac_key_size = hash_size; |
125 | 0 | memcpy(server_write->mac_key, &key_block[pos], hash_size); |
126 | |
|
127 | 0 | pos += hash_size; |
128 | |
|
129 | 0 | _gnutls_hard_log("INT: CLIENT MAC KEY [%d]: %s\n", |
130 | 0 | client_write->mac_key_size, |
131 | 0 | _gnutls_bin2hex(client_write->mac_key, |
132 | 0 | hash_size, |
133 | 0 | buf, sizeof(buf), NULL)); |
134 | |
|
135 | 0 | _gnutls_hard_log("INT: SERVER MAC KEY [%d]: %s\n", |
136 | 0 | server_write->mac_key_size, |
137 | 0 | _gnutls_bin2hex(server_write->mac_key, |
138 | 0 | hash_size, |
139 | 0 | buf, sizeof(buf), NULL)); |
140 | 0 | } |
141 | | |
142 | 0 | if (key_size > 0) { |
143 | 0 | assert(key_size <= sizeof(client_write->key)); |
144 | 0 | client_write->key_size = key_size; |
145 | 0 | memcpy(client_write->key, &key_block[pos], key_size); |
146 | |
|
147 | 0 | pos += key_size; |
148 | |
|
149 | 0 | server_write->key_size = key_size; |
150 | 0 | memcpy(server_write->key, &key_block[pos], key_size); |
151 | |
|
152 | 0 | pos += key_size; |
153 | |
|
154 | 0 | _gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n", |
155 | 0 | key_size, |
156 | 0 | _gnutls_bin2hex(client_write->key, |
157 | 0 | key_size, |
158 | 0 | buf, sizeof(buf), NULL)); |
159 | |
|
160 | 0 | _gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n", |
161 | 0 | key_size, |
162 | 0 | _gnutls_bin2hex(server_write->key, |
163 | 0 | key_size, |
164 | 0 | buf, sizeof(buf), NULL)); |
165 | |
|
166 | 0 | } |
167 | | |
168 | | /* IV generation in export and non export ciphers. |
169 | | */ |
170 | 0 | if (IV_size > 0) { |
171 | 0 | assert(IV_size <= sizeof(client_write->iv)); |
172 | | |
173 | 0 | client_write->iv_size = IV_size; |
174 | 0 | memcpy(client_write->iv, &key_block[pos], IV_size); |
175 | |
|
176 | 0 | pos += IV_size; |
177 | |
|
178 | 0 | server_write->iv_size = IV_size; |
179 | 0 | memcpy(server_write->iv, &key_block[pos], IV_size); |
180 | |
|
181 | 0 | _gnutls_hard_log("INT: CLIENT WRITE IV [%d]: %s\n", |
182 | 0 | client_write->iv_size, |
183 | 0 | _gnutls_bin2hex(client_write->iv, |
184 | 0 | client_write->iv_size, |
185 | 0 | buf, sizeof(buf), NULL)); |
186 | |
|
187 | 0 | _gnutls_hard_log("INT: SERVER WRITE IV [%d]: %s\n", |
188 | 0 | server_write->iv_size, |
189 | 0 | _gnutls_bin2hex(server_write->iv, |
190 | 0 | server_write->iv_size, |
191 | 0 | buf, sizeof(buf), NULL)); |
192 | 0 | } |
193 | | |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | static int |
198 | | _tls13_update_keys(gnutls_session_t session, hs_stage_t stage, |
199 | | record_parameters_st * params, |
200 | | unsigned iv_size, unsigned key_size) |
201 | 0 | { |
202 | 0 | uint8_t key_block[MAX_CIPHER_KEY_SIZE]; |
203 | 0 | uint8_t iv_block[MAX_CIPHER_IV_SIZE]; |
204 | 0 | char buf[65]; |
205 | 0 | record_state_st *upd_state; |
206 | 0 | record_parameters_st *prev = NULL; |
207 | 0 | int ret; |
208 | | |
209 | | /* generate new keys for direction needed and copy old from previous epoch */ |
210 | |
|
211 | 0 | if (stage == STAGE_UPD_OURS) { |
212 | 0 | upd_state = ¶ms->write; |
213 | |
|
214 | 0 | ret = _gnutls_epoch_get(session, EPOCH_READ_CURRENT, &prev); |
215 | 0 | if (ret < 0) |
216 | 0 | return gnutls_assert_val(ret); |
217 | 0 | assert(prev != NULL); |
218 | | |
219 | 0 | params->read.sequence_number = prev->read.sequence_number; |
220 | |
|
221 | 0 | params->read.key_size = prev->read.key_size; |
222 | 0 | memcpy(params->read.key, prev->read.key, prev->read.key_size); |
223 | |
|
224 | 0 | _gnutls_hard_log("INT: READ KEY [%d]: %s\n", |
225 | 0 | params->read.key_size, |
226 | 0 | _gnutls_bin2hex(params->read.key, |
227 | 0 | params->read.key_size, buf, |
228 | 0 | sizeof(buf), NULL)); |
229 | |
|
230 | 0 | params->read.iv_size = prev->read.iv_size; |
231 | 0 | memcpy(params->read.iv, prev->read.iv, prev->read.key_size); |
232 | |
|
233 | 0 | _gnutls_hard_log("INT: READ IV [%d]: %s\n", |
234 | 0 | params->read.iv_size, |
235 | 0 | _gnutls_bin2hex(params->read.iv, |
236 | 0 | params->read.iv_size, buf, |
237 | 0 | sizeof(buf), NULL)); |
238 | 0 | } else { |
239 | 0 | upd_state = ¶ms->read; |
240 | |
|
241 | 0 | ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, &prev); |
242 | 0 | if (ret < 0) |
243 | 0 | return gnutls_assert_val(ret); |
244 | 0 | assert(prev != NULL); |
245 | | |
246 | 0 | params->write.sequence_number = prev->write.sequence_number; |
247 | |
|
248 | 0 | params->write.key_size = prev->write.key_size; |
249 | 0 | memcpy(params->write.key, prev->write.key, |
250 | 0 | prev->write.key_size); |
251 | |
|
252 | 0 | _gnutls_hard_log("INT: WRITE KEY [%d]: %s\n", |
253 | 0 | params->write.key_size, |
254 | 0 | _gnutls_bin2hex(params->write.key, |
255 | 0 | params->write.key_size, buf, |
256 | 0 | sizeof(buf), NULL)); |
257 | |
|
258 | 0 | params->write.iv_size = prev->write.iv_size; |
259 | 0 | memcpy(params->write.iv, prev->write.iv, prev->write.iv_size); |
260 | |
|
261 | 0 | _gnutls_hard_log("INT: WRITE IV [%d]: %s\n", |
262 | 0 | params->write.iv_size, |
263 | 0 | _gnutls_bin2hex(params->write.iv, |
264 | 0 | params->write.iv_size, buf, |
265 | 0 | sizeof(buf), NULL)); |
266 | 0 | } |
267 | | |
268 | 0 | if ((session->security_parameters.entity == GNUTLS_CLIENT |
269 | 0 | && stage == STAGE_UPD_OURS) |
270 | 0 | || (session->security_parameters.entity == GNUTLS_SERVER |
271 | 0 | && stage == STAGE_UPD_PEERS)) { |
272 | | |
273 | | /* client keys */ |
274 | 0 | ret = _tls13_expand_secret(session, APPLICATION_TRAFFIC_UPDATE, |
275 | 0 | sizeof(APPLICATION_TRAFFIC_UPDATE) - |
276 | 0 | 1, NULL, 0, |
277 | 0 | session->key.proto.tls13.ap_ckey, |
278 | 0 | session->security_parameters. |
279 | 0 | prf->output_size, |
280 | 0 | session->key.proto.tls13.ap_ckey); |
281 | 0 | if (ret < 0) |
282 | 0 | return gnutls_assert_val(ret); |
283 | | |
284 | 0 | ret = |
285 | 0 | _tls13_expand_secret(session, "key", 3, NULL, 0, |
286 | 0 | session->key.proto.tls13.ap_ckey, |
287 | 0 | key_size, key_block); |
288 | 0 | if (ret < 0) |
289 | 0 | return gnutls_assert_val(ret); |
290 | | |
291 | 0 | ret = |
292 | 0 | _tls13_expand_secret(session, "iv", 2, NULL, 0, |
293 | 0 | session->key.proto.tls13.ap_ckey, |
294 | 0 | iv_size, iv_block); |
295 | 0 | if (ret < 0) |
296 | 0 | return gnutls_assert_val(ret); |
297 | 0 | } else { |
298 | 0 | ret = _tls13_expand_secret(session, APPLICATION_TRAFFIC_UPDATE, |
299 | 0 | sizeof(APPLICATION_TRAFFIC_UPDATE) - |
300 | 0 | 1, NULL, 0, |
301 | 0 | session->key.proto.tls13.ap_skey, |
302 | 0 | session->security_parameters. |
303 | 0 | prf->output_size, |
304 | 0 | session->key.proto.tls13.ap_skey); |
305 | 0 | if (ret < 0) |
306 | 0 | return gnutls_assert_val(ret); |
307 | | |
308 | 0 | ret = |
309 | 0 | _tls13_expand_secret(session, "key", 3, NULL, 0, |
310 | 0 | session->key.proto.tls13.ap_skey, |
311 | 0 | key_size, key_block); |
312 | 0 | if (ret < 0) |
313 | 0 | return gnutls_assert_val(ret); |
314 | | |
315 | 0 | ret = |
316 | 0 | _tls13_expand_secret(session, "iv", 2, NULL, 0, |
317 | 0 | session->key.proto.tls13.ap_skey, |
318 | 0 | iv_size, iv_block); |
319 | 0 | if (ret < 0) |
320 | 0 | return gnutls_assert_val(ret); |
321 | 0 | } |
322 | | |
323 | 0 | upd_state->mac_key_size = 0; |
324 | |
|
325 | 0 | assert(key_size <= sizeof(upd_state->key)); |
326 | 0 | memcpy(upd_state->key, key_block, key_size); |
327 | 0 | upd_state->key_size = key_size; |
328 | |
|
329 | 0 | _gnutls_hard_log("INT: NEW %s KEY [%d]: %s\n", |
330 | 0 | (upd_state == ¶ms->read) ? "READ" : "WRITE", |
331 | 0 | key_size, |
332 | 0 | _gnutls_bin2hex(key_block, key_size, |
333 | 0 | buf, sizeof(buf), NULL)); |
334 | |
|
335 | 0 | if (iv_size > 0) { |
336 | 0 | assert(iv_size <= sizeof(upd_state->iv)); |
337 | 0 | memcpy(upd_state->iv, iv_block, iv_size); |
338 | 0 | upd_state->iv_size = iv_size; |
339 | |
|
340 | 0 | _gnutls_hard_log("INT: NEW %s IV [%d]: %s\n", |
341 | 0 | (upd_state == |
342 | 0 | ¶ms->read) ? "READ" : "WRITE", iv_size, |
343 | 0 | _gnutls_bin2hex(iv_block, iv_size, buf, |
344 | 0 | sizeof(buf), NULL)); |
345 | 0 | } |
346 | | |
347 | 0 | return 0; |
348 | 0 | } |
349 | | |
350 | | static int |
351 | | _tls13_set_early_keys(gnutls_session_t session, |
352 | | record_parameters_st * params, |
353 | | unsigned iv_size, unsigned key_size) |
354 | 0 | { |
355 | 0 | uint8_t key_block[MAX_CIPHER_KEY_SIZE]; |
356 | 0 | uint8_t iv_block[MAX_CIPHER_IV_SIZE]; |
357 | 0 | char buf[65]; |
358 | 0 | record_state_st *early_state; |
359 | 0 | int ret; |
360 | |
|
361 | 0 | if (session->security_parameters.entity == GNUTLS_CLIENT && |
362 | 0 | !(session->internals.hsk_flags & HSK_TLS13_TICKET_SENT)) { |
363 | 0 | return GNUTLS_E_INVALID_REQUEST; |
364 | 0 | } |
365 | | |
366 | 0 | ret = |
367 | 0 | _tls13_expand_secret2(session->internals. |
368 | 0 | resumed_security_parameters.prf, "key", 3, |
369 | 0 | NULL, 0, session->key.proto.tls13.e_ckey, |
370 | 0 | key_size, key_block); |
371 | 0 | if (ret < 0) |
372 | 0 | return gnutls_assert_val(ret); |
373 | | |
374 | 0 | ret = |
375 | 0 | _tls13_expand_secret2(session->internals. |
376 | 0 | resumed_security_parameters.prf, "iv", 2, |
377 | 0 | NULL, 0, session->key.proto.tls13.e_ckey, |
378 | 0 | iv_size, iv_block); |
379 | 0 | if (ret < 0) |
380 | 0 | return gnutls_assert_val(ret); |
381 | | |
382 | 0 | if (session->security_parameters.entity == GNUTLS_CLIENT) { |
383 | 0 | early_state = ¶ms->write; |
384 | 0 | } else { |
385 | 0 | early_state = ¶ms->read; |
386 | 0 | } |
387 | |
|
388 | 0 | early_state->mac_key_size = 0; |
389 | |
|
390 | 0 | assert(key_size <= sizeof(early_state->key)); |
391 | 0 | memcpy(early_state->key, key_block, key_size); |
392 | 0 | early_state->key_size = key_size; |
393 | |
|
394 | 0 | _gnutls_hard_log("INT: EARLY KEY [%d]: %s\n", |
395 | 0 | key_size, |
396 | 0 | _gnutls_bin2hex(key_block, key_size, |
397 | 0 | buf, sizeof(buf), NULL)); |
398 | |
|
399 | 0 | if (iv_size > 0) { |
400 | 0 | assert(iv_size <= sizeof(early_state->iv)); |
401 | 0 | memcpy(early_state->iv, iv_block, iv_size); |
402 | 0 | early_state->iv_size = iv_size; |
403 | |
|
404 | 0 | _gnutls_hard_log("INT: EARLY IV [%d]: %s\n", |
405 | 0 | iv_size, |
406 | 0 | _gnutls_bin2hex(iv_block, iv_size, |
407 | 0 | buf, sizeof(buf), NULL)); |
408 | 0 | } |
409 | | |
410 | 0 | return 0; |
411 | 0 | } |
412 | | |
413 | | static int |
414 | | _tls13_set_keys(gnutls_session_t session, hs_stage_t stage, |
415 | | record_parameters_st * params, |
416 | | unsigned iv_size, unsigned key_size) |
417 | 0 | { |
418 | 0 | uint8_t ckey_block[MAX_CIPHER_KEY_SIZE]; |
419 | 0 | uint8_t civ_block[MAX_CIPHER_IV_SIZE]; |
420 | 0 | uint8_t skey_block[MAX_CIPHER_KEY_SIZE]; |
421 | 0 | uint8_t siv_block[MAX_CIPHER_IV_SIZE]; |
422 | 0 | char buf[65]; |
423 | 0 | record_state_st *client_write, *server_write; |
424 | 0 | const char *label; |
425 | 0 | unsigned label_size, hsk_len; |
426 | 0 | const char *keylog_label; |
427 | 0 | void *ckey, *skey; |
428 | 0 | int ret; |
429 | |
|
430 | 0 | if (stage == STAGE_UPD_OURS || stage == STAGE_UPD_PEERS) |
431 | 0 | return _tls13_update_keys(session, stage, |
432 | 0 | params, iv_size, key_size); |
433 | | |
434 | 0 | else if (stage == STAGE_EARLY) |
435 | 0 | return _tls13_set_early_keys(session, |
436 | 0 | params, iv_size, key_size); |
437 | | |
438 | 0 | else if (stage == STAGE_HS) { |
439 | 0 | label = HANDSHAKE_CLIENT_TRAFFIC_LABEL; |
440 | 0 | label_size = sizeof(HANDSHAKE_CLIENT_TRAFFIC_LABEL) - 1; |
441 | 0 | hsk_len = session->internals.handshake_hash_buffer.length; |
442 | 0 | keylog_label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; |
443 | 0 | ckey = session->key.proto.tls13.hs_ckey; |
444 | 0 | } else { |
445 | 0 | label = APPLICATION_CLIENT_TRAFFIC_LABEL; |
446 | 0 | label_size = sizeof(APPLICATION_CLIENT_TRAFFIC_LABEL) - 1; |
447 | 0 | hsk_len = |
448 | 0 | session-> |
449 | 0 | internals.handshake_hash_buffer_server_finished_len; |
450 | 0 | keylog_label = "CLIENT_TRAFFIC_SECRET_0"; |
451 | 0 | ckey = session->key.proto.tls13.ap_ckey; |
452 | 0 | } |
453 | | |
454 | 0 | ret = _tls13_derive_secret(session, label, label_size, |
455 | 0 | session->internals. |
456 | 0 | handshake_hash_buffer.data, hsk_len, |
457 | 0 | session->key.proto.tls13.temp_secret, ckey); |
458 | 0 | if (ret < 0) |
459 | 0 | return gnutls_assert_val(ret); |
460 | | |
461 | 0 | ret = _gnutls_call_keylog_func(session, keylog_label, |
462 | 0 | ckey, |
463 | 0 | session->security_parameters. |
464 | 0 | prf->output_size); |
465 | 0 | if (ret < 0) |
466 | 0 | return gnutls_assert_val(ret); |
467 | | |
468 | | /* client keys */ |
469 | 0 | ret = |
470 | 0 | _tls13_expand_secret(session, "key", 3, NULL, 0, ckey, key_size, |
471 | 0 | ckey_block); |
472 | 0 | if (ret < 0) |
473 | 0 | return gnutls_assert_val(ret); |
474 | | |
475 | 0 | ret = |
476 | 0 | _tls13_expand_secret(session, "iv", 2, NULL, 0, ckey, iv_size, |
477 | 0 | civ_block); |
478 | 0 | if (ret < 0) |
479 | 0 | return gnutls_assert_val(ret); |
480 | | |
481 | | /* server keys */ |
482 | 0 | if (stage == STAGE_HS) { |
483 | 0 | label = HANDSHAKE_SERVER_TRAFFIC_LABEL; |
484 | 0 | label_size = sizeof(HANDSHAKE_SERVER_TRAFFIC_LABEL) - 1; |
485 | 0 | keylog_label = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; |
486 | 0 | skey = session->key.proto.tls13.hs_skey; |
487 | 0 | } else { |
488 | 0 | label = APPLICATION_SERVER_TRAFFIC_LABEL; |
489 | 0 | label_size = sizeof(APPLICATION_SERVER_TRAFFIC_LABEL) - 1; |
490 | 0 | keylog_label = "SERVER_TRAFFIC_SECRET_0"; |
491 | 0 | skey = session->key.proto.tls13.ap_skey; |
492 | 0 | } |
493 | |
|
494 | 0 | ret = _tls13_derive_secret(session, label, label_size, |
495 | 0 | session->internals. |
496 | 0 | handshake_hash_buffer.data, hsk_len, |
497 | 0 | session->key.proto.tls13.temp_secret, skey); |
498 | |
|
499 | 0 | if (ret < 0) |
500 | 0 | return gnutls_assert_val(ret); |
501 | | |
502 | 0 | ret = _gnutls_call_keylog_func(session, keylog_label, |
503 | 0 | skey, |
504 | 0 | session->security_parameters. |
505 | 0 | prf->output_size); |
506 | 0 | if (ret < 0) |
507 | 0 | return gnutls_assert_val(ret); |
508 | | |
509 | 0 | ret = |
510 | 0 | _tls13_expand_secret(session, "key", 3, NULL, 0, skey, key_size, |
511 | 0 | skey_block); |
512 | 0 | if (ret < 0) |
513 | 0 | return gnutls_assert_val(ret); |
514 | | |
515 | 0 | ret = |
516 | 0 | _tls13_expand_secret(session, "iv", 2, NULL, 0, skey, iv_size, |
517 | 0 | siv_block); |
518 | 0 | if (ret < 0) |
519 | 0 | return gnutls_assert_val(ret); |
520 | | |
521 | 0 | if (session->security_parameters.entity == GNUTLS_CLIENT) { |
522 | 0 | client_write = ¶ms->write; |
523 | 0 | server_write = ¶ms->read; |
524 | 0 | } else { |
525 | 0 | client_write = ¶ms->read; |
526 | 0 | server_write = ¶ms->write; |
527 | 0 | } |
528 | |
|
529 | 0 | client_write->mac_key_size = 0; |
530 | 0 | server_write->mac_key_size = 0; |
531 | |
|
532 | 0 | assert(key_size <= sizeof(client_write->key)); |
533 | 0 | memcpy(client_write->key, ckey_block, key_size); |
534 | 0 | client_write->key_size = key_size; |
535 | |
|
536 | 0 | _gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n", |
537 | 0 | key_size, |
538 | 0 | _gnutls_bin2hex(ckey_block, key_size, |
539 | 0 | buf, sizeof(buf), NULL)); |
540 | |
|
541 | 0 | memcpy(server_write->key, skey_block, key_size); |
542 | 0 | server_write->key_size = key_size; |
543 | |
|
544 | 0 | _gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n", |
545 | 0 | key_size, |
546 | 0 | _gnutls_bin2hex(skey_block, key_size, |
547 | 0 | buf, sizeof(buf), NULL)); |
548 | |
|
549 | 0 | if (iv_size > 0) { |
550 | 0 | assert(iv_size <= sizeof(client_write->iv)); |
551 | 0 | memcpy(client_write->iv, civ_block, iv_size); |
552 | 0 | client_write->iv_size = iv_size; |
553 | |
|
554 | 0 | _gnutls_hard_log("INT: CLIENT WRITE IV [%d]: %s\n", |
555 | 0 | iv_size, |
556 | 0 | _gnutls_bin2hex(civ_block, iv_size, |
557 | 0 | buf, sizeof(buf), NULL)); |
558 | |
|
559 | 0 | memcpy(server_write->iv, siv_block, iv_size); |
560 | 0 | server_write->iv_size = iv_size; |
561 | |
|
562 | 0 | _gnutls_hard_log("INT: SERVER WRITE IV [%d]: %s\n", |
563 | 0 | iv_size, |
564 | 0 | _gnutls_bin2hex(siv_block, iv_size, |
565 | 0 | buf, sizeof(buf), NULL)); |
566 | 0 | } |
567 | | |
568 | 0 | client_write->level = server_write->level = stage == STAGE_HS ? |
569 | 0 | GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE : |
570 | 0 | GNUTLS_ENCRYPTION_LEVEL_APPLICATION; |
571 | |
|
572 | 0 | return 0; |
573 | 0 | } |
574 | | |
575 | | static int |
576 | | _gnutls_init_record_state(record_parameters_st * params, |
577 | | const version_entry_st * ver, int read, |
578 | | record_state_st * state) |
579 | 0 | { |
580 | 0 | int ret; |
581 | 0 | gnutls_datum_t *iv = NULL, _iv; |
582 | 0 | gnutls_datum_t key; |
583 | 0 | gnutls_datum_t mac; |
584 | |
|
585 | 0 | _iv.data = state->iv; |
586 | 0 | _iv.size = state->iv_size; |
587 | |
|
588 | 0 | key.data = state->key; |
589 | 0 | key.size = state->key_size; |
590 | |
|
591 | 0 | mac.data = state->mac_key; |
592 | 0 | mac.size = state->mac_key_size; |
593 | |
|
594 | 0 | if (_gnutls_cipher_type(params->cipher) == CIPHER_BLOCK) { |
595 | 0 | if (!_gnutls_version_has_explicit_iv(ver)) |
596 | 0 | iv = &_iv; |
597 | 0 | } else if (_gnutls_cipher_type(params->cipher) == CIPHER_STREAM) { |
598 | | /* To handle GOST ciphersuites */ |
599 | 0 | if (_gnutls_cipher_get_implicit_iv_size(params->cipher)) |
600 | 0 | iv = &_iv; |
601 | 0 | } |
602 | |
|
603 | 0 | ret = _gnutls_auth_cipher_init(&state->ctx.tls12, |
604 | 0 | params->cipher, &key, iv, |
605 | 0 | params->mac, &mac, params->etm, |
606 | | #ifdef ENABLE_SSL3 |
607 | | (ver->id == GNUTLS_SSL3) ? 1 : 0, |
608 | | #endif |
609 | 0 | 1 - read /*1==encrypt */ ); |
610 | 0 | if (ret < 0 && params->cipher->id != GNUTLS_CIPHER_NULL) { |
611 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); |
612 | 0 | return gnutls_assert_val(ret); |
613 | 0 | } |
614 | | |
615 | 0 | if (is_cipher_algo_allowed(params->cipher->id)) |
616 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); |
617 | 0 | else |
618 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); |
619 | |
|
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | | int |
624 | | _gnutls_set_cipher_suite2(gnutls_session_t session, |
625 | | const gnutls_cipher_suite_entry_st * cs) |
626 | 0 | { |
627 | 0 | const cipher_entry_st *cipher_algo; |
628 | 0 | const mac_entry_st *mac_algo; |
629 | 0 | record_parameters_st *params; |
630 | 0 | int ret; |
631 | 0 | const version_entry_st *ver = get_version(session); |
632 | |
|
633 | 0 | ret = _gnutls_epoch_get(session, EPOCH_NEXT, ¶ms); |
634 | 0 | if (ret < 0) |
635 | 0 | return gnutls_assert_val(ret); |
636 | | |
637 | 0 | cipher_algo = cipher_to_entry(cs->block_algorithm); |
638 | 0 | mac_algo = mac_to_entry(cs->mac_algorithm); |
639 | |
|
640 | 0 | if (ver->tls13_sem && (session->internals.hsk_flags & HSK_HRR_SENT)) { |
641 | 0 | if (params->initialized && (params->cipher != cipher_algo || |
642 | 0 | params->mac != mac_algo |
643 | 0 | || cs != |
644 | 0 | session->security_parameters.cs)) |
645 | 0 | return |
646 | 0 | gnutls_assert_val |
647 | 0 | (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); |
648 | | |
649 | 0 | return 0; |
650 | 0 | } |
651 | | |
652 | | /* The params shouldn't have been initialized at this point, unless we |
653 | | * are doing trial encryption/decryption of early data. |
654 | | */ |
655 | 0 | if (unlikely |
656 | 0 | (!((session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT && |
657 | 0 | !IS_SERVER(session)) || |
658 | 0 | (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED && |
659 | 0 | IS_SERVER(session))) && |
660 | 0 | (params->initialized |
661 | 0 | || params->cipher != NULL || params->mac != NULL))) { |
662 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
663 | 0 | } |
664 | | |
665 | 0 | if (_gnutls_cipher_is_ok(cipher_algo) == 0 |
666 | 0 | || _gnutls_mac_is_ok(mac_algo) == 0) |
667 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
668 | | |
669 | 0 | if (_gnutls_version_has_selectable_prf(get_version(session))) { |
670 | 0 | if (cs->prf == GNUTLS_MAC_UNKNOWN || |
671 | 0 | _gnutls_mac_is_ok(mac_to_entry(cs->prf)) == 0) |
672 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
673 | 0 | session->security_parameters.prf = mac_to_entry(cs->prf); |
674 | 0 | } else { |
675 | 0 | session->security_parameters.prf = |
676 | 0 | mac_to_entry(GNUTLS_MAC_MD5_SHA1); |
677 | 0 | } |
678 | | |
679 | 0 | session->security_parameters.cs = cs; |
680 | 0 | params->cipher = cipher_algo; |
681 | 0 | params->mac = mac_algo; |
682 | |
|
683 | 0 | return 0; |
684 | 0 | } |
685 | | |
686 | | /* Sets the next epoch to be a clone of the current one. |
687 | | * The keys are not cloned, only the cipher and MAC. |
688 | | */ |
689 | | int _gnutls_epoch_dup(gnutls_session_t session, unsigned int epoch_rel) |
690 | 0 | { |
691 | 0 | record_parameters_st *prev; |
692 | 0 | record_parameters_st *next; |
693 | 0 | int ret; |
694 | |
|
695 | 0 | ret = _gnutls_epoch_get(session, epoch_rel, &prev); |
696 | 0 | if (ret < 0) |
697 | 0 | return gnutls_assert_val(ret); |
698 | | |
699 | 0 | ret = _gnutls_epoch_get(session, EPOCH_NEXT, &next); |
700 | 0 | if (ret < 0) { |
701 | 0 | ret = _gnutls_epoch_setup_next(session, 0, &next); |
702 | 0 | if (ret < 0) |
703 | 0 | return gnutls_assert_val(ret); |
704 | 0 | } |
705 | | |
706 | 0 | if (next->initialized || next->cipher != NULL || next->mac != NULL) |
707 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
708 | | |
709 | 0 | next->cipher = prev->cipher; |
710 | 0 | next->mac = prev->mac; |
711 | |
|
712 | 0 | return 0; |
713 | 0 | } |
714 | | |
715 | | int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch, |
716 | | hs_stage_t stage) |
717 | 0 | { |
718 | 0 | int hash_size; |
719 | 0 | int IV_size; |
720 | 0 | int key_size; |
721 | 0 | record_parameters_st *params; |
722 | 0 | int ret; |
723 | 0 | const version_entry_st *ver = |
724 | 0 | stage == STAGE_EARLY && !IS_SERVER(session) ? |
725 | 0 | session->internals.resumed_security_parameters.pversion : |
726 | 0 | get_version(session); |
727 | |
|
728 | 0 | if (unlikely(ver == NULL)) |
729 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
730 | | |
731 | 0 | ret = _gnutls_epoch_get(session, epoch, ¶ms); |
732 | 0 | if (ret < 0) |
733 | 0 | return gnutls_assert_val(ret); |
734 | | |
735 | 0 | if (params->initialized) |
736 | 0 | return 0; |
737 | | |
738 | 0 | _gnutls_record_log |
739 | 0 | ("REC[%p]: Initializing epoch #%u\n", session, params->epoch); |
740 | |
|
741 | 0 | if (_gnutls_cipher_is_ok(params->cipher) == 0 || |
742 | 0 | _gnutls_mac_is_ok(params->mac) == 0) |
743 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
744 | | |
745 | 0 | if (_gnutls_version_has_explicit_iv(ver) && |
746 | 0 | (_gnutls_cipher_type(params->cipher) != CIPHER_BLOCK)) { |
747 | 0 | IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); |
748 | 0 | } else { |
749 | 0 | IV_size = _gnutls_cipher_get_iv_size(params->cipher); |
750 | 0 | } |
751 | |
|
752 | 0 | key_size = _gnutls_cipher_get_key_size(params->cipher); |
753 | 0 | hash_size = _gnutls_mac_get_key_size(params->mac); |
754 | 0 | params->etm = session->security_parameters.etm; |
755 | |
|
756 | 0 | if (ver->tls13_sem) { |
757 | 0 | ret = _tls13_set_keys |
758 | 0 | (session, stage, params, IV_size, key_size); |
759 | 0 | if (ret < 0) |
760 | 0 | return gnutls_assert_val(ret); |
761 | | |
762 | 0 | if (stage != STAGE_EARLY || |
763 | 0 | session->security_parameters.entity == GNUTLS_SERVER) { |
764 | 0 | ret = |
765 | 0 | _tls13_init_record_state(params->cipher->id, |
766 | 0 | ¶ms->read); |
767 | 0 | if (ret < 0) |
768 | 0 | return gnutls_assert_val(ret); |
769 | 0 | } |
770 | | |
771 | 0 | if (stage != STAGE_EARLY || |
772 | 0 | session->security_parameters.entity == GNUTLS_CLIENT) { |
773 | 0 | ret = |
774 | 0 | _tls13_init_record_state(params->cipher->id, |
775 | 0 | ¶ms->write); |
776 | 0 | if (ret < 0) |
777 | 0 | return gnutls_assert_val(ret); |
778 | 0 | } |
779 | 0 | } else { |
780 | 0 | ret = _gnutls_set_keys |
781 | 0 | (session, params, hash_size, IV_size, key_size); |
782 | 0 | if (ret < 0) |
783 | 0 | return gnutls_assert_val(ret); |
784 | | |
785 | 0 | ret = _gnutls_init_record_state(params, ver, 1, ¶ms->read); |
786 | 0 | if (ret < 0) |
787 | 0 | return gnutls_assert_val(ret); |
788 | | |
789 | 0 | ret = _gnutls_init_record_state(params, ver, 0, ¶ms->write); |
790 | 0 | if (ret < 0) |
791 | 0 | return gnutls_assert_val(ret); |
792 | 0 | } |
793 | | |
794 | | /* The TLS1.3 limit of 256 additional bytes is also enforced under CBC |
795 | | * ciphers to ensure we interoperate with gnutls 2.12.x which could add padding |
796 | | * data exceeding the maximum. */ |
797 | 0 | if (ver->tls13_sem |
798 | 0 | || _gnutls_cipher_type(params->cipher) == CIPHER_BLOCK) { |
799 | 0 | session->internals.max_recv_size = 256; |
800 | 0 | } else { |
801 | 0 | session->internals.max_recv_size = 0; |
802 | 0 | } |
803 | |
|
804 | 0 | if (!ver->tls13_sem) { |
805 | 0 | session->internals.max_recv_size += |
806 | 0 | _gnutls_record_overhead(ver, params->cipher, params->mac, |
807 | 0 | 1); |
808 | 0 | if (session->internals.allow_large_records != 0) |
809 | 0 | session->internals.max_recv_size += EXTRA_COMP_SIZE; |
810 | 0 | } |
811 | |
|
812 | 0 | session->internals.max_recv_size += |
813 | 0 | session->security_parameters.max_record_recv_size + |
814 | 0 | RECORD_HEADER_SIZE(session); |
815 | |
|
816 | 0 | _dtls_reset_window(params); |
817 | |
|
818 | 0 | _gnutls_record_log("REC[%p]: Epoch #%u ready\n", session, |
819 | 0 | params->epoch); |
820 | |
|
821 | 0 | params->initialized = 1; |
822 | 0 | return 0; |
823 | 0 | } |
824 | | |
825 | | void _gnutls_set_resumed_parameters(gnutls_session_t session) |
826 | 0 | { |
827 | 0 | security_parameters_st *src = |
828 | 0 | &session->internals.resumed_security_parameters; |
829 | 0 | security_parameters_st *dst = &session->security_parameters; |
830 | 0 | const version_entry_st *ver = get_version(session); |
831 | | |
832 | | /* Under TLS 1.3, these values are items which are not |
833 | | * negotiated on the subsequent session. */ |
834 | 0 | if (!ver->tls13_sem) { |
835 | 0 | dst->cs = src->cs; |
836 | 0 | _gnutls_memory_mark_defined(dst->master_secret, |
837 | 0 | GNUTLS_MASTER_SIZE); |
838 | 0 | memcpy(dst->master_secret, src->master_secret, |
839 | 0 | GNUTLS_MASTER_SIZE); |
840 | 0 | _gnutls_memory_mark_defined(dst->client_random, |
841 | 0 | GNUTLS_RANDOM_SIZE); |
842 | 0 | memcpy(dst->client_random, src->client_random, |
843 | 0 | GNUTLS_RANDOM_SIZE); |
844 | 0 | _gnutls_memory_mark_defined(dst->server_random, |
845 | 0 | GNUTLS_RANDOM_SIZE); |
846 | 0 | memcpy(dst->server_random, src->server_random, |
847 | 0 | GNUTLS_RANDOM_SIZE); |
848 | 0 | dst->ext_master_secret = src->ext_master_secret; |
849 | 0 | dst->etm = src->etm; |
850 | 0 | dst->prf = src->prf; |
851 | 0 | dst->grp = src->grp; |
852 | 0 | dst->pversion = src->pversion; |
853 | 0 | } |
854 | 0 | memcpy(dst->session_id, src->session_id, GNUTLS_MAX_SESSION_ID_SIZE); |
855 | 0 | dst->session_id_size = src->session_id_size; |
856 | 0 | dst->timestamp = src->timestamp; |
857 | 0 | dst->client_ctype = src->client_ctype; |
858 | 0 | dst->server_ctype = src->server_ctype; |
859 | 0 | dst->client_auth_type = src->client_auth_type; |
860 | 0 | dst->server_auth_type = src->server_auth_type; |
861 | |
|
862 | 0 | if (!ver->tls13_sem && |
863 | 0 | !(session-> |
864 | 0 | internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED)) { |
865 | 0 | dst->max_record_recv_size = src->max_record_recv_size; |
866 | 0 | dst->max_record_send_size = src->max_record_send_size; |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | | /* Sets the current connection session to conform with the |
871 | | * Security parameters(pending session), and initializes encryption. |
872 | | * Actually it initializes and starts encryption ( so it needs |
873 | | * secrets and random numbers to have been negotiated) |
874 | | * This is to be called after sending the Change Cipher Spec packet. |
875 | | */ |
876 | | int _gnutls_connection_state_init(gnutls_session_t session) |
877 | 0 | { |
878 | 0 | int ret; |
879 | | |
880 | | /* Setup the master secret |
881 | | */ |
882 | 0 | if ((ret = _gnutls_generate_master(session, 0)) < 0) |
883 | 0 | return gnutls_assert_val(ret); |
884 | | |
885 | 0 | return 0; |
886 | 0 | } |
887 | | |
888 | | /* Initializes the read connection session |
889 | | * (read encrypted data) |
890 | | */ |
891 | | int _gnutls_read_connection_state_init(gnutls_session_t session) |
892 | 0 | { |
893 | 0 | const uint16_t epoch_next = session->security_parameters.epoch_next; |
894 | 0 | int ret; |
895 | | |
896 | | /* Update internals from CipherSuite selected. |
897 | | * If we are resuming just copy the connection session |
898 | | */ |
899 | 0 | if (session->internals.resumed && |
900 | 0 | session->security_parameters.entity == GNUTLS_CLIENT) |
901 | 0 | _gnutls_set_resumed_parameters(session); |
902 | |
|
903 | 0 | ret = _gnutls_epoch_set_keys(session, epoch_next, 0); |
904 | 0 | if (ret < 0) |
905 | 0 | return ret; |
906 | | |
907 | 0 | _gnutls_handshake_log("HSK[%p]: Cipher Suite: %s\n", |
908 | 0 | session, session->security_parameters.cs->name); |
909 | |
|
910 | 0 | session->security_parameters.epoch_read = epoch_next; |
911 | |
|
912 | 0 | return 0; |
913 | 0 | } |
914 | | |
915 | | /* Initializes the write connection session |
916 | | * (write encrypted data) |
917 | | */ |
918 | | int _gnutls_write_connection_state_init(gnutls_session_t session) |
919 | 0 | { |
920 | 0 | const uint16_t epoch_next = session->security_parameters.epoch_next; |
921 | 0 | int ret; |
922 | | |
923 | | /* reset max_record_send_size if it was negotiated in the |
924 | | * previous handshake using the record_size_limit extension */ |
925 | 0 | if (!(session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED) |
926 | 0 | && session->security_parameters.entity == GNUTLS_SERVER) |
927 | 0 | session->security_parameters.max_record_send_size = |
928 | 0 | session->security_parameters.max_user_record_send_size; |
929 | | |
930 | | /* Update internals from CipherSuite selected. |
931 | | * If we are resuming just copy the connection session |
932 | | */ |
933 | 0 | if (session->internals.resumed && |
934 | 0 | session->security_parameters.entity == GNUTLS_SERVER) |
935 | 0 | _gnutls_set_resumed_parameters(session); |
936 | |
|
937 | 0 | ret = _gnutls_epoch_set_keys(session, epoch_next, 0); |
938 | 0 | if (ret < 0) |
939 | 0 | return gnutls_assert_val(ret); |
940 | | |
941 | 0 | _gnutls_handshake_log("HSK[%p]: Cipher Suite: %s\n", session, |
942 | 0 | session->security_parameters.cs->name); |
943 | |
|
944 | 0 | _gnutls_handshake_log |
945 | 0 | ("HSK[%p]: Initializing internal [write] cipher sessions\n", |
946 | 0 | session); |
947 | |
|
948 | 0 | session->security_parameters.epoch_write = epoch_next; |
949 | |
|
950 | 0 | return 0; |
951 | 0 | } |
952 | | |
953 | | static inline int |
954 | | epoch_resolve(gnutls_session_t session, |
955 | | unsigned int epoch_rel, uint16_t * epoch_out) |
956 | 0 | { |
957 | 0 | switch (epoch_rel) { |
958 | 0 | case EPOCH_READ_CURRENT: |
959 | 0 | *epoch_out = session->security_parameters.epoch_read; |
960 | 0 | return 0; |
961 | | |
962 | 0 | case EPOCH_WRITE_CURRENT: |
963 | 0 | *epoch_out = session->security_parameters.epoch_write; |
964 | 0 | return 0; |
965 | | |
966 | 0 | case EPOCH_NEXT: |
967 | 0 | *epoch_out = session->security_parameters.epoch_next; |
968 | 0 | return 0; |
969 | | |
970 | 0 | default: |
971 | 0 | if (epoch_rel > 0xffffu) |
972 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
973 | | |
974 | 0 | *epoch_out = epoch_rel; |
975 | 0 | return 0; |
976 | 0 | } |
977 | 0 | } |
978 | | |
979 | | static inline record_parameters_st **epoch_get_slot(gnutls_session_t |
980 | | session, uint16_t epoch) |
981 | 0 | { |
982 | 0 | uint16_t epoch_index = epoch - session->security_parameters.epoch_min; |
983 | |
|
984 | 0 | if (epoch_index >= MAX_EPOCH_INDEX) { |
985 | 0 | _gnutls_handshake_log |
986 | 0 | ("Epoch %d out of range (idx: %d, max: %d)\n", |
987 | 0 | (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX); |
988 | 0 | gnutls_assert(); |
989 | 0 | return NULL; |
990 | 0 | } |
991 | | /* The slot may still be empty (NULL) */ |
992 | 0 | return &session->record_parameters[epoch_index]; |
993 | 0 | } |
994 | | |
995 | | int |
996 | | _gnutls_epoch_get(gnutls_session_t session, unsigned int epoch_rel, |
997 | | record_parameters_st ** params_out) |
998 | 0 | { |
999 | 0 | uint16_t epoch; |
1000 | 0 | record_parameters_st **params; |
1001 | 0 | int ret; |
1002 | |
|
1003 | 0 | gnutls_mutex_lock(&session->internals.epoch_lock); |
1004 | |
|
1005 | 0 | ret = epoch_resolve(session, epoch_rel, &epoch); |
1006 | 0 | if (ret < 0) { |
1007 | 0 | gnutls_assert(); |
1008 | 0 | goto cleanup; |
1009 | 0 | } |
1010 | | |
1011 | 0 | params = epoch_get_slot(session, epoch); |
1012 | 0 | if (params == NULL || *params == NULL) { |
1013 | 0 | ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
1014 | 0 | goto cleanup; |
1015 | 0 | } |
1016 | | |
1017 | 0 | if (params_out) |
1018 | 0 | *params_out = *params; |
1019 | |
|
1020 | 0 | ret = 0; |
1021 | |
|
1022 | 0 | cleanup: |
1023 | 0 | gnutls_mutex_unlock(&session->internals.epoch_lock); |
1024 | 0 | return ret; |
1025 | 0 | } |
1026 | | |
1027 | | /* Ensures that the next epoch is setup. When an epoch will null ciphers |
1028 | | * is to be setup, call with @null_epoch set to true. In that case |
1029 | | * the epoch is fully initialized after call. |
1030 | | */ |
1031 | | int |
1032 | | _gnutls_epoch_setup_next(gnutls_session_t session, unsigned null_epoch, |
1033 | | record_parameters_st ** newp) |
1034 | 0 | { |
1035 | 0 | record_parameters_st **slot; |
1036 | |
|
1037 | 0 | slot = epoch_get_slot(session, session->security_parameters.epoch_next); |
1038 | | |
1039 | | /* If slot out of range or not empty. */ |
1040 | 0 | if (slot == NULL) |
1041 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
1042 | | |
1043 | 0 | if (*slot != NULL) { /* already initialized */ |
1044 | 0 | if (unlikely(null_epoch && !(*slot)->initialized)) |
1045 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1046 | | |
1047 | 0 | if (unlikely |
1048 | 0 | ((*slot)->epoch != session->security_parameters.epoch_next)) |
1049 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1050 | | |
1051 | 0 | goto finish; |
1052 | 0 | } |
1053 | | |
1054 | 0 | _gnutls_record_log("REC[%p]: Allocating epoch #%u\n", session, |
1055 | 0 | session->security_parameters.epoch_next); |
1056 | |
|
1057 | 0 | *slot = gnutls_calloc(1, sizeof(record_parameters_st)); |
1058 | 0 | if (*slot == NULL) |
1059 | 0 | return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); |
1060 | | |
1061 | 0 | (*slot)->epoch = session->security_parameters.epoch_next; |
1062 | |
|
1063 | 0 | if (null_epoch) { |
1064 | 0 | (*slot)->cipher = cipher_to_entry(GNUTLS_CIPHER_NULL); |
1065 | 0 | (*slot)->mac = mac_to_entry(GNUTLS_MAC_NULL); |
1066 | 0 | (*slot)->initialized = 1; |
1067 | 0 | } else { |
1068 | 0 | (*slot)->cipher = NULL; |
1069 | 0 | (*slot)->mac = NULL; |
1070 | 0 | } |
1071 | |
|
1072 | 0 | if (IS_DTLS(session)) { |
1073 | 0 | uint64_t seq = (*slot)->write.sequence_number; |
1074 | 0 | seq &= UINT64_C(0xffffffffffff); |
1075 | 0 | seq |= |
1076 | 0 | ((uint64_t) session->security_parameters.epoch_next) << 48; |
1077 | 0 | (*slot)->write.sequence_number = seq; |
1078 | 0 | } |
1079 | |
|
1080 | 0 | finish: |
1081 | 0 | if (newp != NULL) |
1082 | 0 | *newp = *slot; |
1083 | |
|
1084 | 0 | return 0; |
1085 | 0 | } |
1086 | | |
1087 | | static inline int |
1088 | | epoch_is_active(gnutls_session_t session, record_parameters_st * params) |
1089 | 0 | { |
1090 | 0 | const security_parameters_st *sp = &session->security_parameters; |
1091 | |
|
1092 | 0 | if (params->epoch == sp->epoch_read) |
1093 | 0 | return 1; |
1094 | | |
1095 | 0 | if (params->epoch == sp->epoch_write) |
1096 | 0 | return 1; |
1097 | | |
1098 | 0 | if (params->epoch == sp->epoch_next) |
1099 | 0 | return 1; |
1100 | | |
1101 | 0 | return 0; |
1102 | 0 | } |
1103 | | |
1104 | | static inline int |
1105 | | epoch_alive(gnutls_session_t session, record_parameters_st * params) |
1106 | 0 | { |
1107 | 0 | if (params->usage_cnt > 0) |
1108 | 0 | return 1; |
1109 | | |
1110 | 0 | return epoch_is_active(session, params); |
1111 | 0 | } |
1112 | | |
1113 | | void _gnutls_epoch_gc(gnutls_session_t session) |
1114 | 0 | { |
1115 | 0 | int i, j; |
1116 | 0 | unsigned int min_index = 0; |
1117 | |
|
1118 | 0 | _gnutls_record_log("REC[%p]: Start of epoch cleanup\n", session); |
1119 | |
|
1120 | 0 | gnutls_mutex_lock(&session->internals.epoch_lock); |
1121 | | |
1122 | | /* Free all dead cipher state */ |
1123 | 0 | for (i = 0; i < MAX_EPOCH_INDEX; i++) { |
1124 | 0 | if (session->record_parameters[i] != NULL) { |
1125 | 0 | if (!epoch_is_active |
1126 | 0 | (session, session->record_parameters[i]) |
1127 | 0 | && session->record_parameters[i]->usage_cnt) |
1128 | 0 | _gnutls_record_log |
1129 | 0 | ("REC[%p]: Note inactive epoch %d has %d users\n", |
1130 | 0 | session, |
1131 | 0 | session->record_parameters[i]->epoch, |
1132 | 0 | session->record_parameters[i]->usage_cnt); |
1133 | 0 | if (!epoch_alive |
1134 | 0 | (session, session->record_parameters[i])) { |
1135 | 0 | _gnutls_epoch_free(session, |
1136 | 0 | session->record_parameters |
1137 | 0 | [i]); |
1138 | 0 | session->record_parameters[i] = NULL; |
1139 | 0 | } |
1140 | 0 | } |
1141 | 0 | } |
1142 | | |
1143 | | /* Look for contiguous NULLs at the start of the array */ |
1144 | 0 | for (i = 0; |
1145 | 0 | i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL; |
1146 | 0 | i++) ; |
1147 | 0 | min_index = i; |
1148 | | |
1149 | | /* Pick up the slack in the epoch window. */ |
1150 | 0 | if (min_index != 0) { |
1151 | 0 | for (i = 0, j = min_index; j < MAX_EPOCH_INDEX; i++, j++) { |
1152 | 0 | session->record_parameters[i] = |
1153 | 0 | session->record_parameters[j]; |
1154 | 0 | session->record_parameters[j] = NULL; |
1155 | 0 | } |
1156 | 0 | } |
1157 | | |
1158 | | /* Set the new epoch_min */ |
1159 | 0 | if (session->record_parameters[0] != NULL) |
1160 | 0 | session->security_parameters.epoch_min = |
1161 | 0 | session->record_parameters[0]->epoch; |
1162 | |
|
1163 | 0 | gnutls_mutex_unlock(&session->internals.epoch_lock); |
1164 | |
|
1165 | 0 | _gnutls_record_log("REC[%p]: End of epoch cleanup\n", session); |
1166 | 0 | } |
1167 | | |
1168 | | static inline void free_record_state(record_state_st * state) |
1169 | 0 | { |
1170 | 0 | zeroize_temp_key(state->mac_key, state->mac_key_size); |
1171 | 0 | zeroize_temp_key(state->iv, state->iv_size); |
1172 | 0 | zeroize_temp_key(state->key, state->key_size); |
1173 | |
|
1174 | 0 | if (state->is_aead) |
1175 | 0 | _gnutls_aead_cipher_deinit(&state->ctx.aead); |
1176 | 0 | else |
1177 | 0 | _gnutls_auth_cipher_deinit(&state->ctx.tls12); |
1178 | 0 | } |
1179 | | |
1180 | | void _gnutls_epoch_free(gnutls_session_t session, record_parameters_st * params) |
1181 | 0 | { |
1182 | 0 | _gnutls_record_log("REC[%p]: Epoch #%u freed\n", session, |
1183 | 0 | params->epoch); |
1184 | |
|
1185 | 0 | free_record_state(¶ms->read); |
1186 | 0 | free_record_state(¶ms->write); |
1187 | |
|
1188 | 0 | gnutls_free(params); |
1189 | 0 | } |
1190 | | |
1191 | | static int |
1192 | | _gnutls_call_secret_func(gnutls_session_t session, |
1193 | | hs_stage_t stage, bool for_read, bool for_write) |
1194 | 0 | { |
1195 | 0 | const mac_entry_st *prf = NULL; |
1196 | 0 | gnutls_record_encryption_level_t level; |
1197 | 0 | void *secret_read = NULL, *secret_write = NULL; |
1198 | |
|
1199 | 0 | if (session->internals.h_secret_func == NULL) |
1200 | 0 | return 0; |
1201 | | |
1202 | 0 | switch (stage) { |
1203 | 0 | case STAGE_EARLY: |
1204 | 0 | prf = session->key.binders[0].prf; |
1205 | 0 | level = GNUTLS_ENCRYPTION_LEVEL_EARLY; |
1206 | 0 | if (for_read) { |
1207 | 0 | if (unlikely |
1208 | 0 | (session->security_parameters.entity == |
1209 | 0 | GNUTLS_CLIENT)) |
1210 | 0 | return |
1211 | 0 | gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1212 | 0 | secret_read = session->key.proto.tls13.e_ckey; |
1213 | 0 | } |
1214 | 0 | if (for_write) { |
1215 | 0 | if (unlikely |
1216 | 0 | (session->security_parameters.entity == |
1217 | 0 | GNUTLS_SERVER)) |
1218 | 0 | return |
1219 | 0 | gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1220 | 0 | secret_write = session->key.proto.tls13.e_ckey; |
1221 | 0 | } |
1222 | 0 | break; |
1223 | 0 | case STAGE_HS: |
1224 | 0 | prf = session->security_parameters.prf; |
1225 | 0 | level = GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE; |
1226 | 0 | if (for_read) |
1227 | 0 | secret_read = |
1228 | 0 | session->security_parameters.entity == |
1229 | 0 | GNUTLS_CLIENT ? session->key.proto. |
1230 | 0 | tls13.hs_skey : session->key.proto.tls13.hs_ckey; |
1231 | 0 | if (for_write) |
1232 | 0 | secret_write = |
1233 | 0 | session->security_parameters.entity == |
1234 | 0 | GNUTLS_CLIENT ? session->key.proto. |
1235 | 0 | tls13.hs_ckey : session->key.proto.tls13.hs_skey; |
1236 | 0 | break; |
1237 | 0 | case STAGE_APP: |
1238 | 0 | case STAGE_UPD_OURS: |
1239 | 0 | case STAGE_UPD_PEERS: |
1240 | 0 | prf = session->security_parameters.prf; |
1241 | 0 | level = GNUTLS_ENCRYPTION_LEVEL_APPLICATION; |
1242 | 0 | if (for_read) |
1243 | 0 | secret_read = |
1244 | 0 | session->security_parameters.entity == |
1245 | 0 | GNUTLS_CLIENT ? session->key.proto. |
1246 | 0 | tls13.ap_skey : session->key.proto.tls13.ap_ckey; |
1247 | 0 | if (for_write) |
1248 | 0 | secret_write = |
1249 | 0 | session->security_parameters.entity == |
1250 | 0 | GNUTLS_CLIENT ? session->key.proto. |
1251 | 0 | tls13.ap_ckey : session->key.proto.tls13.ap_skey; |
1252 | 0 | break; |
1253 | 0 | default: |
1254 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1255 | 0 | } |
1256 | | |
1257 | 0 | return session->internals.h_secret_func(session, level, |
1258 | 0 | secret_read, secret_write, |
1259 | 0 | prf->output_size); |
1260 | 0 | } |
1261 | | |
1262 | | int _tls13_connection_state_init(gnutls_session_t session, hs_stage_t stage) |
1263 | 0 | { |
1264 | 0 | const uint16_t epoch_next = session->security_parameters.epoch_next; |
1265 | 0 | int ret; |
1266 | |
|
1267 | 0 | ret = _gnutls_epoch_set_keys(session, epoch_next, stage); |
1268 | 0 | if (ret < 0) |
1269 | 0 | return ret; |
1270 | | |
1271 | 0 | _gnutls_handshake_log("HSK[%p]: TLS 1.3 re-key with cipher suite: %s\n", |
1272 | 0 | session, session->security_parameters.cs->name); |
1273 | |
|
1274 | 0 | session->security_parameters.epoch_read = epoch_next; |
1275 | 0 | session->security_parameters.epoch_write = epoch_next; |
1276 | |
|
1277 | 0 | ret = _gnutls_call_secret_func(session, stage, 1, 1); |
1278 | 0 | if (ret < 0) |
1279 | 0 | return gnutls_assert_val(ret); |
1280 | | |
1281 | 0 | return 0; |
1282 | 0 | } |
1283 | | |
1284 | | int _tls13_read_connection_state_init(gnutls_session_t session, |
1285 | | hs_stage_t stage) |
1286 | 0 | { |
1287 | 0 | const uint16_t epoch_next = session->security_parameters.epoch_next; |
1288 | 0 | int ret; |
1289 | |
|
1290 | 0 | if (unlikely(stage == STAGE_EARLY && !IS_SERVER(session))) { |
1291 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1292 | 0 | } |
1293 | | |
1294 | 0 | ret = _gnutls_epoch_set_keys(session, epoch_next, stage); |
1295 | 0 | if (ret < 0) |
1296 | 0 | return ret; |
1297 | | |
1298 | 0 | _gnutls_handshake_log |
1299 | 0 | ("HSK[%p]: TLS 1.3 set read key with cipher suite: %s\n", session, |
1300 | 0 | stage == |
1301 | 0 | STAGE_EARLY ? session->internals.resumed_security_parameters. |
1302 | 0 | cs->name : session->security_parameters.cs->name); |
1303 | |
|
1304 | 0 | session->security_parameters.epoch_read = epoch_next; |
1305 | |
|
1306 | 0 | ret = _gnutls_call_secret_func(session, stage, 1, 0); |
1307 | 0 | if (ret < 0) |
1308 | 0 | return gnutls_assert_val(ret); |
1309 | | |
1310 | 0 | return 0; |
1311 | 0 | } |
1312 | | |
1313 | | int _tls13_write_connection_state_init(gnutls_session_t session, |
1314 | | hs_stage_t stage) |
1315 | 0 | { |
1316 | 0 | const uint16_t epoch_next = session->security_parameters.epoch_next; |
1317 | 0 | int ret; |
1318 | |
|
1319 | 0 | if (unlikely(stage == STAGE_EARLY && IS_SERVER(session))) { |
1320 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
1321 | 0 | } |
1322 | | |
1323 | 0 | ret = _gnutls_epoch_set_keys(session, epoch_next, stage); |
1324 | 0 | if (ret < 0) |
1325 | 0 | return ret; |
1326 | | |
1327 | 0 | _gnutls_handshake_log |
1328 | 0 | ("HSK[%p]: TLS 1.3 set write key with cipher suite: %s\n", session, |
1329 | 0 | stage == |
1330 | 0 | STAGE_EARLY ? session->internals.resumed_security_parameters. |
1331 | 0 | cs->name : session->security_parameters.cs->name); |
1332 | |
|
1333 | 0 | session->security_parameters.epoch_write = epoch_next; |
1334 | |
|
1335 | 0 | ret = _gnutls_call_secret_func(session, stage, 0, 1); |
1336 | 0 | if (ret < 0) |
1337 | 0 | return gnutls_assert_val(ret); |
1338 | | |
1339 | 0 | return 0; |
1340 | 0 | } |
1341 | | |
1342 | | static int |
1343 | | _tls13_init_record_state(gnutls_cipher_algorithm_t algo, |
1344 | | record_state_st * state) |
1345 | 0 | { |
1346 | 0 | int ret; |
1347 | 0 | gnutls_datum_t key; |
1348 | |
|
1349 | 0 | key.data = state->key; |
1350 | 0 | key.size = state->key_size; |
1351 | |
|
1352 | 0 | ret = _gnutls_aead_cipher_init(&state->ctx.aead, algo, &key); |
1353 | 0 | if (ret < 0) { |
1354 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); |
1355 | 0 | return gnutls_assert_val(ret); |
1356 | 0 | } |
1357 | | |
1358 | 0 | if (is_cipher_algo_allowed(algo)) |
1359 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); |
1360 | 0 | else |
1361 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); |
1362 | |
|
1363 | 0 | state->aead_tag_size = gnutls_cipher_get_tag_size(algo); |
1364 | 0 | state->is_aead = 1; |
1365 | |
|
1366 | 0 | return 0; |
1367 | 0 | } |
1368 | | |
1369 | | /** |
1370 | | * gnutls_handshake_set_secret_function: |
1371 | | * @session: is a #gnutls_session_t type. |
1372 | | * @func: the secret func |
1373 | | * |
1374 | | * This function will set a callback to be called when a new traffic |
1375 | | * secret is installed. |
1376 | | * |
1377 | | * Since: 3.7.0 |
1378 | | */ |
1379 | | void |
1380 | | gnutls_handshake_set_secret_function(gnutls_session_t session, |
1381 | | gnutls_handshake_secret_func func) |
1382 | 0 | { |
1383 | 0 | session->internals.h_secret_func = func; |
1384 | 0 | } |