Refactored common used operations into TLS crypto helper
[strongswan.git] / src / charon / plugins / eap_tls / tls / tls_peer.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tls_peer.h"
17
18 #include <daemon.h>
19
20 #include <time.h>
21
22 typedef struct private_tls_peer_t private_tls_peer_t;
23
24 typedef enum {
25 STATE_INIT,
26 STATE_HELLO_SENT,
27 STATE_HELLO_DONE,
28 STATE_CERT_SENT,
29 STATE_KEY_EXCHANGE_SENT,
30 STATE_VERIFY_SENT,
31 STATE_CIPHERSPEC_CHANGED_OUT,
32 STATE_FINISHED_SENT,
33 STATE_CIPHERSPEC_CHANGED_IN,
34 STATE_COMPLETE,
35 } peer_state_t;
36
37 /**
38 * Private data of an tls_peer_t object.
39 */
40 struct private_tls_peer_t {
41
42 /**
43 * Public tls_peer_t interface.
44 */
45 tls_peer_t public;
46
47 /**
48 * TLS stack
49 */
50 tls_t *tls;
51
52 /**
53 * TLS crypto context
54 */
55 tls_crypto_t *crypto;
56
57 /**
58 * Peer identity
59 */
60 identification_t *peer;
61
62 /**
63 * Server identity
64 */
65 identification_t *server;
66
67 /**
68 * State we are in
69 */
70 peer_state_t state;
71
72 /**
73 * Hello random data selected by client
74 */
75 char client_random[32];
76
77 /**
78 * Hello random data selected by server
79 */
80 char server_random[32];
81
82 /**
83 * Auth helper for peer authentication
84 */
85 auth_cfg_t *peer_auth;
86
87 /**
88 * Auth helper for server authentication
89 */
90 auth_cfg_t *server_auth;
91
92 /**
93 * Peer private key
94 */
95 private_key_t *private;
96 };
97
98 /**
99 * Process a server hello message
100 */
101 static status_t process_server_hello(private_tls_peer_t *this,
102 tls_reader_t *reader)
103 {
104 u_int8_t compression;
105 u_int16_t version, cipher;
106 chunk_t random, session, ext = chunk_empty;
107 tls_cipher_suite_t suite;
108
109 this->crypto->append_handshake(this->crypto,
110 TLS_SERVER_HELLO, reader->peek(reader));
111
112 if (!reader->read_uint16(reader, &version) ||
113 !reader->read_data(reader, sizeof(this->server_random), &random) ||
114 !reader->read_data8(reader, &session) ||
115 !reader->read_uint16(reader, &cipher) ||
116 !reader->read_uint8(reader, &compression) ||
117 (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
118 {
119 DBG1(DBG_IKE, "received invalid ServerHello");
120 return FAILED;
121 }
122
123 memcpy(this->server_random, random.ptr, sizeof(this->server_random));
124
125 if (version < this->tls->get_version(this->tls))
126 {
127 this->tls->set_version(this->tls, version);
128 }
129 suite = cipher;
130 if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1))
131 {
132 DBG1(DBG_IKE, "received cipher suite inacceptable");
133 return FAILED;
134 }
135 return NEED_MORE;
136 }
137
138 /**
139 * Process a Certificate message
140 */
141 static status_t process_certificate(private_tls_peer_t *this,
142 tls_reader_t *reader)
143 {
144 certificate_t *cert;
145 tls_reader_t *certs;
146 chunk_t data;
147 bool first = TRUE;
148
149 this->crypto->append_handshake(this->crypto,
150 TLS_CERTIFICATE, reader->peek(reader));
151
152 if (!reader->read_data24(reader, &data))
153 {
154 return FAILED;
155 }
156 certs = tls_reader_create(data);
157 while (certs->remaining(certs))
158 {
159 if (!certs->read_data24(certs, &data))
160 {
161 certs->destroy(certs);
162 return FAILED;
163 }
164 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
165 BUILD_BLOB_ASN1_DER, data, BUILD_END);
166 if (cert)
167 {
168 if (first)
169 {
170 this->server_auth->add(this->server_auth,
171 AUTH_RULE_SUBJECT_CERT, cert);
172 DBG1(DBG_IKE, "received TLS server certificate '%Y'",
173 cert->get_subject(cert));
174 first = FALSE;
175 }
176 else
177 {
178 DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
179 cert->get_subject(cert));
180 this->server_auth->add(this->server_auth,
181 AUTH_RULE_IM_CERT, cert);
182 }
183 }
184 else
185 {
186 DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
187 }
188 }
189 certs->destroy(certs);
190 return NEED_MORE;
191 }
192
193 /**
194 * Process a Certificate message
195 */
196 static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
197 {
198 chunk_t types, hashsig, data;
199 tls_reader_t *authorities;
200 identification_t *id;
201 certificate_t *cert;
202
203 this->crypto->append_handshake(this->crypto,
204 TLS_CERTIFICATE_REQUEST, reader->peek(reader));
205
206 if (!reader->read_data8(reader, &types))
207 {
208 return FAILED;
209 }
210 if (this->tls->get_version(this->tls) >= TLS_1_2)
211 {
212 if (!reader->read_data16(reader, &hashsig))
213 {
214 return FAILED;
215 }
216 /* TODO: store supported hashsig algorithms */
217 }
218 if (!reader->read_data16(reader, &data))
219 {
220 return FAILED;
221 }
222 authorities = tls_reader_create(data);
223 while (authorities->remaining(authorities))
224 {
225 if (!authorities->read_data16(authorities, &data))
226 {
227 authorities->destroy(authorities);
228 return FAILED;
229 }
230 id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
231 cert = charon->credentials->get_cert(charon->credentials,
232 CERT_X509, KEY_ANY, id, TRUE);
233 if (cert)
234 {
235 DBG1(DBG_IKE, "received cert request for '%Y", id);
236 this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
237 }
238 else
239 {
240 DBG1(DBG_IKE, "received cert request for unknown CA '%Y'", id);
241 }
242 id->destroy(id);
243 }
244 authorities->destroy(authorities);
245 return NEED_MORE;
246 }
247
248 /**
249 * Process Hello Done message
250 */
251 static status_t process_hello_done(private_tls_peer_t *this,
252 tls_reader_t *reader)
253 {
254 this->crypto->append_handshake(this->crypto,
255 TLS_SERVER_HELLO_DONE, reader->peek(reader));
256 this->state = STATE_HELLO_DONE;
257 return NEED_MORE;
258 }
259
260 /**
261 * Process finished message
262 */
263 static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
264 {
265 chunk_t received;
266 char buf[12];
267
268 if (!reader->read_data(reader, sizeof(buf), &received))
269 {
270 DBG1(DBG_IKE, "received server finished too short");
271 return FAILED;
272 }
273 if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
274 {
275 DBG1(DBG_IKE, "calculating server finished failed");
276 return FAILED;
277 }
278 if (!chunk_equals(received, chunk_from_thing(buf)))
279 {
280 DBG1(DBG_IKE, "received server finished invalid");
281 return FAILED;
282 }
283 this->state = STATE_COMPLETE;
284 this->crypto->derive_eap_msk(this->crypto,
285 chunk_from_thing(this->client_random),
286 chunk_from_thing(this->server_random));
287 return NEED_MORE;
288 }
289
290 METHOD(tls_handshake_t, process, status_t,
291 private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
292 {
293 switch (this->state)
294 {
295 case STATE_HELLO_SENT:
296 switch (type)
297 {
298 case TLS_SERVER_HELLO:
299 return process_server_hello(this, reader);
300 case TLS_CERTIFICATE:
301 return process_certificate(this, reader);
302 case TLS_CERTIFICATE_REQUEST:
303 return process_certreq(this, reader);
304 case TLS_SERVER_HELLO_DONE:
305 return process_hello_done(this, reader);
306 default:
307 break;
308 }
309 break;
310 case STATE_CIPHERSPEC_CHANGED_IN:
311 switch (type)
312 {
313 case TLS_FINISHED:
314 return process_finished(this, reader);
315 default:
316 break;
317 }
318 break;
319 default:
320 break;
321 }
322 DBG1(DBG_IKE, "received TLS handshake message %N, ignored",
323 tls_handshake_type_names, type);
324 return NEED_MORE;
325 }
326
327 /**
328 * Send a client hello
329 */
330 static status_t send_hello(private_tls_peer_t *this,
331 tls_handshake_type_t *type, tls_writer_t *writer)
332 {
333 tls_cipher_suite_t *suite;
334 int count, i;
335 rng_t *rng;
336
337 htoun32(&this->client_random, time(NULL));
338 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
339 if (!rng)
340 {
341 return FAILED;
342 }
343 rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4);
344 rng->destroy(rng);
345
346 writer->write_uint16(writer, this->tls->get_version(this->tls));
347 writer->write_data(writer, chunk_from_thing(this->client_random));
348 /* session identifier => none */
349 writer->write_data8(writer, chunk_empty);
350
351 count = this->crypto->get_cipher_suites(this->crypto, &suite);
352 writer->write_uint16(writer, count * 2);
353 for (i = 0; i < count; i++)
354 {
355 writer->write_uint16(writer, suite[i]);
356 }
357 /* NULL compression only */
358 writer->write_uint8(writer, 1);
359 writer->write_uint8(writer, 0);
360
361 *type = TLS_CLIENT_HELLO;
362 this->state = STATE_HELLO_SENT;
363 this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
364 return NEED_MORE;
365 }
366
367 /**
368 * Send Certificate
369 */
370 static status_t send_certificate(private_tls_peer_t *this,
371 tls_handshake_type_t *type, tls_writer_t *writer)
372 {
373 enumerator_t *enumerator;
374 certificate_t *cert;
375 auth_rule_t rule;
376 tls_writer_t *certs;
377 chunk_t data;
378
379 this->private = charon->credentials->get_private(charon->credentials,
380 KEY_ANY, this->peer, this->peer_auth);
381 if (!this->private)
382 {
383 DBG1(DBG_IKE, "no TLS peer certificate found for '%Y'", this->peer);
384 return FAILED;
385 }
386
387 /* generate certificate payload */
388 certs = tls_writer_create(256);
389 cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
390 if (cert)
391 {
392 DBG1(DBG_IKE, "sending TLS peer certificate '%Y'",
393 cert->get_subject(cert));
394 data = cert->get_encoding(cert);
395 certs->write_data24(certs, data);
396 free(data.ptr);
397 }
398 enumerator = this->peer_auth->create_enumerator(this->peer_auth);
399 while (enumerator->enumerate(enumerator, &rule, &cert))
400 {
401 if (rule == AUTH_RULE_IM_CERT)
402 {
403 DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
404 cert->get_subject(cert));
405 data = cert->get_encoding(cert);
406 certs->write_data24(certs, data);
407 free(data.ptr);
408 }
409 }
410 enumerator->destroy(enumerator);
411
412 writer->write_data24(writer, certs->get_buf(certs));
413 certs->destroy(certs);
414
415 *type = TLS_CERTIFICATE;
416 this->state = STATE_CERT_SENT;
417 this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
418 return NEED_MORE;
419 }
420
421 /**
422 * Send client key exchange
423 */
424 static status_t send_key_exchange(private_tls_peer_t *this,
425 tls_handshake_type_t *type, tls_writer_t *writer)
426 {
427 public_key_t *public = NULL, *current;
428 enumerator_t *enumerator;
429 auth_cfg_t *auth;
430 rng_t *rng;
431 char premaster[48];
432 chunk_t encrypted;
433
434 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
435 if (!rng)
436 {
437 DBG1(DBG_IKE, "no suitable RNG found for TLS premaster secret");
438 return FAILED;
439 }
440 rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
441 rng->destroy(rng);
442 htoun16(premaster, TLS_1_2);
443
444 this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
445 chunk_from_thing(this->client_random),
446 chunk_from_thing(this->server_random));
447
448 enumerator = charon->credentials->create_public_enumerator(
449 charon->credentials, KEY_ANY, this->server, this->server_auth);
450 while (enumerator->enumerate(enumerator, &current, &auth))
451 {
452 public = current->get_ref(current);
453 break;
454 }
455 enumerator->destroy(enumerator);
456
457 if (!public)
458 {
459 DBG1(DBG_IKE, "no TLS public key found for server '%Y'", this->server);
460 return FAILED;
461 }
462 if (!public->encrypt(public, chunk_from_thing(premaster), &encrypted))
463 {
464 public->destroy(public);
465 DBG1(DBG_IKE, "encrypting TLS premaster secret failed");
466 return FAILED;
467 }
468 public->destroy(public);
469
470 writer->write_data16(writer, encrypted);
471 free(encrypted.ptr);
472
473 *type = TLS_CLIENT_KEY_EXCHANGE;
474 this->state = STATE_KEY_EXCHANGE_SENT;
475 this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
476 return NEED_MORE;
477 }
478
479 /**
480 * Send certificate verify
481 */
482 static status_t send_certificate_verify(private_tls_peer_t *this,
483 tls_handshake_type_t *type, tls_writer_t *writer)
484 {
485 chunk_t signature;
486
487 if (!this->private ||
488 !this->crypto->sign_handshake(this->crypto, this->private, &signature))
489 {
490 DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
491 return FAILED;
492 }
493 writer->write_data(writer, signature);
494 free(signature.ptr);
495
496 *type = TLS_CERTIFICATE_VERIFY;
497 this->state = STATE_VERIFY_SENT;
498 this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
499 return NEED_MORE;
500 }
501
502 /**
503 * Send Finished
504 */
505 static status_t send_finished(private_tls_peer_t *this,
506 tls_handshake_type_t *type, tls_writer_t *writer)
507 {
508 char buf[12];
509
510 if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
511 {
512 DBG1(DBG_IKE, "calculating client finished data failed");
513 return FAILED;
514 }
515
516 writer->write_data(writer, chunk_from_thing(buf));
517
518 *type = TLS_FINISHED;
519 this->state = STATE_FINISHED_SENT;
520 this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
521 return NEED_MORE;
522 }
523
524 METHOD(tls_handshake_t, build, status_t,
525 private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
526 {
527 switch (this->state)
528 {
529 case STATE_INIT:
530 return send_hello(this, type, writer);
531 case STATE_HELLO_DONE:
532 return send_certificate(this, type, writer);
533 case STATE_CERT_SENT:
534 return send_key_exchange(this, type, writer);
535 case STATE_KEY_EXCHANGE_SENT:
536 return send_certificate_verify(this, type, writer);
537 case STATE_CIPHERSPEC_CHANGED_OUT:
538 return send_finished(this, type, writer);
539 case STATE_COMPLETE:
540 return INVALID_STATE;
541 default:
542 return INVALID_STATE;
543 }
544 }
545
546 METHOD(tls_handshake_t, cipherspec_changed, bool,
547 private_tls_peer_t *this)
548 {
549 if (this->state == STATE_VERIFY_SENT)
550 {
551 this->crypto->change_cipher(this->crypto, FALSE);
552 this->state = STATE_CIPHERSPEC_CHANGED_OUT;
553 return TRUE;
554 }
555 return FALSE;
556 }
557
558 METHOD(tls_handshake_t, change_cipherspec, bool,
559 private_tls_peer_t *this)
560 {
561 if (this->state == STATE_FINISHED_SENT)
562 {
563 this->crypto->change_cipher(this->crypto, TRUE);
564 this->state = STATE_CIPHERSPEC_CHANGED_IN;
565 return TRUE;
566 }
567 return FALSE;
568 }
569
570 METHOD(tls_handshake_t, destroy, void,
571 private_tls_peer_t *this)
572 {
573 DESTROY_IF(this->private);
574 this->peer_auth->destroy(this->peer_auth);
575 this->server_auth->destroy(this->server_auth);
576 free(this);
577 }
578
579 /**
580 * See header
581 */
582 tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
583 identification_t *peer, identification_t *server)
584 {
585 private_tls_peer_t *this;
586
587 INIT(this,
588 .public.handshake = {
589 .process = _process,
590 .build = _build,
591 .cipherspec_changed = _cipherspec_changed,
592 .change_cipherspec = _change_cipherspec,
593 .destroy = _destroy,
594 },
595 .state = STATE_INIT,
596 .tls = tls,
597 .crypto = crypto,
598 .peer = peer,
599 .server = server,
600 .peer_auth = auth_cfg_create(),
601 .server_auth = auth_cfg_create(),
602 );
603
604 return &this->public;
605 }