2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
22 typedef struct private_tls_peer_t private_tls_peer_t
;
29 STATE_KEY_EXCHANGE_SENT
,
31 STATE_CIPHERSPEC_CHANGED_OUT
,
33 STATE_CIPHERSPEC_CHANGED_IN
,
38 * Private data of an tls_peer_t object.
40 struct private_tls_peer_t
{
43 * Public tls_peer_t interface.
60 identification_t
*peer
;
65 identification_t
*server
;
73 * Hello random data selected by client
75 char client_random
[32];
78 * Hello random data selected by server
80 char server_random
[32];
83 * Auth helper for peer authentication
85 auth_cfg_t
*peer_auth
;
88 * Auth helper for server authentication
90 auth_cfg_t
*server_auth
;
95 private_key_t
*private;
99 * Process a server hello message
101 static status_t
process_server_hello(private_tls_peer_t
*this,
102 tls_reader_t
*reader
)
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
;
109 this->crypto
->append_handshake(this->crypto
,
110 TLS_SERVER_HELLO
, reader
->peek(reader
));
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
)))
119 DBG1(DBG_IKE
, "received invalid ServerHello");
123 memcpy(this->server_random
, random
.ptr
, sizeof(this->server_random
));
125 if (version
< this->tls
->get_version(this->tls
))
127 this->tls
->set_version(this->tls
, version
);
130 if (!this->crypto
->select_cipher_suite(this->crypto
, &suite
, 1))
132 DBG1(DBG_IKE
, "received cipher suite inacceptable");
139 * Process a Certificate message
141 static status_t
process_certificate(private_tls_peer_t
*this,
142 tls_reader_t
*reader
)
149 this->crypto
->append_handshake(this->crypto
,
150 TLS_CERTIFICATE
, reader
->peek(reader
));
152 if (!reader
->read_data24(reader
, &data
))
156 certs
= tls_reader_create(data
);
157 while (certs
->remaining(certs
))
159 if (!certs
->read_data24(certs
, &data
))
161 certs
->destroy(certs
);
164 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
165 BUILD_BLOB_ASN1_DER
, data
, BUILD_END
);
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
));
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
);
186 DBG1(DBG_IKE
, "parsing TLS certificate failed, skipped");
189 certs
->destroy(certs
);
194 * Process a Certificate message
196 static status_t
process_certreq(private_tls_peer_t
*this, tls_reader_t
*reader
)
198 chunk_t types
, hashsig
, data
;
199 tls_reader_t
*authorities
;
200 identification_t
*id
;
203 this->crypto
->append_handshake(this->crypto
,
204 TLS_CERTIFICATE_REQUEST
, reader
->peek(reader
));
206 if (!reader
->read_data8(reader
, &types
))
210 if (this->tls
->get_version(this->tls
) >= TLS_1_2
)
212 if (!reader
->read_data16(reader
, &hashsig
))
216 /* TODO: store supported hashsig algorithms */
218 if (!reader
->read_data16(reader
, &data
))
222 authorities
= tls_reader_create(data
);
223 while (authorities
->remaining(authorities
))
225 if (!authorities
->read_data16(authorities
, &data
))
227 authorities
->destroy(authorities
);
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
);
235 DBG1(DBG_IKE
, "received cert request for '%Y", id
);
236 this->peer_auth
->add(this->peer_auth
, AUTH_RULE_CA_CERT
, cert
);
240 DBG1(DBG_IKE
, "received cert request for unknown CA '%Y'", id
);
244 authorities
->destroy(authorities
);
249 * Process Hello Done message
251 static status_t
process_hello_done(private_tls_peer_t
*this,
252 tls_reader_t
*reader
)
254 this->crypto
->append_handshake(this->crypto
,
255 TLS_SERVER_HELLO_DONE
, reader
->peek(reader
));
256 this->state
= STATE_HELLO_DONE
;
261 * Process finished message
263 static status_t
process_finished(private_tls_peer_t
*this, tls_reader_t
*reader
)
268 if (!reader
->read_data(reader
, sizeof(buf
), &received
))
270 DBG1(DBG_IKE
, "received server finished too short");
273 if (!this->crypto
->calculate_finished(this->crypto
, "server finished", buf
))
275 DBG1(DBG_IKE
, "calculating server finished failed");
278 if (!chunk_equals(received
, chunk_from_thing(buf
)))
280 DBG1(DBG_IKE
, "received server finished invalid");
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
));
290 METHOD(tls_handshake_t
, process
, status_t
,
291 private_tls_peer_t
*this, tls_handshake_type_t type
, tls_reader_t
*reader
)
295 case STATE_HELLO_SENT
:
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
);
310 case STATE_CIPHERSPEC_CHANGED_IN
:
314 return process_finished(this, reader
);
322 DBG1(DBG_IKE
, "received TLS handshake message %N, ignored",
323 tls_handshake_type_names
, type
);
328 * Send a client hello
330 static status_t
send_hello(private_tls_peer_t
*this,
331 tls_handshake_type_t
*type
, tls_writer_t
*writer
)
333 tls_cipher_suite_t
*suite
;
337 htoun32(&this->client_random
, time(NULL
));
338 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
343 rng
->get_bytes(rng
, sizeof(this->client_random
) - 4, this->client_random
+ 4);
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
);
351 count
= this->crypto
->get_cipher_suites(this->crypto
, &suite
);
352 writer
->write_uint16(writer
, count
* 2);
353 for (i
= 0; i
< count
; i
++)
355 writer
->write_uint16(writer
, suite
[i
]);
357 /* NULL compression only */
358 writer
->write_uint8(writer
, 1);
359 writer
->write_uint8(writer
, 0);
361 *type
= TLS_CLIENT_HELLO
;
362 this->state
= STATE_HELLO_SENT
;
363 this->crypto
->append_handshake(this->crypto
, *type
, writer
->get_buf(writer
));
370 static status_t
send_certificate(private_tls_peer_t
*this,
371 tls_handshake_type_t
*type
, tls_writer_t
*writer
)
373 enumerator_t
*enumerator
;
379 this->private = charon
->credentials
->get_private(charon
->credentials
,
380 KEY_ANY
, this->peer
, this->peer_auth
);
383 DBG1(DBG_IKE
, "no TLS peer certificate found for '%Y'", this->peer
);
387 /* generate certificate payload */
388 certs
= tls_writer_create(256);
389 cert
= this->peer_auth
->get(this->peer_auth
, AUTH_RULE_SUBJECT_CERT
);
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
);
398 enumerator
= this->peer_auth
->create_enumerator(this->peer_auth
);
399 while (enumerator
->enumerate(enumerator
, &rule
, &cert
))
401 if (rule
== AUTH_RULE_IM_CERT
)
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
);
410 enumerator
->destroy(enumerator
);
412 writer
->write_data24(writer
, certs
->get_buf(certs
));
413 certs
->destroy(certs
);
415 *type
= TLS_CERTIFICATE
;
416 this->state
= STATE_CERT_SENT
;
417 this->crypto
->append_handshake(this->crypto
, *type
, writer
->get_buf(writer
));
422 * Send client key exchange
424 static status_t
send_key_exchange(private_tls_peer_t
*this,
425 tls_handshake_type_t
*type
, tls_writer_t
*writer
)
427 public_key_t
*public = NULL
, *current
;
428 enumerator_t
*enumerator
;
434 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
437 DBG1(DBG_IKE
, "no suitable RNG found for TLS premaster secret");
440 rng
->get_bytes(rng
, sizeof(premaster
) - 2, premaster
+ 2);
442 htoun16(premaster
, TLS_1_2
);
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
));
448 enumerator
= charon
->credentials
->create_public_enumerator(
449 charon
->credentials
, KEY_ANY
, this->server
, this->server_auth
);
450 while (enumerator
->enumerate(enumerator
, ¤t
, &auth
))
452 public = current
->get_ref(current
);
455 enumerator
->destroy(enumerator
);
459 DBG1(DBG_IKE
, "no TLS public key found for server '%Y'", this->server
);
462 if (!public->encrypt(public, chunk_from_thing(premaster
), &encrypted
))
464 public->destroy(public);
465 DBG1(DBG_IKE
, "encrypting TLS premaster secret failed");
468 public->destroy(public);
470 writer
->write_data16(writer
, encrypted
);
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
));
480 * Send certificate verify
482 static status_t
send_certificate_verify(private_tls_peer_t
*this,
483 tls_handshake_type_t
*type
, tls_writer_t
*writer
)
487 if (!this->private ||
488 !this->crypto
->sign_handshake(this->crypto
, this->private, &signature
))
490 DBG1(DBG_IKE
, "creating TLS Certificate Verify signature failed");
493 writer
->write_data(writer
, signature
);
496 *type
= TLS_CERTIFICATE_VERIFY
;
497 this->state
= STATE_VERIFY_SENT
;
498 this->crypto
->append_handshake(this->crypto
, *type
, writer
->get_buf(writer
));
505 static status_t
send_finished(private_tls_peer_t
*this,
506 tls_handshake_type_t
*type
, tls_writer_t
*writer
)
510 if (!this->crypto
->calculate_finished(this->crypto
, "client finished", buf
))
512 DBG1(DBG_IKE
, "calculating client finished data failed");
516 writer
->write_data(writer
, chunk_from_thing(buf
));
518 *type
= TLS_FINISHED
;
519 this->state
= STATE_FINISHED_SENT
;
520 this->crypto
->append_handshake(this->crypto
, *type
, writer
->get_buf(writer
));
524 METHOD(tls_handshake_t
, build
, status_t
,
525 private_tls_peer_t
*this, tls_handshake_type_t
*type
, tls_writer_t
*writer
)
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
);
540 return INVALID_STATE
;
542 return INVALID_STATE
;
546 METHOD(tls_handshake_t
, cipherspec_changed
, bool,
547 private_tls_peer_t
*this)
549 if (this->state
== STATE_VERIFY_SENT
)
551 this->crypto
->change_cipher(this->crypto
, FALSE
);
552 this->state
= STATE_CIPHERSPEC_CHANGED_OUT
;
558 METHOD(tls_handshake_t
, change_cipherspec
, bool,
559 private_tls_peer_t
*this)
561 if (this->state
== STATE_FINISHED_SENT
)
563 this->crypto
->change_cipher(this->crypto
, TRUE
);
564 this->state
= STATE_CIPHERSPEC_CHANGED_IN
;
570 METHOD(tls_handshake_t
, destroy
, void,
571 private_tls_peer_t
*this)
573 DESTROY_IF(this->private);
574 this->peer_auth
->destroy(this->peer_auth
);
575 this->server_auth
->destroy(this->server_auth
);
582 tls_peer_t
*tls_peer_create(tls_t
*tls
, tls_crypto_t
*crypto
,
583 identification_t
*peer
, identification_t
*server
)
585 private_tls_peer_t
*this;
588 .public.handshake
= {
591 .cipherspec_changed
= _cipherspec_changed
,
592 .change_cipherspec
= _change_cipherspec
,
600 .peer_auth
= auth_cfg_create(),
601 .server_auth
= auth_cfg_create(),
604 return &this->public;