]>
Commit | Line | Data |
---|---|---|
4c0c2283 | 1 | /* |
c78b2bee | 2 | * Copyright (C) 2020 Tobias Brunner |
dc9f6c68 | 3 | * Copyright (C) 2020-2021 Pascal Knecht |
c78b2bee TB |
4 | * Copyright (C) 2020 Méline Sieber |
5 | * HSR Hochschule fuer Technik Rapperswil | |
6 | * | |
4c0c2283 MW |
7 | * Copyright (C) 2010 Martin Willi |
8 | * Copyright (C) 2010 revosec AG | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify it | |
11 | * under the terms of the GNU General Public License as published by the | |
12 | * Free Software Foundation; either version 2 of the License, or (at your | |
13 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, but | |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | * for more details. | |
19 | */ | |
20 | ||
21 | #include "tls_peer.h" | |
22 | ||
f05b4272 | 23 | #include <utils/debug.h> |
c8114799 | 24 | #include <credentials/certificates/x509.h> |
4c0c2283 MW |
25 | |
26 | #include <time.h> | |
27 | ||
28 | typedef struct private_tls_peer_t private_tls_peer_t; | |
29 | ||
698674c7 MW |
30 | typedef enum { |
31 | STATE_INIT, | |
32 | STATE_HELLO_SENT, | |
8fef06a6 | 33 | STATE_HELLO_RECEIVED, |
3e962b08 | 34 | STATE_HELLO_DONE, |
3ddd164e | 35 | STATE_CERT_SENT, |
8fef06a6 | 36 | STATE_CERT_RECEIVED, |
da3f4a9f | 37 | STATE_KEY_EXCHANGE_RECEIVED, |
8fef06a6 | 38 | STATE_CERTREQ_RECEIVED, |
3ddd164e MW |
39 | STATE_KEY_EXCHANGE_SENT, |
40 | STATE_VERIFY_SENT, | |
f139b578 | 41 | STATE_CIPHERSPEC_CHANGED_OUT, |
3ddd164e | 42 | STATE_FINISHED_SENT, |
f139b578 | 43 | STATE_CIPHERSPEC_CHANGED_IN, |
6a5c86b7 | 44 | STATE_FINISHED_RECEIVED, |
7a2b0266 | 45 | /* new states in TLS 1.3 */ |
46 | STATE_HELLORETRYREQ_RECEIVED, | |
47 | STATE_ENCRYPTED_EXTENSIONS_RECEIVED, | |
48 | STATE_CERT_VERIFY_RECEIVED, | |
49 | STATE_FINISHED_SENT_KEY_SWITCHED, | |
e02f19e3 TB |
50 | STATE_KEY_UPDATE_REQUESTED, |
51 | STATE_KEY_UPDATE_SENT, | |
9ef46cfa | 52 | STATE_CERT_VERIFY_SENT, |
698674c7 MW |
53 | } peer_state_t; |
54 | ||
4c0c2283 MW |
55 | /** |
56 | * Private data of an tls_peer_t object. | |
57 | */ | |
58 | struct private_tls_peer_t { | |
59 | ||
60 | /** | |
61 | * Public tls_peer_t interface. | |
62 | */ | |
63 | tls_peer_t public; | |
536dbc00 | 64 | |
3e962b08 MW |
65 | /** |
66 | * TLS stack | |
67 | */ | |
68 | tls_t *tls; | |
69 | ||
536dbc00 MW |
70 | /** |
71 | * TLS crypto context | |
72 | */ | |
73 | tls_crypto_t *crypto; | |
698674c7 | 74 | |
e6f3ef13 MW |
75 | /** |
76 | * TLS alert handler | |
77 | */ | |
78 | tls_alert_t *alert; | |
79 | ||
3ddd164e | 80 | /** |
69e8bb2e | 81 | * Peer identity, NULL for no client authentication |
3ddd164e MW |
82 | */ |
83 | identification_t *peer; | |
84 | ||
85 | /** | |
86 | * Server identity | |
87 | */ | |
88 | identification_t *server; | |
89 | ||
698674c7 MW |
90 | /** |
91 | * State we are in | |
92 | */ | |
93 | peer_state_t state; | |
3ddd164e | 94 | |
b37080f8 MW |
95 | /** |
96 | * TLS version we offered in hello | |
97 | */ | |
98 | tls_version_t hello_version; | |
99 | ||
18010de2 MW |
100 | /** |
101 | * Hello random data selected by client | |
102 | */ | |
103 | char client_random[32]; | |
104 | ||
105 | /** | |
106 | * Hello random data selected by server | |
107 | */ | |
108 | char server_random[32]; | |
109 | ||
3ddd164e MW |
110 | /** |
111 | * Auth helper for peer authentication | |
112 | */ | |
113 | auth_cfg_t *peer_auth; | |
114 | ||
115 | /** | |
116 | * Auth helper for server authentication | |
117 | */ | |
118 | auth_cfg_t *server_auth; | |
119 | ||
120 | /** | |
121 | * Peer private key | |
122 | */ | |
123 | private_key_t *private; | |
dbb7c030 | 124 | |
da3f4a9f MW |
125 | /** |
126 | * DHE exchange | |
127 | */ | |
128 | diffie_hellman_t *dh; | |
129 | ||
2b6565c2 TB |
130 | /** |
131 | * Requested DH group | |
132 | */ | |
133 | tls_named_group_t requested_curve; | |
134 | ||
3abcbf82 TB |
135 | /** |
136 | * Original cipher suite in HelloRetryRequest | |
137 | */ | |
138 | tls_cipher_suite_t original_suite; | |
139 | ||
2b6565c2 TB |
140 | /** |
141 | * Cookie extension received in HelloRetryRequest | |
142 | */ | |
143 | chunk_t cookie; | |
144 | ||
6a5c86b7 MW |
145 | /** |
146 | * Resuming a session? | |
147 | */ | |
148 | bool resume; | |
149 | ||
150 | /** | |
151 | * TLS session identifier | |
152 | */ | |
153 | chunk_t session; | |
154 | ||
dbb7c030 MW |
155 | /** |
156 | * List of server-supported hashsig algorithms | |
157 | */ | |
158 | chunk_t hashsig; | |
159 | ||
160 | /** | |
161 | * List of server-supported client certificate types | |
162 | */ | |
163 | chunk_t cert_types; | |
4c0c2283 MW |
164 | }; |
165 | ||
5c4cb40e | 166 | /* Implemented in tls_server.c */ |
066ac880 | 167 | bool tls_write_key_share(bio_writer_t **key_share, diffie_hellman_t *dh); |
e4b4aabc | 168 | public_key_t *tls_find_public_key(auth_cfg_t *peer_auth, identification_t *id); |
5c4cb40e | 169 | |
2b6565c2 TB |
170 | /** |
171 | * Verify the DH group/key type requested by the server is valid. | |
172 | */ | |
173 | static bool verify_requested_key_type(private_tls_peer_t *this, | |
174 | uint16_t key_type) | |
175 | { | |
176 | enumerator_t *enumerator; | |
177 | diffie_hellman_group_t group, found = MODP_NONE; | |
178 | tls_named_group_t curve; | |
179 | ||
180 | enumerator = this->crypto->create_ec_enumerator(this->crypto); | |
181 | while (enumerator->enumerate(enumerator, &group, &curve)) | |
182 | { | |
183 | if (key_type == curve) | |
184 | { | |
185 | found = group; | |
186 | break; | |
187 | } | |
188 | } | |
189 | enumerator->destroy(enumerator); | |
190 | ||
191 | if (found == MODP_NONE) | |
192 | { | |
193 | DBG1(DBG_TLS, "server requested key exchange we didn't propose"); | |
194 | return FALSE; | |
195 | } | |
196 | if (this->dh->get_dh_group(this->dh) == found) | |
197 | { | |
198 | DBG1(DBG_TLS, "server requested key exchange we already use"); | |
199 | return FALSE; | |
200 | } | |
201 | return TRUE; | |
202 | } | |
203 | ||
3e962b08 MW |
204 | /** |
205 | * Process a server hello message | |
206 | */ | |
4ef946dd | 207 | static status_t process_server_hello(private_tls_peer_t *this, |
7e432eff | 208 | bio_reader_t *reader) |
3e962b08 | 209 | { |
b12c53ce | 210 | uint8_t compression; |
2b6565c2 | 211 | uint16_t version, cipher, key_type = 0; |
c78b2bee | 212 | bio_reader_t *extensions, *extension; |
2b6565c2 TB |
213 | chunk_t msg, random, session, ext = chunk_empty, key_share = chunk_empty; |
214 | chunk_t cookie = chunk_empty; | |
6a5c86b7 | 215 | tls_cipher_suite_t suite = 0; |
dc9f6c68 | 216 | tls_version_t version_max; |
2b6565c2 | 217 | bool is_retry_request; |
4ef946dd | 218 | |
2b6565c2 | 219 | msg = reader->peek(reader); |
4ef946dd | 220 | if (!reader->read_uint16(reader, &version) || |
18010de2 | 221 | !reader->read_data(reader, sizeof(this->server_random), &random) || |
4ef946dd MW |
222 | !reader->read_data8(reader, &session) || |
223 | !reader->read_uint16(reader, &cipher) || | |
224 | !reader->read_uint8(reader, &compression) || | |
225 | (reader->remaining(reader) && !reader->read_data16(reader, &ext))) | |
3e962b08 | 226 | { |
3c19b346 | 227 | DBG1(DBG_TLS, "received invalid ServerHello"); |
e6f3ef13 MW |
228 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); |
229 | return NEED_MORE; | |
4ef946dd | 230 | } |
18010de2 | 231 | |
2b6565c2 TB |
232 | is_retry_request = chunk_equals_const(random, tls_hello_retry_request_magic); |
233 | ||
18010de2 MW |
234 | memcpy(this->server_random, random.ptr, sizeof(this->server_random)); |
235 | ||
c78b2bee TB |
236 | extensions = bio_reader_create(ext); |
237 | while (extensions->remaining(extensions)) | |
7a2b0266 | 238 | { |
c78b2bee TB |
239 | uint16_t extension_type; |
240 | chunk_t extension_data; | |
7a2b0266 | 241 | |
c78b2bee TB |
242 | if (!extensions->read_uint16(extensions, &extension_type) || |
243 | !extensions->read_data16(extensions, &extension_data)) | |
7a2b0266 | 244 | { |
c78b2bee TB |
245 | DBG1(DBG_TLS, "invalid extension in ServerHello"); |
246 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
247 | extensions->destroy(extensions); | |
248 | return NEED_MORE; | |
7a2b0266 | 249 | } |
c78b2bee | 250 | extension = bio_reader_create(extension_data); |
7a2b0266 | 251 | switch (extension_type) |
252 | { | |
253 | case TLS_EXT_SUPPORTED_VERSIONS: | |
c78b2bee TB |
254 | if (!extension->read_uint16(extension, &version)) |
255 | { | |
256 | DBG1(DBG_TLS, "invalid %N extension", tls_extension_names, | |
257 | extension_type); | |
258 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
259 | extensions->destroy(extensions); | |
260 | extension->destroy(extension); | |
261 | return NEED_MORE; | |
262 | } | |
7a2b0266 | 263 | break; |
7a2b0266 | 264 | case TLS_EXT_KEY_SHARE: |
c78b2bee | 265 | if (!extension->read_uint16(extension, &key_type) || |
2b6565c2 | 266 | (!is_retry_request && |
d532d6c7 TB |
267 | !(extension->read_data16(extension, &key_share) && |
268 | key_share.len))) | |
7a2b0266 | 269 | { |
c78b2bee TB |
270 | DBG1(DBG_TLS, "invalid %N extension", tls_extension_names, |
271 | extension_type); | |
272 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
273 | extensions->destroy(extensions); | |
274 | extension->destroy(extension); | |
275 | return NEED_MORE; | |
7a2b0266 | 276 | } |
277 | break; | |
2b6565c2 TB |
278 | case TLS_EXT_COOKIE: |
279 | if (!extension->read_data16(extension, &cookie)) | |
280 | { | |
281 | DBG1(DBG_TLS, "invalid %N extension", tls_extension_names, | |
282 | extension_type); | |
283 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
284 | extensions->destroy(extensions); | |
285 | extension->destroy(extension); | |
286 | return NEED_MORE; | |
287 | } | |
7a2b0266 | 288 | default: |
c78b2bee | 289 | break; |
7a2b0266 | 290 | } |
c78b2bee | 291 | extension->destroy(extension); |
7a2b0266 | 292 | } |
c78b2bee | 293 | extensions->destroy(extensions); |
7a2b0266 | 294 | |
dc9f6c68 PK |
295 | /* downgrade protection (see RFC 8446, section 4.1.3) */ |
296 | version_max = this->tls->get_version_max(this->tls); | |
297 | if ((version_max == TLS_1_3 && version < TLS_1_3) || | |
298 | (version_max == TLS_1_2 && version < TLS_1_2)) | |
299 | { | |
300 | chunk_t server_random_end = chunk_create(&this->server_random[24], 8); | |
301 | ||
302 | if (chunk_equals(server_random_end, tls_downgrade_protection_tls11) || | |
303 | chunk_equals(server_random_end, tls_downgrade_protection_tls12)) | |
304 | { | |
305 | DBG1(DBG_TLS, "server random indicates downgrade attack to %N", | |
306 | tls_version_names, version); | |
307 | this->alert->add(this->alert, TLS_FATAL, TLS_ILLEGAL_PARAMETER); | |
308 | return NEED_MORE; | |
309 | } | |
310 | } | |
311 | ||
c4576a1f | 312 | if (!this->tls->set_version(this->tls, version, version)) |
4ef946dd | 313 | { |
f154e304 MW |
314 | DBG1(DBG_TLS, "negotiated version %N not supported", |
315 | tls_version_names, version); | |
e6f3ef13 MW |
316 | this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION); |
317 | return NEED_MORE; | |
3e962b08 | 318 | } |
6a5c86b7 | 319 | |
7a2b0266 | 320 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
18010de2 | 321 | { |
7a2b0266 | 322 | if (chunk_equals(this->session, session)) |
6a5c86b7 | 323 | { |
7a2b0266 | 324 | suite = this->crypto->resume_session(this->crypto, session, |
325 | this->server, chunk_from_thing | |
326 | (this->client_random), | |
327 | chunk_from_thing | |
328 | (this->server_random)); | |
329 | if (suite) | |
330 | { | |
331 | DBG1(DBG_TLS, "resumed %N using suite %N", | |
332 | tls_version_names, version, tls_cipher_suite_names, suite); | |
333 | this->resume = TRUE; | |
334 | } | |
6a5c86b7 | 335 | } |
7a2b0266 | 336 | DESTROY_IF(this->dh); |
337 | this->dh = NULL; | |
6a5c86b7 | 338 | } |
c78b2bee | 339 | |
6a5c86b7 MW |
340 | if (!suite) |
341 | { | |
342 | suite = cipher; | |
343 | if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY)) | |
344 | { | |
2ad1df95 | 345 | DBG1(DBG_TLS, "received TLS cipher suite %N unacceptable", |
6a5c86b7 MW |
346 | tls_cipher_suite_names, suite); |
347 | this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); | |
348 | return NEED_MORE; | |
349 | } | |
3abcbf82 TB |
350 | if (this->original_suite && this->original_suite != suite) |
351 | { | |
352 | DBG1(DBG_TLS, "server selected %N instead of %N after retry", | |
353 | tls_cipher_suite_names, suite, tls_cipher_suite_names, | |
354 | this->original_suite); | |
355 | this->alert->add(this->alert, TLS_FATAL, TLS_ILLEGAL_PARAMETER); | |
356 | return NEED_MORE; | |
357 | } | |
6a5c86b7 MW |
358 | DBG1(DBG_TLS, "negotiated %N using suite %N", |
359 | tls_version_names, version, tls_cipher_suite_names, suite); | |
360 | free(this->session.ptr); | |
361 | this->session = chunk_clone(session); | |
18010de2 | 362 | } |
7a2b0266 | 363 | |
2b6565c2 TB |
364 | if (is_retry_request) |
365 | { | |
366 | if (!this->crypto->hash_handshake(this->crypto, NULL)) | |
367 | { | |
368 | DBG1(DBG_TLS, "failed to hash handshake messages"); | |
369 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
370 | return NEED_MORE; | |
371 | } | |
372 | } | |
373 | this->crypto->append_handshake(this->crypto, TLS_SERVER_HELLO, msg); | |
374 | ||
375 | if (is_retry_request) | |
376 | { | |
377 | if (key_type) | |
378 | { | |
379 | DBG1(DBG_TLS, "server requests key exchange with %N", | |
380 | tls_named_group_names, key_type); | |
381 | } | |
382 | else if (cookie.len) | |
383 | { | |
384 | DBG1(DBG_TLS, "server requests retry with cookie"); | |
385 | } | |
386 | else | |
387 | { | |
388 | DBG1(DBG_TLS, "invalid retry request received"); | |
389 | this->alert->add(this->alert, TLS_FATAL, TLS_ILLEGAL_PARAMETER); | |
390 | return NEED_MORE; | |
391 | } | |
392 | if (this->requested_curve || this->cookie.len) | |
393 | { | |
394 | DBG1(DBG_TLS, "already replied to previous retry request"); | |
395 | this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE); | |
396 | return NEED_MORE; | |
397 | } | |
398 | if (key_type && !verify_requested_key_type(this, key_type)) | |
399 | { | |
400 | this->alert->add(this->alert, TLS_FATAL, TLS_ILLEGAL_PARAMETER); | |
401 | return NEED_MORE; | |
402 | } | |
403 | ||
404 | DESTROY_IF(this->dh); | |
405 | this->dh = NULL; | |
3abcbf82 | 406 | this->original_suite = suite; |
2b6565c2 TB |
407 | this->requested_curve = key_type; |
408 | this->cookie = chunk_clone(cookie); | |
409 | this->state = STATE_INIT; | |
410 | return NEED_MORE; | |
411 | } | |
412 | ||
d532d6c7 | 413 | if (this->tls->get_version_max(this->tls) >= TLS_1_3) |
7a2b0266 | 414 | { |
2921f437 | 415 | chunk_t shared_secret = chunk_empty; |
7a2b0266 | 416 | |
d532d6c7 TB |
417 | if (key_share.len && |
418 | key_type != TLS_CURVE25519 && | |
419 | key_type != TLS_CURVE448) | |
420 | { /* classic format (see RFC 8446, section 4.2.8.2) */ | |
421 | if (key_share.ptr[0] != TLS_ANSI_UNCOMPRESSED) | |
422 | { | |
423 | DBG1(DBG_TLS, "DH point format '%N' not supported", | |
424 | tls_ansi_point_format_names, key_share.ptr[0]); | |
425 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
426 | return NEED_MORE; | |
427 | } | |
428 | key_share = chunk_skip(key_share, 1); | |
429 | } | |
430 | if (!key_share.len || | |
431 | !this->dh->set_other_public_value(this->dh, key_share) || | |
2921f437 TB |
432 | !this->dh->get_shared_secret(this->dh, &shared_secret) || |
433 | !this->crypto->derive_handshake_keys(this->crypto, shared_secret)) | |
7a2b0266 | 434 | { |
2921f437 TB |
435 | DBG1(DBG_TLS, "DH key derivation failed"); |
436 | this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); | |
437 | chunk_clear(&shared_secret); | |
438 | return NEED_MORE; | |
7a2b0266 | 439 | } |
2921f437 | 440 | chunk_clear(&shared_secret); |
7a2b0266 | 441 | |
2921f437 TB |
442 | this->crypto->change_cipher(this->crypto, TRUE); |
443 | this->crypto->change_cipher(this->crypto, FALSE); | |
7a2b0266 | 444 | } |
445 | ||
8fef06a6 | 446 | this->state = STATE_HELLO_RECEIVED; |
4ef946dd | 447 | return NEED_MORE; |
3e962b08 MW |
448 | } |
449 | ||
7a2b0266 | 450 | /** |
c78b2bee TB |
451 | * Process a server encrypted extensions message |
452 | */ | |
7a2b0266 | 453 | static status_t process_encrypted_extensions(private_tls_peer_t *this, |
454 | bio_reader_t *reader) | |
455 | { | |
7a2b0266 | 456 | chunk_t ext = chunk_empty; |
c78b2bee | 457 | uint16_t extension_type; |
7a2b0266 | 458 | |
c78b2bee TB |
459 | this->crypto->append_handshake(this->crypto, TLS_ENCRYPTED_EXTENSIONS, |
460 | reader->peek(reader)); | |
7a2b0266 | 461 | |
f0ed5f91 | 462 | if (!reader->read_data16(reader, &ext)) |
7a2b0266 | 463 | { |
464 | DBG1(DBG_TLS, "received invalid EncryptedExtensions"); | |
465 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
466 | return NEED_MORE; | |
467 | } | |
c78b2bee | 468 | if (ext.len) |
7a2b0266 | 469 | { |
c78b2bee | 470 | bio_reader_t *extensions = bio_reader_create(ext); |
7a2b0266 | 471 | |
c78b2bee | 472 | while (extensions->remaining(extensions)) |
7a2b0266 | 473 | { |
c78b2bee TB |
474 | chunk_t extension_data = chunk_empty; |
475 | ||
476 | if (!extensions->read_uint16(extensions, &extension_type) || | |
477 | !extensions->read_data16(extensions, &extension_data)) | |
7a2b0266 | 478 | { |
c78b2bee TB |
479 | DBG1(DBG_TLS, "invalid extension in EncryptedExtensions"); |
480 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
481 | extensions->destroy(extensions); | |
482 | return NEED_MORE; | |
7a2b0266 | 483 | } |
484 | switch (extension_type) | |
485 | { | |
7a2b0266 | 486 | case TLS_EXT_SERVER_NAME: |
487 | case TLS_EXT_MAX_FRAGMENT_LENGTH: | |
488 | case TLS_EXT_SUPPORTED_GROUPS: | |
489 | case TLS_EXT_USE_SRTP: | |
490 | case TLS_EXT_HEARTBEAT: | |
491 | case TLS_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION: | |
492 | case TLS_SERVER_CERTIFICATE_TYPE: | |
c78b2bee TB |
493 | /* not supported so far */ |
494 | DBG2(DBG_TLS, "ignoring unsupported %N EncryptedExtension", | |
495 | tls_extension_names, extension_type); | |
7a2b0266 | 496 | break; |
497 | default: | |
c78b2bee TB |
498 | DBG1(DBG_TLS, "received forbidden EncryptedExtension (%d)", |
499 | extension_type); | |
7a2b0266 | 500 | this->alert->add(this->alert, TLS_FATAL, |
501 | TLS_ILLEGAL_PARAMETER); | |
c78b2bee | 502 | extensions->destroy(extensions); |
7a2b0266 | 503 | return NEED_MORE; |
504 | } | |
505 | } | |
c78b2bee | 506 | extensions->destroy(extensions); |
7a2b0266 | 507 | } |
c78b2bee | 508 | this->state = STATE_ENCRYPTED_EXTENSIONS_RECEIVED; |
7a2b0266 | 509 | return NEED_MORE; |
510 | } | |
511 | ||
c8114799 MW |
512 | /** |
513 | * Check if a server certificate is acceptable for the given server identity | |
514 | */ | |
515 | static bool check_certificate(private_tls_peer_t *this, certificate_t *cert) | |
516 | { | |
517 | identification_t *id; | |
518 | ||
519 | if (cert->has_subject(cert, this->server)) | |
520 | { | |
521 | return TRUE; | |
522 | } | |
523 | id = cert->get_subject(cert); | |
524 | if (id->matches(id, this->server)) | |
525 | { | |
526 | return TRUE; | |
527 | } | |
528 | if (cert->get_type(cert) == CERT_X509) | |
529 | { | |
530 | x509_t *x509 = (x509_t*)cert; | |
531 | enumerator_t *enumerator; | |
532 | ||
533 | enumerator = x509->create_subjectAltName_enumerator(x509); | |
534 | while (enumerator->enumerate(enumerator, &id)) | |
535 | { | |
536 | if (id->matches(id, this->server)) | |
537 | { | |
538 | enumerator->destroy(enumerator); | |
539 | return TRUE; | |
540 | } | |
541 | } | |
542 | enumerator->destroy(enumerator); | |
543 | } | |
544 | DBG1(DBG_TLS, "server certificate does not match to '%Y'", this->server); | |
545 | return FALSE; | |
546 | } | |
547 | ||
3e962b08 MW |
548 | /** |
549 | * Process a Certificate message | |
550 | */ | |
4ef946dd | 551 | static status_t process_certificate(private_tls_peer_t *this, |
7e432eff | 552 | bio_reader_t *reader) |
3e962b08 | 553 | { |
4ef946dd | 554 | certificate_t *cert; |
7e432eff | 555 | bio_reader_t *certs; |
4ef946dd | 556 | chunk_t data; |
3ddd164e MW |
557 | bool first = TRUE; |
558 | ||
84d67ead MW |
559 | this->crypto->append_handshake(this->crypto, |
560 | TLS_CERTIFICATE, reader->peek(reader)); | |
3e962b08 | 561 | |
7a2b0266 | 562 | if (this->tls->get_version_max(this->tls) > TLS_1_2) |
563 | { | |
564 | if (!reader->read_data8(reader, &data)) | |
565 | { | |
566 | DBG1(DBG_TLS, "certificate request context invalid"); | |
567 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
568 | return NEED_MORE; | |
569 | } | |
7a2b0266 | 570 | } |
6549adb6 | 571 | |
4ef946dd MW |
572 | if (!reader->read_data24(reader, &data)) |
573 | { | |
e6f3ef13 MW |
574 | DBG1(DBG_TLS, "certificate message header invalid"); |
575 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
576 | return NEED_MORE; | |
4ef946dd | 577 | } |
7e432eff | 578 | certs = bio_reader_create(data); |
4ef946dd MW |
579 | while (certs->remaining(certs)) |
580 | { | |
581 | if (!certs->read_data24(certs, &data)) | |
3e962b08 | 582 | { |
e6f3ef13 MW |
583 | DBG1(DBG_TLS, "certificate message invalid"); |
584 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
4ef946dd | 585 | certs->destroy(certs); |
e6f3ef13 | 586 | return NEED_MORE; |
3e962b08 | 587 | } |
4ef946dd | 588 | cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, |
3ddd164e | 589 | BUILD_BLOB_ASN1_DER, data, BUILD_END); |
4ef946dd | 590 | if (cert) |
3e962b08 | 591 | { |
3ddd164e MW |
592 | if (first) |
593 | { | |
c8114799 MW |
594 | if (!check_certificate(this, cert)) |
595 | { | |
596 | cert->destroy(cert); | |
597 | certs->destroy(certs); | |
598 | this->alert->add(this->alert, TLS_FATAL, TLS_ACCESS_DENIED); | |
599 | return NEED_MORE; | |
600 | } | |
3ddd164e | 601 | this->server_auth->add(this->server_auth, |
400df4ca | 602 | AUTH_HELPER_SUBJECT_CERT, cert); |
3c19b346 | 603 | DBG1(DBG_TLS, "received TLS server certificate '%Y'", |
3ddd164e MW |
604 | cert->get_subject(cert)); |
605 | first = FALSE; | |
606 | } | |
607 | else | |
608 | { | |
3c19b346 | 609 | DBG1(DBG_TLS, "received TLS intermediate certificate '%Y'", |
3ddd164e MW |
610 | cert->get_subject(cert)); |
611 | this->server_auth->add(this->server_auth, | |
400df4ca | 612 | AUTH_HELPER_IM_CERT, cert); |
3ddd164e MW |
613 | } |
614 | } | |
615 | else | |
616 | { | |
3c19b346 | 617 | DBG1(DBG_TLS, "parsing TLS certificate failed, skipped"); |
e6f3ef13 | 618 | this->alert->add(this->alert, TLS_WARNING, TLS_BAD_CERTIFICATE); |
3e962b08 | 619 | } |
7a2b0266 | 620 | if (this->tls->get_version_max(this->tls) > TLS_1_2) |
621 | { | |
622 | if (!certs->read_data16(certs, &data)) | |
623 | { | |
4c40a3d3 | 624 | DBG1(DBG_TLS, "failed to read extensions of CertificateEntry"); |
7a2b0266 | 625 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); |
626 | return NEED_MORE; | |
627 | } | |
7a2b0266 | 628 | } |
3e962b08 | 629 | } |
4ef946dd | 630 | certs->destroy(certs); |
8fef06a6 | 631 | this->state = STATE_CERT_RECEIVED; |
3e962b08 MW |
632 | return NEED_MORE; |
633 | } | |
634 | ||
bfa31788 TB |
635 | /** |
636 | * Process CertificateVerify message | |
637 | */ | |
638 | static status_t process_cert_verify(private_tls_peer_t *this, | |
639 | bio_reader_t *reader) | |
640 | { | |
641 | public_key_t *public; | |
642 | chunk_t msg; | |
643 | ||
e4b4aabc | 644 | public = tls_find_public_key(this->server_auth, this->server); |
bfa31788 TB |
645 | if (!public) |
646 | { | |
4635f348 PK |
647 | DBG1(DBG_TLS, "no trusted certificate found for '%Y' to verify TLS server", |
648 | this->server); | |
bfa31788 TB |
649 | this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); |
650 | return NEED_MORE; | |
651 | } | |
652 | ||
653 | msg = reader->peek(reader); | |
654 | if (!this->crypto->verify_handshake(this->crypto, public, reader)) | |
655 | { | |
656 | public->destroy(public); | |
657 | DBG1(DBG_TLS, "signature verification failed"); | |
658 | this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE); | |
659 | return NEED_MORE; | |
660 | } | |
661 | public->destroy(public); | |
662 | ||
663 | this->crypto->append_handshake(this->crypto, TLS_CERTIFICATE_VERIFY, msg); | |
664 | this->state = STATE_CERT_VERIFY_RECEIVED; | |
665 | return NEED_MORE; | |
666 | } | |
667 | ||
da3f4a9f MW |
668 | /** |
669 | * Process a Key Exchange message using MODP Diffie Hellman | |
670 | */ | |
671 | static status_t process_modp_key_exchange(private_tls_peer_t *this, | |
7e432eff | 672 | bio_reader_t *reader) |
da3f4a9f MW |
673 | { |
674 | chunk_t prime, generator, pub, chunk; | |
675 | public_key_t *public; | |
676 | ||
677 | chunk = reader->peek(reader); | |
678 | if (!reader->read_data16(reader, &prime) || | |
679 | !reader->read_data16(reader, &generator) || | |
680 | !reader->read_data16(reader, &pub)) | |
681 | { | |
682 | DBG1(DBG_TLS, "received invalid Server Key Exchange"); | |
683 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
684 | return NEED_MORE; | |
685 | } | |
47e96391 MW |
686 | /* reject (export) DH groups using primes smaller than 1024 bit */ |
687 | if (prime.len < 1024 / 8) | |
688 | { | |
689 | DBG1(DBG_TLS, "short DH prime received (%zu bytes)", prime.len); | |
690 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
691 | return NEED_MORE; | |
692 | } | |
e4b4aabc | 693 | public = tls_find_public_key(this->server_auth, this->server); |
da3f4a9f MW |
694 | if (!public) |
695 | { | |
696 | DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server); | |
697 | this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); | |
698 | return NEED_MORE; | |
699 | } | |
700 | ||
701 | chunk.len = 2 + prime.len + 2 + generator.len + 2 + pub.len; | |
702 | chunk = chunk_cat("ccc", chunk_from_thing(this->client_random), | |
703 | chunk_from_thing(this->server_random), chunk); | |
704 | if (!this->crypto->verify(this->crypto, public, reader, chunk)) | |
705 | { | |
706 | public->destroy(public); | |
707 | free(chunk.ptr); | |
708 | DBG1(DBG_TLS, "verifying DH parameters failed"); | |
709 | this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE); | |
710 | return NEED_MORE; | |
711 | } | |
712 | public->destroy(public); | |
713 | free(chunk.ptr); | |
714 | ||
715 | this->dh = lib->crypto->create_dh(lib->crypto, MODP_CUSTOM, | |
716 | generator, prime); | |
717 | if (!this->dh) | |
718 | { | |
719 | DBG1(DBG_TLS, "custom DH parameters not supported"); | |
720 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
721 | return NEED_MORE; | |
722 | } | |
a777155f MW |
723 | if (!this->dh->set_other_public_value(this->dh, pub)) |
724 | { | |
725 | DBG1(DBG_TLS, "applying DH public value failed"); | |
726 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
727 | return NEED_MORE; | |
728 | } | |
da3f4a9f MW |
729 | |
730 | this->state = STATE_KEY_EXCHANGE_RECEIVED; | |
731 | return NEED_MORE; | |
732 | } | |
733 | ||
3f7bb88b MW |
734 | /** |
735 | * Get the EC group for a TLS named curve | |
736 | */ | |
737 | static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this, | |
7a2b0266 | 738 | tls_named_group_t curve) |
3f7bb88b MW |
739 | { |
740 | diffie_hellman_group_t group; | |
7a2b0266 | 741 | tls_named_group_t current; |
3f7bb88b MW |
742 | enumerator_t *enumerator; |
743 | ||
744 | enumerator = this->crypto->create_ec_enumerator(this->crypto); | |
745 | while (enumerator->enumerate(enumerator, &group, ¤t)) | |
746 | { | |
747 | if (current == curve) | |
748 | { | |
749 | enumerator->destroy(enumerator); | |
750 | return group; | |
751 | } | |
752 | } | |
753 | enumerator->destroy(enumerator); | |
754 | return 0; | |
755 | } | |
5fc7297e MW |
756 | |
757 | /** | |
758 | * Process a Key Exchange message using EC Diffie Hellman | |
759 | */ | |
760 | static status_t process_ec_key_exchange(private_tls_peer_t *this, | |
7e432eff | 761 | bio_reader_t *reader) |
5fc7297e MW |
762 | { |
763 | diffie_hellman_group_t group; | |
764 | public_key_t *public; | |
b12c53ce AS |
765 | uint8_t type; |
766 | uint16_t curve; | |
5fc7297e MW |
767 | chunk_t pub, chunk; |
768 | ||
769 | chunk = reader->peek(reader); | |
770 | if (!reader->read_uint8(reader, &type)) | |
771 | { | |
772 | DBG1(DBG_TLS, "received invalid Server Key Exchange"); | |
773 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
774 | return NEED_MORE; | |
775 | } | |
776 | if (type != TLS_ECC_NAMED_CURVE) | |
777 | { | |
778 | DBG1(DBG_TLS, "ECDH curve type %N not supported", | |
779 | tls_ecc_curve_type_names, type); | |
780 | this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); | |
781 | return NEED_MORE; | |
782 | } | |
783 | if (!reader->read_uint16(reader, &curve) || | |
e6cce7ff | 784 | !reader->read_data8(reader, &pub) || pub.len == 0) |
5fc7297e MW |
785 | { |
786 | DBG1(DBG_TLS, "received invalid Server Key Exchange"); | |
787 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
788 | return NEED_MORE; | |
789 | } | |
3f7bb88b MW |
790 | |
791 | group = curve_to_ec_group(this, curve); | |
792 | if (!group) | |
5fc7297e | 793 | { |
3f7bb88b | 794 | DBG1(DBG_TLS, "ECDH curve %N not supported", |
7a2b0266 | 795 | tls_named_group_names, curve); |
3f7bb88b MW |
796 | this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); |
797 | return NEED_MORE; | |
5fc7297e MW |
798 | } |
799 | ||
e4b4aabc | 800 | public = tls_find_public_key(this->server_auth, this->server); |
5fc7297e MW |
801 | if (!public) |
802 | { | |
803 | DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server); | |
804 | this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); | |
805 | return NEED_MORE; | |
806 | } | |
807 | ||
808 | chunk.len = 4 + pub.len; | |
809 | chunk = chunk_cat("ccc", chunk_from_thing(this->client_random), | |
810 | chunk_from_thing(this->server_random), chunk); | |
811 | if (!this->crypto->verify(this->crypto, public, reader, chunk)) | |
812 | { | |
813 | public->destroy(public); | |
814 | free(chunk.ptr); | |
815 | DBG1(DBG_TLS, "verifying DH parameters failed"); | |
816 | this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE); | |
817 | return NEED_MORE; | |
818 | } | |
819 | public->destroy(public); | |
820 | free(chunk.ptr); | |
821 | ||
822 | this->dh = lib->crypto->create_dh(lib->crypto, group); | |
823 | if (!this->dh) | |
824 | { | |
825 | DBG1(DBG_TLS, "DH group %N not supported", | |
826 | diffie_hellman_group_names, group); | |
827 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
828 | return NEED_MORE; | |
829 | } | |
e6cce7ff | 830 | |
8495138d TB |
831 | if (group != CURVE_25519 && |
832 | group != CURVE_448) | |
833 | { /* classic ECPoint format (see RFC 8422, section 5.4.1) */ | |
834 | if (pub.ptr[0] != TLS_ANSI_UNCOMPRESSED) | |
835 | { | |
836 | DBG1(DBG_TLS, "DH point format '%N' not supported", | |
837 | tls_ansi_point_format_names, pub.ptr[0]); | |
838 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
839 | return NEED_MORE; | |
840 | } | |
841 | pub = chunk_skip(pub, 1); | |
e6cce7ff | 842 | } |
8495138d TB |
843 | |
844 | if (!this->dh->set_other_public_value(this->dh, pub)) | |
a777155f MW |
845 | { |
846 | DBG1(DBG_TLS, "applying DH public value failed"); | |
847 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
848 | return NEED_MORE; | |
849 | } | |
5fc7297e MW |
850 | |
851 | this->state = STATE_KEY_EXCHANGE_RECEIVED; | |
852 | return NEED_MORE; | |
853 | } | |
854 | ||
da3f4a9f MW |
855 | /** |
856 | * Process a Server Key Exchange | |
857 | */ | |
858 | static status_t process_key_exchange(private_tls_peer_t *this, | |
7e432eff | 859 | bio_reader_t *reader) |
da3f4a9f MW |
860 | { |
861 | diffie_hellman_group_t group; | |
862 | ||
863 | this->crypto->append_handshake(this->crypto, | |
864 | TLS_SERVER_KEY_EXCHANGE, reader->peek(reader)); | |
865 | ||
866 | group = this->crypto->get_dh_group(this->crypto); | |
f4c98ae6 | 867 | if (group == MODP_NONE) |
da3f4a9f | 868 | { |
f4c98ae6 MW |
869 | DBG1(DBG_TLS, "received Server Key Exchange, but not required " |
870 | "for current suite"); | |
871 | this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); | |
872 | return NEED_MORE; | |
873 | } | |
874 | if (diffie_hellman_group_is_ec(group)) | |
875 | { | |
876 | return process_ec_key_exchange(this, reader); | |
da3f4a9f | 877 | } |
f4c98ae6 | 878 | return process_modp_key_exchange(this, reader); |
da3f4a9f MW |
879 | } |
880 | ||
3e962b08 | 881 | /** |
9ef46cfa | 882 | * Read all available certificate authorities from the given reader |
3e962b08 | 883 | */ |
9ef46cfa PK |
884 | static bool read_certificate_authorities(private_tls_peer_t *this, |
885 | bio_reader_t *reader) | |
3e962b08 | 886 | { |
9ef46cfa | 887 | chunk_t data; |
7e432eff | 888 | bio_reader_t *authorities; |
3e962b08 | 889 | identification_t *id; |
3ddd164e MW |
890 | certificate_t *cert; |
891 | ||
4ef946dd | 892 | if (!reader->read_data16(reader, &data)) |
3e962b08 | 893 | { |
9ef46cfa | 894 | return FALSE; |
3e962b08 | 895 | } |
7e432eff | 896 | authorities = bio_reader_create(data); |
4ef946dd | 897 | while (authorities->remaining(authorities)) |
3e962b08 | 898 | { |
4ef946dd | 899 | if (!authorities->read_data16(authorities, &data)) |
3e962b08 | 900 | { |
4ef946dd | 901 | authorities->destroy(authorities); |
9ef46cfa | 902 | return FALSE; |
3e962b08 | 903 | } |
6a8f1a57 | 904 | if (this->peer) |
3ddd164e | 905 | { |
6a8f1a57 MW |
906 | id = identification_create_from_encoding(ID_DER_ASN1_DN, data); |
907 | cert = lib->credmgr->get_cert(lib->credmgr, | |
908 | CERT_X509, KEY_ANY, id, TRUE); | |
909 | if (cert) | |
910 | { | |
911 | DBG1(DBG_TLS, "received TLS cert request for '%Y", id); | |
912 | this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert); | |
913 | } | |
914 | else | |
915 | { | |
916 | DBG1(DBG_TLS, "received TLS cert request for unknown CA '%Y'", id); | |
917 | } | |
918 | id->destroy(id); | |
3ddd164e | 919 | } |
3e962b08 | 920 | } |
4ef946dd | 921 | authorities->destroy(authorities); |
9ef46cfa PK |
922 | return TRUE; |
923 | } | |
924 | ||
925 | /** | |
926 | * Process a Certificate Request message | |
927 | */ | |
928 | static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader) | |
929 | { | |
930 | chunk_t types, hashsig, context, ext; | |
931 | bio_reader_t *extensions, *extension; | |
932 | ||
933 | if (!this->peer) | |
934 | { | |
935 | DBG1(DBG_TLS, "server requested a certificate, but client " | |
936 | "authentication disabled"); | |
937 | } | |
938 | this->crypto->append_handshake(this->crypto, | |
939 | TLS_CERTIFICATE_REQUEST, reader->peek(reader)); | |
940 | ||
941 | if (this->tls->get_version_max(this->tls) < TLS_1_3) | |
942 | { | |
943 | if (!reader->read_data8(reader, &types)) | |
944 | { | |
945 | DBG1(DBG_TLS, "certreq message header invalid"); | |
946 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
947 | return NEED_MORE; | |
948 | } | |
949 | this->cert_types = chunk_clone(types); | |
950 | if (this->tls->get_version_max(this->tls) >= TLS_1_2) | |
951 | { | |
952 | if (!reader->read_data16(reader, &hashsig)) | |
953 | { | |
954 | DBG1(DBG_TLS, "certreq message invalid"); | |
955 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
956 | return NEED_MORE; | |
957 | } | |
958 | this->hashsig = chunk_clone(hashsig); | |
959 | } | |
960 | ||
961 | if (!read_certificate_authorities(this, reader)) | |
962 | { | |
963 | DBG1(DBG_TLS, "certreq message invalid"); | |
964 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
965 | return NEED_MORE; | |
966 | } | |
967 | } | |
968 | else | |
969 | { | |
970 | /* certificate request context as described in RFC 8446, section 4.3.2 */ | |
971 | reader->read_data8(reader, &context); | |
972 | ||
973 | reader->read_data16(reader, &ext); | |
974 | extensions = bio_reader_create(ext); | |
975 | while (extensions->remaining(extensions)) | |
976 | { | |
977 | uint16_t extension_type; | |
978 | chunk_t extension_data; | |
979 | ||
980 | if (!extensions->read_uint16(extensions, &extension_type) || | |
981 | !extensions->read_data16(extensions, &extension_data)) | |
982 | { | |
983 | DBG1(DBG_TLS, "invalid extension in CertificateRequest"); | |
984 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
985 | extensions->destroy(extensions); | |
986 | return NEED_MORE; | |
987 | } | |
988 | extension = bio_reader_create(extension_data); | |
989 | switch (extension_type) | |
990 | { | |
991 | case TLS_EXT_SIGNATURE_ALGORITHMS: | |
992 | if (!extension->read_data16(extension, &extension_data)) | |
993 | { | |
994 | DBG1(DBG_TLS, "invalid %N extension", | |
995 | tls_extension_names, extension_type); | |
996 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
997 | extension->destroy(extension); | |
998 | extensions->destroy(extensions); | |
999 | return NEED_MORE; | |
1000 | } | |
1001 | chunk_free(&this->hashsig); | |
1002 | this->hashsig = chunk_clone(extension_data); | |
1003 | break; | |
1004 | case TLS_EXT_CERTIFICATE_AUTHORITIES: | |
1005 | if (!read_certificate_authorities(this, extension)) | |
1006 | { | |
1007 | DBG1(DBG_TLS, "certificate request message invalid"); | |
1008 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
1009 | extension->destroy(extension); | |
1010 | extensions->destroy(extensions); | |
1011 | return NEED_MORE; | |
1012 | } | |
1013 | break; | |
1014 | default: | |
1015 | break; | |
1016 | } | |
1017 | extension->destroy(extension); | |
1018 | } | |
1019 | extensions->destroy(extensions); | |
1020 | } | |
8fef06a6 | 1021 | this->state = STATE_CERTREQ_RECEIVED; |
3e962b08 MW |
1022 | return NEED_MORE; |
1023 | } | |
1024 | ||
3ddd164e MW |
1025 | /** |
1026 | * Process Hello Done message | |
1027 | */ | |
1028 | static status_t process_hello_done(private_tls_peer_t *this, | |
7e432eff | 1029 | bio_reader_t *reader) |
3ddd164e | 1030 | { |
84d67ead MW |
1031 | this->crypto->append_handshake(this->crypto, |
1032 | TLS_SERVER_HELLO_DONE, reader->peek(reader)); | |
3ddd164e MW |
1033 | this->state = STATE_HELLO_DONE; |
1034 | return NEED_MORE; | |
1035 | } | |
1036 | ||
f139b578 MW |
1037 | /** |
1038 | * Process finished message | |
1039 | */ | |
7e432eff | 1040 | static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader) |
f139b578 | 1041 | { |
7a2b0266 | 1042 | chunk_t received, verify_data; |
de31646a | 1043 | u_char buf[12]; |
110364b0 | 1044 | |
7a2b0266 | 1045 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
110364b0 | 1046 | { |
7a2b0266 | 1047 | if (!reader->read_data(reader, sizeof(buf), &received)) |
1048 | { | |
1049 | DBG1(DBG_TLS, "received server finished too short"); | |
1050 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
1051 | return NEED_MORE; | |
1052 | } | |
2e1c0a27 TB |
1053 | if (!this->crypto->calculate_finished_legacy(this->crypto, |
1054 | "server finished", buf)) | |
7a2b0266 | 1055 | { |
1056 | DBG1(DBG_TLS, "calculating server finished failed"); | |
1057 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1058 | return NEED_MORE; | |
1059 | } | |
de31646a | 1060 | verify_data = chunk_from_thing(buf); |
110364b0 | 1061 | } |
7a2b0266 | 1062 | else |
110364b0 | 1063 | { |
de31646a TB |
1064 | received = reader->peek(reader); |
1065 | if (!this->crypto->calculate_finished(this->crypto, TRUE, &verify_data)) | |
7a2b0266 | 1066 | { |
1067 | DBG1(DBG_TLS, "calculating server finished failed"); | |
1068 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1069 | return NEED_MORE; | |
1070 | } | |
110364b0 | 1071 | } |
6a5c86b7 | 1072 | |
de31646a TB |
1073 | if (!chunk_equals_const(received, verify_data)) |
1074 | { | |
1075 | DBG1(DBG_TLS, "received server finished invalid"); | |
1076 | this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR); | |
1077 | return NEED_MORE; | |
1078 | } | |
1079 | ||
1080 | if (verify_data.ptr != buf) | |
1081 | { | |
1082 | chunk_free(&verify_data); | |
1083 | } | |
1084 | ||
1085 | this->crypto->append_handshake(this->crypto, TLS_FINISHED, received); | |
1086 | this->state = STATE_FINISHED_RECEIVED; | |
110364b0 | 1087 | return NEED_MORE; |
f139b578 MW |
1088 | } |
1089 | ||
7a2b0266 | 1090 | /** |
de31646a | 1091 | * Process NewSessionTicket message |
7a2b0266 | 1092 | */ |
1093 | static status_t process_new_session_ticket(private_tls_peer_t *this, | |
1094 | bio_reader_t *reader) | |
1095 | { | |
1096 | uint32_t ticket_lifetime, ticket_age_add; | |
1097 | chunk_t ticket_nonce, ticket, extensions; | |
1098 | ||
1099 | if (!reader->read_uint32(reader, &ticket_lifetime) || | |
1100 | !reader->read_uint32(reader, &ticket_age_add) || | |
1101 | !reader->read_data8(reader, &ticket_nonce) || | |
1102 | !reader->read_data16(reader, &ticket) || | |
1103 | !reader->read_data16(reader, &extensions)) | |
1104 | { | |
1105 | DBG1(DBG_TLS, "received invalid NewSessionTicket"); | |
1106 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
1107 | return NEED_MORE; | |
1108 | } | |
1109 | return NEED_MORE; | |
1110 | } | |
1111 | ||
bfcb49b3 TB |
1112 | /** |
1113 | * Process KeyUpdate message | |
1114 | */ | |
1115 | static status_t process_key_update(private_tls_peer_t *this, | |
1116 | bio_reader_t *reader) | |
1117 | { | |
1118 | uint8_t update_requested; | |
1119 | ||
1120 | if (!reader->read_uint8(reader, &update_requested) || | |
1121 | update_requested > 1) | |
1122 | { | |
1123 | DBG1(DBG_TLS, "received invalid KeyUpdate"); | |
1124 | this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); | |
1125 | return NEED_MORE; | |
1126 | } | |
1127 | ||
1128 | if (!this->crypto->update_app_keys(this->crypto, TRUE)) | |
1129 | { | |
1130 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1131 | return NEED_MORE; | |
1132 | } | |
1133 | this->crypto->change_cipher(this->crypto, TRUE); | |
1134 | ||
1135 | if (update_requested) | |
1136 | { | |
e02f19e3 TB |
1137 | DBG1(DBG_TLS, "server requested KeyUpdate"); |
1138 | this->state = STATE_KEY_UPDATE_REQUESTED; | |
bfcb49b3 TB |
1139 | } |
1140 | return NEED_MORE; | |
1141 | } | |
1142 | ||
4c0c2283 | 1143 | METHOD(tls_handshake_t, process, status_t, |
7e432eff | 1144 | private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader) |
4c0c2283 | 1145 | { |
8fef06a6 MW |
1146 | tls_handshake_type_t expected; |
1147 | ||
7a2b0266 | 1148 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
3e962b08 | 1149 | { |
7a2b0266 | 1150 | switch (this->state) |
1151 | { | |
1152 | case STATE_HELLO_SENT: | |
1153 | if (type == TLS_SERVER_HELLO) | |
1154 | { | |
1155 | return process_server_hello(this, reader); | |
1156 | } | |
1157 | expected = TLS_SERVER_HELLO; | |
1158 | break; | |
1159 | case STATE_HELLO_RECEIVED: | |
1160 | if (type == TLS_CERTIFICATE) | |
1161 | { | |
1162 | return process_certificate(this, reader); | |
1163 | } | |
1164 | expected = TLS_CERTIFICATE; | |
1165 | break; | |
1166 | case STATE_CERT_RECEIVED: | |
1167 | if (type == TLS_SERVER_KEY_EXCHANGE) | |
1168 | { | |
1169 | return process_key_exchange(this, reader); | |
1170 | } | |
1171 | /* fall through since TLS_SERVER_KEY_EXCHANGE is optional */ | |
1172 | case STATE_KEY_EXCHANGE_RECEIVED: | |
1173 | if (type == TLS_CERTIFICATE_REQUEST) | |
1174 | { | |
1175 | return process_certreq(this, reader); | |
1176 | } | |
1177 | /* no cert request, server does not want to authenticate us */ | |
1178 | DESTROY_IF(this->peer); | |
1179 | this->peer = NULL; | |
1180 | /* fall through since TLS_CERTIFICATE_REQUEST is optional */ | |
1181 | case STATE_CERTREQ_RECEIVED: | |
1182 | if (type == TLS_SERVER_HELLO_DONE) | |
1183 | { | |
1184 | return process_hello_done(this, reader); | |
1185 | } | |
1186 | expected = TLS_SERVER_HELLO_DONE; | |
1187 | break; | |
1188 | case STATE_CIPHERSPEC_CHANGED_IN: | |
1189 | if (type == TLS_FINISHED) | |
1190 | { | |
1191 | return process_finished(this, reader); | |
1192 | } | |
1193 | expected = TLS_FINISHED; | |
1194 | break; | |
1195 | default: | |
1196 | DBG1(DBG_TLS, "TLS %N not expected in current state", | |
1197 | tls_handshake_type_names, type); | |
1198 | this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE); | |
1199 | return NEED_MORE; | |
1200 | } | |
1201 | } | |
1202 | else | |
1203 | { | |
1204 | switch (this->state) | |
1205 | { | |
1206 | case STATE_HELLO_SENT: | |
1207 | if (type == TLS_SERVER_HELLO) | |
1208 | { | |
1209 | return process_server_hello(this, reader); | |
1210 | } | |
1211 | expected = TLS_SERVER_HELLO; | |
1212 | break; | |
1213 | case STATE_CIPHERSPEC_CHANGED_IN: | |
1214 | case STATE_HELLO_RECEIVED: | |
1215 | if (type == TLS_ENCRYPTED_EXTENSIONS) | |
1216 | { | |
1217 | return process_encrypted_extensions(this, reader); | |
1218 | } | |
1219 | expected = TLS_ENCRYPTED_EXTENSIONS; | |
1220 | break; | |
1221 | case STATE_ENCRYPTED_EXTENSIONS_RECEIVED: | |
9ef46cfa PK |
1222 | if (type == TLS_CERTIFICATE_REQUEST) |
1223 | { | |
1224 | return process_certreq(this, reader); | |
1225 | } | |
1226 | /* no cert request, server does not want to authenticate us */ | |
1227 | DESTROY_IF(this->peer); | |
1228 | this->peer = NULL; | |
1229 | /* otherwise fall through to next state */ | |
1230 | case STATE_CERTREQ_RECEIVED: | |
7a2b0266 | 1231 | if (type == TLS_CERTIFICATE) |
1232 | { | |
1233 | return process_certificate(this, reader); | |
1234 | } | |
1235 | expected = TLS_CERTIFICATE; | |
1236 | break; | |
1237 | case STATE_CERT_RECEIVED: | |
1238 | if (type == TLS_CERTIFICATE_VERIFY) | |
1239 | { | |
1240 | return process_cert_verify(this, reader); | |
1241 | } | |
1242 | expected = TLS_CERTIFICATE_VERIFY; | |
1243 | break; | |
1244 | case STATE_CERT_VERIFY_RECEIVED: | |
1245 | if (type == TLS_FINISHED) | |
1246 | { | |
1247 | return process_finished(this, reader); | |
1248 | } | |
1249 | expected = TLS_FINISHED; | |
1250 | break; | |
1251 | case STATE_FINISHED_RECEIVED: | |
1252 | return NEED_MORE; | |
1253 | case STATE_FINISHED_SENT_KEY_SWITCHED: | |
1254 | if (type == TLS_NEW_SESSION_TICKET) | |
1255 | { | |
1256 | return process_new_session_ticket(this, reader); | |
1257 | } | |
bfcb49b3 TB |
1258 | if (type == TLS_KEY_UPDATE) |
1259 | { | |
1260 | return process_key_update(this, reader); | |
1261 | } | |
7a2b0266 | 1262 | expected = TLS_NEW_SESSION_TICKET; |
1263 | break; | |
1264 | default: | |
1265 | DBG1(DBG_TLS, "TLS %N not expected in current state", | |
1266 | tls_handshake_type_names, type); | |
1267 | this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE); | |
1268 | return NEED_MORE; | |
1269 | } | |
3e962b08 | 1270 | } |
3c19b346 | 1271 | DBG1(DBG_TLS, "TLS %N expected, but received %N", |
8fef06a6 | 1272 | tls_handshake_type_names, expected, tls_handshake_type_names, type); |
e6f3ef13 MW |
1273 | this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE); |
1274 | return NEED_MORE; | |
4c0c2283 MW |
1275 | } |
1276 | ||
698674c7 MW |
1277 | /** |
1278 | * Send a client hello | |
1279 | */ | |
8fef06a6 | 1280 | static status_t send_client_hello(private_tls_peer_t *this, |
851b605e TB |
1281 | tls_handshake_type_t *type, |
1282 | bio_writer_t *writer) | |
698674c7 | 1283 | { |
7ea87db0 | 1284 | tls_cipher_suite_t *suites; |
6549adb6 | 1285 | bio_writer_t *extensions, *curves = NULL, *versions, *key_share, *signatures; |
7a2b0266 | 1286 | tls_version_t version_max, version_min; |
851b605e | 1287 | diffie_hellman_group_t group; |
066ac880 | 1288 | tls_named_group_t curve; |
3f7bb88b | 1289 | enumerator_t *enumerator; |
7a2b0266 | 1290 | int count, i, v; |
698674c7 MW |
1291 | rng_t *rng; |
1292 | ||
18010de2 | 1293 | htoun32(&this->client_random, time(NULL)); |
698674c7 | 1294 | rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); |
126eb2af TB |
1295 | if (!rng || |
1296 | !rng->get_bytes(rng, sizeof(this->client_random) - 4, | |
1297 | this->client_random + 4)) | |
698674c7 | 1298 | { |
126eb2af | 1299 | DBG1(DBG_TLS, "failed to generate client random"); |
e6f3ef13 | 1300 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); |
126eb2af | 1301 | DESTROY_IF(rng); |
e6f3ef13 | 1302 | return NEED_MORE; |
698674c7 | 1303 | } |
3a1640de MW |
1304 | rng->destroy(rng); |
1305 | ||
8a6edc08 PK |
1306 | /* determine supported suites before the versions as they might change */ |
1307 | count = this->crypto->get_cipher_suites(this->crypto, &suites); | |
1308 | ||
7a2b0266 | 1309 | /* TLS version_max in handshake protocol */ |
1310 | version_max = this->tls->get_version_max(this->tls); | |
1311 | version_min = this->tls->get_version_min(this->tls); | |
1312 | if (version_max < TLS_1_3) | |
1313 | { | |
1314 | this->hello_version = version_max; | |
1315 | } | |
1316 | else | |
1317 | { | |
1318 | this->hello_version = TLS_1_2; | |
1319 | } | |
1320 | writer->write_uint16(writer, this->hello_version); | |
18010de2 | 1321 | writer->write_data(writer, chunk_from_thing(this->client_random)); |
7ea87db0 | 1322 | |
6a5c86b7 MW |
1323 | /* session identifier */ |
1324 | this->session = this->crypto->get_session(this->crypto, this->server); | |
1325 | writer->write_data8(writer, this->session); | |
3a1640de | 1326 | |
7ea87db0 | 1327 | /* add TLS cipher suites */ |
f9201253 PK |
1328 | if (count <= 0) |
1329 | { | |
1330 | DBG1(DBG_TLS, "no supported TLS cipher suite available"); | |
1331 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1332 | return NEED_MORE; | |
1333 | } | |
3a1640de MW |
1334 | writer->write_uint16(writer, count * 2); |
1335 | for (i = 0; i < count; i++) | |
1336 | { | |
7ea87db0 | 1337 | writer->write_uint16(writer, suites[i]); |
3a1640de | 1338 | } |
7ea87db0 | 1339 | |
3a1640de MW |
1340 | /* NULL compression only */ |
1341 | writer->write_uint8(writer, 1); | |
1342 | writer->write_uint8(writer, 0); | |
1343 | ||
7e432eff | 1344 | extensions = bio_writer_create(32); |
37a59a8f | 1345 | |
7a2b0266 | 1346 | if (this->server->get_type(this->server) == ID_FQDN) |
1347 | { | |
1348 | bio_writer_t *names; | |
37a59a8f | 1349 | |
7a2b0266 | 1350 | DBG2(DBG_TLS, "sending extension: Server Name Indication for '%Y'", |
1351 | this->server); | |
1352 | names = bio_writer_create(8); | |
1353 | names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME); | |
1354 | names->write_data16(names, this->server->get_encoding(this->server)); | |
1355 | names->wrap16(names); | |
1356 | extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME); | |
1357 | extensions->write_data16(extensions, names->get_buf(names)); | |
1358 | names->destroy(names); | |
1359 | } | |
1360 | ||
3f7bb88b | 1361 | enumerator = this->crypto->create_ec_enumerator(this->crypto); |
851b605e | 1362 | while (enumerator->enumerate(enumerator, &group, &curve)) |
3f7bb88b | 1363 | { |
2b6565c2 TB |
1364 | if (this->requested_curve && this->requested_curve != curve) |
1365 | { | |
1366 | continue; | |
1367 | } | |
3f7bb88b MW |
1368 | if (!curves) |
1369 | { | |
7a2b0266 | 1370 | extensions->write_uint16(extensions, TLS_EXT_SUPPORTED_GROUPS); |
7e432eff | 1371 | curves = bio_writer_create(16); |
3f7bb88b | 1372 | } |
851b605e TB |
1373 | if (!this->dh) |
1374 | { | |
1375 | this->dh = lib->crypto->create_dh(lib->crypto, group); | |
1376 | if (!this->dh) | |
1377 | { | |
1378 | continue; | |
1379 | } | |
851b605e | 1380 | } |
3f7bb88b MW |
1381 | curves->write_uint16(curves, curve); |
1382 | } | |
1383 | enumerator->destroy(enumerator); | |
7b64880a | 1384 | |
3f7bb88b MW |
1385 | if (curves) |
1386 | { | |
7b64880a TB |
1387 | DBG2(DBG_TLS, "sending extension: %N", |
1388 | tls_extension_names, TLS_EXT_SUPPORTED_GROUPS); | |
1389 | ||
07f826af | 1390 | curves->wrap16(curves); |
3f7bb88b MW |
1391 | extensions->write_data16(extensions, curves->get_buf(curves)); |
1392 | curves->destroy(curves); | |
31c65eb3 MW |
1393 | |
1394 | /* if we support curves, add point format extension */ | |
1395 | extensions->write_uint16(extensions, TLS_EXT_EC_POINT_FORMATS); | |
1396 | extensions->write_uint16(extensions, 2); | |
1397 | extensions->write_uint8(extensions, 1); | |
1398 | extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED); | |
3f7bb88b | 1399 | } |
7a2b0266 | 1400 | |
851b605e | 1401 | if (version_max >= TLS_1_3) |
1c21f47a | 1402 | { |
851b605e TB |
1403 | DBG2(DBG_TLS, "sending extension: %N", |
1404 | tls_extension_names, TLS_EXT_SUPPORTED_VERSIONS); | |
1405 | extensions->write_uint16(extensions, TLS_EXT_SUPPORTED_VERSIONS); | |
1406 | versions = bio_writer_create(0); | |
1407 | for (v = version_max; v >= version_min; v--) | |
1408 | { | |
1409 | versions->write_uint16(versions, v); | |
1410 | } | |
1411 | versions->wrap8(versions); | |
1412 | extensions->write_data16(extensions, versions->get_buf(versions)); | |
1413 | versions->destroy(versions); | |
7a2b0266 | 1414 | } |
1c21f47a | 1415 | |
2b6565c2 TB |
1416 | if (this->cookie.len) |
1417 | { | |
1418 | DBG2(DBG_TLS, "sending extension: %N", | |
1419 | tls_extension_names, TLS_EXT_COOKIE); | |
1420 | extensions->write_uint16(extensions, TLS_EXT_COOKIE); | |
1421 | extensions->write_uint16(extensions, this->cookie.len + 2); | |
1422 | extensions->write_data16(extensions, this->cookie); | |
1423 | chunk_free(&this->cookie); | |
1424 | } | |
1425 | ||
7a2b0266 | 1426 | DBG2(DBG_TLS, "sending extension: %N", |
1427 | tls_extension_names, TLS_EXT_SIGNATURE_ALGORITHMS); | |
1428 | extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS); | |
6549adb6 PK |
1429 | signatures = bio_writer_create(32); |
1430 | this->crypto->get_signature_algorithms(this->crypto, signatures, FALSE); | |
1431 | extensions->write_data16(extensions, signatures->get_buf(signatures)); | |
1432 | signatures->destroy(signatures); | |
1433 | ||
1b593e1d TB |
1434 | DBG2(DBG_TLS, "sending extension: %N", |
1435 | tls_extension_names, TLS_EXT_SIGNATURE_ALGORITHMS_CERT); | |
1436 | extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS_CERT); | |
6549adb6 PK |
1437 | signatures = bio_writer_create(32); |
1438 | this->crypto->get_signature_algorithms(this->crypto, signatures, TRUE); | |
1439 | extensions->write_data16(extensions, signatures->get_buf(signatures)); | |
1440 | signatures->destroy(signatures); | |
1c21f47a | 1441 | |
066ac880 | 1442 | if (this->tls->get_version_max(this->tls) >= TLS_1_3) |
7a2b0266 | 1443 | { |
851b605e TB |
1444 | DBG2(DBG_TLS, "sending extension: %N", |
1445 | tls_extension_names, TLS_EXT_KEY_SHARE); | |
5c4cb40e | 1446 | extensions->write_uint16(extensions, TLS_EXT_KEY_SHARE); |
066ac880 | 1447 | if (!tls_write_key_share(&key_share, this->dh)) |
851b605e TB |
1448 | { |
1449 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1450 | extensions->destroy(extensions); | |
1451 | return NEED_MORE; | |
1452 | } | |
851b605e TB |
1453 | key_share->wrap16(key_share); |
1454 | extensions->write_data16(extensions, key_share->get_buf(key_share)); | |
1455 | key_share->destroy(key_share); | |
1c21f47a | 1456 | } |
37a59a8f | 1457 | |
06109c47 MW |
1458 | writer->write_data16(writer, extensions->get_buf(extensions)); |
1459 | extensions->destroy(extensions); | |
1460 | ||
3a1640de | 1461 | *type = TLS_CLIENT_HELLO; |
3e962b08 | 1462 | this->state = STATE_HELLO_SENT; |
84d67ead | 1463 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); |
3ddd164e MW |
1464 | return NEED_MORE; |
1465 | } | |
1466 | ||
dbb7c030 | 1467 | /** |
d41d8b00 PK |
1468 | * Convert certificate types to signature schemes so TLS version <= 1.1 can use |
1469 | * the same private key enumeration as newer TLS versions. | |
dbb7c030 | 1470 | */ |
d41d8b00 | 1471 | static void convert_cert_types(private_tls_peer_t *this) |
dbb7c030 | 1472 | { |
7e432eff | 1473 | bio_reader_t *reader; |
d41d8b00 PK |
1474 | bio_writer_t *writer; |
1475 | uint8_t type; | |
dbb7c030 | 1476 | |
7e432eff | 1477 | reader = bio_reader_create(this->cert_types); |
d41d8b00 PK |
1478 | writer = bio_writer_create(0); |
1479 | while (reader->remaining(reader) && reader->read_uint8(reader, &type)) | |
dbb7c030 | 1480 | { |
d41d8b00 PK |
1481 | /* each certificate type is mapped to one signature scheme, which is not |
1482 | * ideal but serves our needs in legacy TLS versions */ | |
1483 | switch (type) | |
dbb7c030 MW |
1484 | { |
1485 | case TLS_RSA_SIGN: | |
d41d8b00 | 1486 | writer->write_uint16(writer, TLS_SIG_RSA_PKCS1_SHA256); |
dbb7c030 MW |
1487 | break; |
1488 | case TLS_ECDSA_SIGN: | |
d41d8b00 | 1489 | writer->write_uint16(writer, TLS_SIG_ECDSA_SHA256); |
dbb7c030 MW |
1490 | break; |
1491 | default: | |
1492 | continue; | |
1493 | } | |
dbb7c030 MW |
1494 | } |
1495 | reader->destroy(reader); | |
d41d8b00 PK |
1496 | this->hashsig = writer->extract_buf(writer); |
1497 | writer->destroy(writer); | |
dbb7c030 MW |
1498 | } |
1499 | ||
3ddd164e MW |
1500 | /** |
1501 | * Send Certificate | |
1502 | */ | |
1503 | static status_t send_certificate(private_tls_peer_t *this, | |
7e432eff | 1504 | tls_handshake_type_t *type, bio_writer_t *writer) |
3ddd164e MW |
1505 | { |
1506 | enumerator_t *enumerator; | |
1507 | certificate_t *cert; | |
1508 | auth_rule_t rule; | |
7e432eff | 1509 | bio_writer_t *certs; |
d8e42a3d PK |
1510 | private_key_t *key; |
1511 | auth_cfg_t *auth; | |
3ddd164e | 1512 | chunk_t data; |
d8e42a3d | 1513 | tls_version_t version_min, version_max; |
3ddd164e | 1514 | |
d8e42a3d PK |
1515 | version_min = this->tls->get_version_min(this->tls); |
1516 | version_max = this->tls->get_version_max(this->tls); | |
d41d8b00 PK |
1517 | if (!this->hashsig.len) |
1518 | { | |
1519 | convert_cert_types(this); | |
1520 | } | |
1521 | enumerator = tls_create_private_key_enumerator(version_min, version_max, | |
1522 | this->hashsig, this->peer); | |
1523 | if (!enumerator || !enumerator->enumerate(enumerator, &key, &auth)) | |
d8e42a3d | 1524 | { |
d8e42a3d PK |
1525 | if (!enumerator) |
1526 | { | |
1527 | DBG1(DBG_TLS, "no common signature algorithms found"); | |
d8e42a3d | 1528 | } |
d41d8b00 | 1529 | else |
d8e42a3d | 1530 | { |
d41d8b00 PK |
1531 | DBG1(DBG_TLS, "no usable TLS client certificate found for '%Y'", |
1532 | this->peer); | |
d8e42a3d | 1533 | } |
d41d8b00 PK |
1534 | this->peer->destroy(this->peer); |
1535 | this->peer = NULL; | |
d8e42a3d PK |
1536 | } |
1537 | else | |
1538 | { | |
d41d8b00 PK |
1539 | this->private = key->get_ref(key); |
1540 | this->peer_auth->merge(this->peer_auth, auth, FALSE); | |
3ddd164e | 1541 | } |
d41d8b00 | 1542 | DESTROY_IF(enumerator); |
3ddd164e | 1543 | |
9ef46cfa PK |
1544 | /* certificate request context as described in RFC 8446, section 4.4.2 */ |
1545 | if (this->tls->get_version_max(this->tls) > TLS_1_2) | |
1546 | { | |
1547 | writer->write_uint8(writer, 0); | |
1548 | } | |
1549 | ||
3ddd164e | 1550 | /* generate certificate payload */ |
7e432eff | 1551 | certs = bio_writer_create(256); |
9ef46cfa PK |
1552 | cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT); |
1553 | if (cert) | |
3ddd164e | 1554 | { |
9ef46cfa PK |
1555 | if (cert->get_encoding(cert, CERT_ASN1_DER, &data)) |
1556 | { | |
1557 | DBG1(DBG_TLS, "sending TLS client certificate '%Y'", | |
1558 | cert->get_subject(cert)); | |
1559 | certs->write_data24(certs, data); | |
1560 | free(data.ptr); | |
1561 | } | |
1562 | /* extensions see RFC 8446, section 4.4.2 */ | |
1563 | if (this->tls->get_version_max(this->tls) > TLS_1_2) | |
1564 | { | |
1565 | certs->write_uint16(certs, 0); | |
1566 | } | |
1567 | } | |
1568 | enumerator = this->peer_auth->create_enumerator(this->peer_auth); | |
1569 | while (enumerator->enumerate(enumerator, &rule, &cert)) | |
1570 | { | |
1571 | if (rule == AUTH_RULE_IM_CERT) | |
3ddd164e | 1572 | { |
0b71bc7a MW |
1573 | if (cert->get_encoding(cert, CERT_ASN1_DER, &data)) |
1574 | { | |
9ef46cfa | 1575 | DBG1(DBG_TLS, "sending TLS intermediate certificate '%Y'", |
0b71bc7a MW |
1576 | cert->get_subject(cert)); |
1577 | certs->write_data24(certs, data); | |
1578 | free(data.ptr); | |
1579 | } | |
3ddd164e MW |
1580 | } |
1581 | } | |
9ef46cfa | 1582 | enumerator->destroy(enumerator); |
3ddd164e MW |
1583 | |
1584 | writer->write_data24(writer, certs->get_buf(certs)); | |
1585 | certs->destroy(certs); | |
1586 | ||
1587 | *type = TLS_CERTIFICATE; | |
1588 | this->state = STATE_CERT_SENT; | |
84d67ead | 1589 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); |
3ddd164e MW |
1590 | return NEED_MORE; |
1591 | } | |
1592 | ||
1593 | /** | |
da3f4a9f | 1594 | * Send client key exchange, using premaster encryption |
3ddd164e | 1595 | */ |
da3f4a9f | 1596 | static status_t send_key_exchange_encrypt(private_tls_peer_t *this, |
7e432eff | 1597 | tls_handshake_type_t *type, bio_writer_t *writer) |
3ddd164e | 1598 | { |
da3f4a9f | 1599 | public_key_t *public; |
3ddd164e MW |
1600 | rng_t *rng; |
1601 | char premaster[48]; | |
1602 | chunk_t encrypted; | |
1603 | ||
1604 | rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); | |
126eb2af | 1605 | if (!rng || !rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2)) |
3ddd164e | 1606 | { |
126eb2af | 1607 | DBG1(DBG_TLS, "failed to generate TLS premaster secret"); |
a596006e | 1608 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); |
126eb2af | 1609 | DESTROY_IF(rng); |
da3f4a9f | 1610 | return NEED_MORE; |
3ddd164e | 1611 | } |
3ddd164e | 1612 | rng->destroy(rng); |
b37080f8 | 1613 | htoun16(premaster, this->hello_version); |
3ddd164e | 1614 | |
9020f7d0 MW |
1615 | if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), |
1616 | this->session, this->server, | |
1617 | chunk_from_thing(this->client_random), | |
1618 | chunk_from_thing(this->server_random))) | |
1619 | { | |
1620 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1621 | return NEED_MORE; | |
1622 | } | |
18010de2 | 1623 | |
e4b4aabc | 1624 | public = tls_find_public_key(this->server_auth, this->server); |
3ddd164e MW |
1625 | if (!public) |
1626 | { | |
3c19b346 | 1627 | DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server); |
a596006e | 1628 | this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN); |
da3f4a9f | 1629 | return NEED_MORE; |
3ddd164e | 1630 | } |
4abb29f6 | 1631 | if (!public->encrypt(public, ENCRYPT_RSA_PKCS1, NULL, |
33ddaaab | 1632 | chunk_from_thing(premaster), &encrypted)) |
3ddd164e MW |
1633 | { |
1634 | public->destroy(public); | |
3c19b346 | 1635 | DBG1(DBG_TLS, "encrypting TLS premaster secret failed"); |
a596006e | 1636 | this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE); |
da3f4a9f | 1637 | return NEED_MORE; |
3ddd164e MW |
1638 | } |
1639 | public->destroy(public); | |
1640 | ||
1641 | writer->write_data16(writer, encrypted); | |
1642 | free(encrypted.ptr); | |
1643 | ||
1644 | *type = TLS_CLIENT_KEY_EXCHANGE; | |
1645 | this->state = STATE_KEY_EXCHANGE_SENT; | |
84d67ead | 1646 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); |
3ddd164e MW |
1647 | return NEED_MORE; |
1648 | } | |
1649 | ||
da3f4a9f MW |
1650 | /** |
1651 | * Send client key exchange, using DHE exchange | |
1652 | */ | |
1653 | static status_t send_key_exchange_dhe(private_tls_peer_t *this, | |
7e432eff | 1654 | tls_handshake_type_t *type, bio_writer_t *writer) |
da3f4a9f MW |
1655 | { |
1656 | chunk_t premaster, pub; | |
1657 | ||
bace1d64 | 1658 | if (!this->dh->get_shared_secret(this->dh, &premaster)) |
da3f4a9f MW |
1659 | { |
1660 | DBG1(DBG_TLS, "calculating premaster from DH failed"); | |
1661 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1662 | return NEED_MORE; | |
1663 | } | |
9020f7d0 MW |
1664 | if (!this->crypto->derive_secrets(this->crypto, premaster, |
1665 | this->session, this->server, | |
1666 | chunk_from_thing(this->client_random), | |
1667 | chunk_from_thing(this->server_random))) | |
1668 | { | |
1669 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1670 | chunk_clear(&premaster); | |
1671 | return NEED_MORE; | |
1672 | } | |
da3f4a9f MW |
1673 | chunk_clear(&premaster); |
1674 | ||
42431690 MW |
1675 | if (!this->dh->get_my_public_value(this->dh, &pub)) |
1676 | { | |
1677 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1678 | return NEED_MORE; | |
1679 | } | |
8495138d | 1680 | switch (this->dh->get_dh_group(this->dh)) |
5fc7297e | 1681 | { |
8495138d TB |
1682 | case MODP_CUSTOM: |
1683 | writer->write_data16(writer, pub); | |
1684 | break; | |
1685 | case CURVE_25519: | |
1686 | case CURVE_448: | |
1687 | /* ECPoint uses an 8-bit length header only */ | |
1688 | writer->write_data8(writer, pub); | |
1689 | break; | |
1690 | default: | |
1691 | /* classic ECPoint format (see RFC 8422, section 5.4.1) */ | |
1692 | writer->write_uint8(writer, pub.len + 1); | |
1693 | writer->write_uint8(writer, TLS_ANSI_UNCOMPRESSED); | |
1694 | writer->write_data(writer, pub); | |
1695 | break; | |
5fc7297e | 1696 | } |
da3f4a9f MW |
1697 | free(pub.ptr); |
1698 | ||
1699 | *type = TLS_CLIENT_KEY_EXCHANGE; | |
1700 | this->state = STATE_KEY_EXCHANGE_SENT; | |
1701 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); | |
1702 | return NEED_MORE; | |
1703 | } | |
1704 | ||
1705 | /** | |
1706 | * Send client key exchange, depending on suite | |
1707 | */ | |
1708 | static status_t send_key_exchange(private_tls_peer_t *this, | |
7e432eff | 1709 | tls_handshake_type_t *type, bio_writer_t *writer) |
da3f4a9f MW |
1710 | { |
1711 | if (this->dh) | |
1712 | { | |
1713 | return send_key_exchange_dhe(this, type, writer); | |
1714 | } | |
1715 | return send_key_exchange_encrypt(this, type, writer); | |
1716 | } | |
1717 | ||
3ddd164e MW |
1718 | /** |
1719 | * Send certificate verify | |
1720 | */ | |
1721 | static status_t send_certificate_verify(private_tls_peer_t *this, | |
9ef46cfa PK |
1722 | tls_handshake_type_t *type, |
1723 | bio_writer_t *writer) | |
3ddd164e | 1724 | { |
84d67ead | 1725 | if (!this->private || |
dbb7c030 MW |
1726 | !this->crypto->sign_handshake(this->crypto, this->private, |
1727 | writer, this->hashsig)) | |
3ddd164e | 1728 | { |
3c19b346 | 1729 | DBG1(DBG_TLS, "creating TLS Certificate Verify signature failed"); |
a596006e | 1730 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); |
da3f4a9f | 1731 | return NEED_MORE; |
3ddd164e | 1732 | } |
3ddd164e MW |
1733 | |
1734 | *type = TLS_CERTIFICATE_VERIFY; | |
1735 | this->state = STATE_VERIFY_SENT; | |
84d67ead | 1736 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); |
3ddd164e MW |
1737 | return NEED_MORE; |
1738 | } | |
1739 | ||
1740 | /** | |
1741 | * Send Finished | |
1742 | */ | |
1743 | static status_t send_finished(private_tls_peer_t *this, | |
7e432eff | 1744 | tls_handshake_type_t *type, bio_writer_t *writer) |
3ddd164e | 1745 | { |
7a2b0266 | 1746 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
18010de2 | 1747 | { |
7a2b0266 | 1748 | char buf[12]; |
1749 | ||
2e1c0a27 TB |
1750 | if (!this->crypto->calculate_finished_legacy(this->crypto, |
1751 | "client finished", buf)) | |
7a2b0266 | 1752 | { |
1753 | DBG1(DBG_TLS, "calculating client finished data failed"); | |
1754 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1755 | return NEED_MORE; | |
1756 | } | |
1757 | ||
1758 | writer->write_data(writer, chunk_from_thing(buf)); | |
18010de2 | 1759 | } |
7a2b0266 | 1760 | else |
1761 | { | |
de31646a TB |
1762 | chunk_t verify_data; |
1763 | ||
2e1c0a27 | 1764 | if (!this->crypto->calculate_finished(this->crypto, FALSE, &verify_data)) |
7a2b0266 | 1765 | { |
1766 | DBG1(DBG_TLS, "calculating client finished data failed"); | |
1767 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1768 | return NEED_MORE; | |
1769 | } | |
18010de2 | 1770 | |
7a2b0266 | 1771 | writer->write_data(writer, verify_data); |
de31646a | 1772 | chunk_free(&verify_data); |
7a2b0266 | 1773 | } |
18010de2 | 1774 | |
3ddd164e MW |
1775 | *type = TLS_FINISHED; |
1776 | this->state = STATE_FINISHED_SENT; | |
84d67ead | 1777 | this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); |
698674c7 MW |
1778 | return NEED_MORE; |
1779 | } | |
1780 | ||
e02f19e3 TB |
1781 | /** |
1782 | * Send KeyUpdate message | |
1783 | */ | |
1784 | static status_t send_key_update(private_tls_peer_t *this, | |
1785 | tls_handshake_type_t *type, bio_writer_t *writer) | |
1786 | { | |
1787 | *type = TLS_KEY_UPDATE; | |
1788 | ||
1789 | /* we currently only send this as reply, so we never request an update */ | |
1790 | writer->write_uint8(writer, 0); | |
1791 | ||
1792 | this->state = STATE_KEY_UPDATE_SENT; | |
1793 | return NEED_MORE; | |
1794 | } | |
1795 | ||
4c0c2283 | 1796 | METHOD(tls_handshake_t, build, status_t, |
7e432eff | 1797 | private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer) |
4c0c2283 | 1798 | { |
7a2b0266 | 1799 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
698674c7 | 1800 | { |
7a2b0266 | 1801 | switch (this->state) |
1802 | { | |
1803 | case STATE_INIT: | |
1804 | return send_client_hello(this, type, writer); | |
1805 | case STATE_HELLO_DONE: | |
1806 | if (this->peer) | |
1807 | { | |
1808 | return send_certificate(this, type, writer); | |
1809 | } | |
1810 | /* otherwise fall through to next state */ | |
1811 | case STATE_CERT_SENT: | |
1812 | return send_key_exchange(this, type, writer); | |
1813 | case STATE_KEY_EXCHANGE_SENT: | |
1814 | if (this->peer) | |
1815 | { | |
1816 | return send_certificate_verify(this, type, writer); | |
1817 | } | |
1818 | else | |
1819 | { | |
1820 | return INVALID_STATE; | |
1821 | } | |
1822 | case STATE_CIPHERSPEC_CHANGED_OUT: | |
1823 | return send_finished(this, type, writer); | |
1824 | default: | |
b4d30a42 | 1825 | return INVALID_STATE; |
7a2b0266 | 1826 | } |
698674c7 | 1827 | } |
7a2b0266 | 1828 | else |
1829 | { | |
1830 | switch (this->state) | |
1831 | { | |
1832 | case STATE_INIT: | |
1833 | return send_client_hello(this, type, writer); | |
1834 | case STATE_HELLO_DONE: | |
7a2b0266 | 1835 | case STATE_CIPHERSPEC_CHANGED_OUT: |
1836 | case STATE_FINISHED_RECEIVED: | |
2921f437 TB |
1837 | if (!this->crypto->derive_app_keys(this->crypto)) |
1838 | { | |
1839 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1840 | return NEED_MORE; | |
1841 | } | |
7a2b0266 | 1842 | this->crypto->change_cipher(this->crypto, TRUE); |
9ef46cfa PK |
1843 | if (this->peer) |
1844 | { | |
1845 | return send_certificate(this, type, writer); | |
1846 | } | |
1847 | /* otherwise fall through to next state */ | |
1848 | case STATE_CERT_SENT: | |
1849 | if (this->peer) | |
1850 | { | |
1851 | return send_certificate_verify(this, type, writer); | |
1852 | } | |
1853 | /* otherwise fall through to next state */ | |
1854 | case STATE_VERIFY_SENT: | |
2d933f31 PK |
1855 | return send_finished(this, type, writer); |
1856 | case STATE_FINISHED_SENT: | |
7a2b0266 | 1857 | this->crypto->change_cipher(this->crypto, FALSE); |
1858 | this->state = STATE_FINISHED_SENT_KEY_SWITCHED; | |
00a6280a | 1859 | return INVALID_STATE; |
e02f19e3 TB |
1860 | case STATE_KEY_UPDATE_REQUESTED: |
1861 | return send_key_update(this, type, writer); | |
1862 | case STATE_KEY_UPDATE_SENT: | |
1863 | if (!this->crypto->update_app_keys(this->crypto, FALSE)) | |
1864 | { | |
1865 | this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); | |
1866 | return NEED_MORE; | |
1867 | } | |
1868 | this->crypto->change_cipher(this->crypto, FALSE); | |
1869 | this->state = STATE_FINISHED_SENT_KEY_SWITCHED; | |
00a6280a | 1870 | return INVALID_STATE; |
7a2b0266 | 1871 | default: |
1872 | return INVALID_STATE; | |
1873 | } | |
1874 | } | |
2b6565c2 | 1875 | } |
7a2b0266 | 1876 | |
2b6565c2 TB |
1877 | /** |
1878 | * Check if we are currently retrying to connect to the server. | |
1879 | */ | |
1880 | static bool retrying(private_tls_peer_t *this) | |
1881 | { | |
1882 | return this->state == STATE_INIT && (this->requested_curve || this->cookie.len); | |
4c0c2283 MW |
1883 | } |
1884 | ||
3ddd164e | 1885 | METHOD(tls_handshake_t, cipherspec_changed, bool, |
4caa3806 | 1886 | private_tls_peer_t *this, bool inbound) |
3ddd164e | 1887 | { |
7a2b0266 | 1888 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
3ddd164e | 1889 | { |
7a2b0266 | 1890 | if (inbound) |
6a5c86b7 | 1891 | { |
7a2b0266 | 1892 | if (this->resume) |
1893 | { | |
1894 | return this->state == STATE_HELLO_RECEIVED; | |
1895 | } | |
1896 | return this->state == STATE_FINISHED_SENT; | |
1897 | } | |
1898 | else | |
1899 | { | |
1900 | if (this->resume) | |
1901 | { | |
1902 | return this->state == STATE_FINISHED_RECEIVED; | |
1903 | } | |
1904 | if (this->peer) | |
1905 | { | |
1906 | return this->state == STATE_VERIFY_SENT; | |
1907 | } | |
1908 | return this->state == STATE_KEY_EXCHANGE_SENT; | |
1909 | ||
6a5c86b7 | 1910 | } |
4caa3806 MW |
1911 | } |
1912 | else | |
1913 | { | |
7a2b0266 | 1914 | if (inbound) |
2b6565c2 TB |
1915 | { /* accept ChangeCipherSpec after ServerHello or HelloRetryRequest */ |
1916 | return this->state == STATE_HELLO_RECEIVED || retrying(this); | |
6a5c86b7 | 1917 | } |
7a2b0266 | 1918 | else |
4caa3806 | 1919 | { |
7a2b0266 | 1920 | return FALSE; |
4caa3806 | 1921 | } |
3ddd164e | 1922 | } |
3ddd164e MW |
1923 | } |
1924 | ||
4caa3806 MW |
1925 | METHOD(tls_handshake_t, change_cipherspec, void, |
1926 | private_tls_peer_t *this, bool inbound) | |
3ddd164e | 1927 | { |
7a2b0266 | 1928 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
1929 | { | |
1930 | this->crypto->change_cipher(this->crypto, inbound); | |
1931 | } | |
1932 | ||
2b6565c2 TB |
1933 | if (retrying(this)) |
1934 | { /* servers might send a ChangeCipherSpec after a HelloRetryRequest, | |
1935 | * which should not cause any state changes */ | |
1936 | return; | |
1937 | } | |
1938 | ||
4caa3806 | 1939 | if (inbound) |
f139b578 | 1940 | { |
f139b578 | 1941 | this->state = STATE_CIPHERSPEC_CHANGED_IN; |
f139b578 | 1942 | } |
4caa3806 MW |
1943 | else |
1944 | { | |
1945 | this->state = STATE_CIPHERSPEC_CHANGED_OUT; | |
1946 | } | |
3ddd164e MW |
1947 | } |
1948 | ||
1327839d AS |
1949 | METHOD(tls_handshake_t, finished, bool, |
1950 | private_tls_peer_t *this) | |
1951 | { | |
7a2b0266 | 1952 | if (this->tls->get_version_max(this->tls) < TLS_1_3) |
6a5c86b7 | 1953 | { |
7a2b0266 | 1954 | if (this->resume) |
1955 | { | |
ba3c90de | 1956 | return this->state == STATE_FINISHED_SENT; |
7a2b0266 | 1957 | } |
7a2b0266 | 1958 | return this->state == STATE_FINISHED_RECEIVED; |
1959 | } | |
1960 | else | |
1961 | { | |
1962 | return this->state == STATE_FINISHED_SENT_KEY_SWITCHED; | |
6a5c86b7 | 1963 | } |
1327839d AS |
1964 | } |
1965 | ||
2de481e3 MW |
1966 | METHOD(tls_handshake_t, get_peer_id, identification_t*, |
1967 | private_tls_peer_t *this) | |
1968 | { | |
1969 | return this->peer; | |
1970 | } | |
1971 | ||
1972 | METHOD(tls_handshake_t, get_server_id, identification_t*, | |
1973 | private_tls_peer_t *this) | |
1974 | { | |
1975 | return this->server; | |
1976 | } | |
1977 | ||
666c5523 MW |
1978 | METHOD(tls_handshake_t, get_auth, auth_cfg_t*, |
1979 | private_tls_peer_t *this) | |
1980 | { | |
1981 | return this->server_auth; | |
1982 | } | |
1983 | ||
4c0c2283 MW |
1984 | METHOD(tls_handshake_t, destroy, void, |
1985 | private_tls_peer_t *this) | |
1986 | { | |
3ddd164e | 1987 | DESTROY_IF(this->private); |
da3f4a9f | 1988 | DESTROY_IF(this->dh); |
2de481e3 MW |
1989 | DESTROY_IF(this->peer); |
1990 | this->server->destroy(this->server); | |
3ddd164e MW |
1991 | this->peer_auth->destroy(this->peer_auth); |
1992 | this->server_auth->destroy(this->server_auth); | |
dbb7c030 MW |
1993 | free(this->hashsig.ptr); |
1994 | free(this->cert_types.ptr); | |
6a5c86b7 | 1995 | free(this->session.ptr); |
2b6565c2 | 1996 | free(this->cookie.ptr); |
4c0c2283 MW |
1997 | free(this); |
1998 | } | |
1999 | ||
2000 | /** | |
2001 | * See header | |
2002 | */ | |
e6f3ef13 | 2003 | tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert, |
3ddd164e | 2004 | identification_t *peer, identification_t *server) |
4c0c2283 MW |
2005 | { |
2006 | private_tls_peer_t *this; | |
2007 | ||
2008 | INIT(this, | |
ba31fe1f MW |
2009 | .public = { |
2010 | .handshake = { | |
2011 | .process = _process, | |
2012 | .build = _build, | |
2013 | .cipherspec_changed = _cipherspec_changed, | |
2014 | .change_cipherspec = _change_cipherspec, | |
2015 | .finished = _finished, | |
2de481e3 MW |
2016 | .get_peer_id = _get_peer_id, |
2017 | .get_server_id = _get_server_id, | |
666c5523 | 2018 | .get_auth = _get_auth, |
ba31fe1f MW |
2019 | .destroy = _destroy, |
2020 | }, | |
4c0c2283 | 2021 | }, |
698674c7 | 2022 | .state = STATE_INIT, |
3e962b08 | 2023 | .tls = tls, |
536dbc00 | 2024 | .crypto = crypto, |
e6f3ef13 | 2025 | .alert = alert, |
2de481e3 MW |
2026 | .peer = peer ? peer->clone(peer) : NULL, |
2027 | .server = server->clone(server), | |
3ddd164e MW |
2028 | .peer_auth = auth_cfg_create(), |
2029 | .server_auth = auth_cfg_create(), | |
4c0c2283 MW |
2030 | ); |
2031 | ||
2032 | return &this->public; | |
2033 | } |