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