summaryrefslogtreecommitdiff
path: root/src/libtls/tls_peer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libtls/tls_peer.c')
-rw-r--r--src/libtls/tls_peer.c169
1 files changed, 109 insertions, 60 deletions
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index 621f1729d..6091702cf 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -36,7 +36,7 @@ typedef enum {
STATE_CIPHERSPEC_CHANGED_OUT,
STATE_FINISHED_SENT,
STATE_CIPHERSPEC_CHANGED_IN,
- STATE_COMPLETE,
+ STATE_FINISHED_RECEIVED,
} peer_state_t;
/**
@@ -110,6 +110,16 @@ struct private_tls_peer_t {
diffie_hellman_t *dh;
/**
+ * Resuming a session?
+ */
+ bool resume;
+
+ /**
+ * TLS session identifier
+ */
+ chunk_t session;
+
+ /**
* List of server-supported hashsig algorithms
*/
chunk_t hashsig;
@@ -124,12 +134,12 @@ struct private_tls_peer_t {
* Process a server hello message
*/
static status_t process_server_hello(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
u_int8_t compression;
u_int16_t version, cipher;
chunk_t random, session, ext = chunk_empty;
- tls_cipher_suite_t suite;
+ tls_cipher_suite_t suite = 0;
this->crypto->append_handshake(this->crypto,
TLS_SERVER_HELLO, reader->peek(reader));
@@ -155,16 +165,34 @@ static status_t process_server_hello(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
return NEED_MORE;
}
- suite = cipher;
- if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+
+ if (chunk_equals(this->session, session))
{
- DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
- tls_cipher_suite_names, suite);
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
+ suite = this->crypto->resume_session(this->crypto, session, this->server,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
+ if (suite)
+ {
+ DBG1(DBG_TLS, "resumed %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ this->resume = TRUE;
+ }
+ }
+ if (!suite)
+ {
+ suite = cipher;
+ if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+ {
+ DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
+ tls_cipher_suite_names, suite);
+ this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
+ return NEED_MORE;
+ }
+ DBG1(DBG_TLS, "negotiated %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ free(this->session.ptr);
+ this->session = chunk_clone(session);
}
- DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
- tls_version_names, version, tls_cipher_suite_names, suite);
this->state = STATE_HELLO_RECEIVED;
return NEED_MORE;
}
@@ -209,10 +237,10 @@ static bool check_certificate(private_tls_peer_t *this, certificate_t *cert)
* Process a Certificate message
*/
static status_t process_certificate(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
certificate_t *cert;
- tls_reader_t *certs;
+ bio_reader_t *certs;
chunk_t data;
bool first = TRUE;
@@ -225,7 +253,7 @@ static status_t process_certificate(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- certs = tls_reader_create(data);
+ certs = bio_reader_create(data);
while (certs->remaining(certs))
{
if (!certs->read_data24(certs, &data))
@@ -302,7 +330,7 @@ static public_key_t *find_public_key(private_tls_peer_t *this)
* Process a Key Exchange message using MODP Diffie Hellman
*/
static status_t process_modp_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
chunk_t prime, generator, pub, chunk;
public_key_t *public;
@@ -379,7 +407,7 @@ static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
* Process a Key Exchange message using EC Diffie Hellman
*/
static status_t process_ec_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
diffie_hellman_group_t group;
public_key_t *public;
@@ -466,7 +494,7 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
* Process a Server Key Exchange
*/
static status_t process_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
diffie_hellman_group_t group;
@@ -491,10 +519,10 @@ static status_t process_key_exchange(private_tls_peer_t *this,
/**
* Process a Certificate Request message
*/
-static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
+static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader)
{
chunk_t types, hashsig, data;
- tls_reader_t *authorities;
+ bio_reader_t *authorities;
identification_t *id;
certificate_t *cert;
@@ -529,7 +557,7 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- authorities = tls_reader_create(data);
+ authorities = bio_reader_create(data);
while (authorities->remaining(authorities))
{
if (!authorities->read_data16(authorities, &data))
@@ -565,7 +593,7 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
* Process Hello Done message
*/
static status_t process_hello_done(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
this->crypto->append_handshake(this->crypto,
TLS_SERVER_HELLO_DONE, reader->peek(reader));
@@ -576,7 +604,7 @@ static status_t process_hello_done(private_tls_peer_t *this,
/**
* Process finished message
*/
-static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
+static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
{
chunk_t received;
char buf[12];
@@ -599,15 +627,14 @@ static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
return NEED_MORE;
}
- this->state = STATE_COMPLETE;
- this->crypto->derive_eap_msk(this->crypto,
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
+ this->state = STATE_FINISHED_RECEIVED;
+ this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
+
return NEED_MORE;
}
METHOD(tls_handshake_t, process, status_t,
- private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
+ private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
{
tls_handshake_type_t expected;
@@ -670,10 +697,10 @@ METHOD(tls_handshake_t, process, status_t,
* Send a client hello
*/
static status_t send_client_hello(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
tls_cipher_suite_t *suites;
- tls_writer_t *extensions, *curves = NULL;
+ bio_writer_t *extensions, *curves = NULL;
tls_version_t version;
tls_named_curve_t curve;
enumerator_t *enumerator;
@@ -696,8 +723,9 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint16(writer, version);
writer->write_data(writer, chunk_from_thing(this->client_random));
- /* session identifier => none */
- writer->write_data8(writer, chunk_empty);
+ /* session identifier */
+ this->session = this->crypto->get_session(this->crypto, this->server);
+ writer->write_data8(writer, this->session);
/* add TLS cipher suites */
count = this->crypto->get_cipher_suites(this->crypto, &suites);
@@ -711,7 +739,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint8(writer, 1);
writer->write_uint8(writer, 0);
- extensions = tls_writer_create(32);
+ extensions = bio_writer_create(32);
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
this->crypto->get_signature_algorithms(this->crypto, extensions);
@@ -723,7 +751,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
if (!curves)
{
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
- curves = tls_writer_create(16);
+ curves = bio_writer_create(16);
}
curves->write_uint16(curves, curve);
}
@@ -741,11 +769,11 @@ static status_t send_client_hello(private_tls_peer_t *this,
}
if (this->server->get_type(this->server) == ID_FQDN)
{
- tls_writer_t *names;
+ bio_writer_t *names;
DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
- names = tls_writer_create(8);
+ names = bio_writer_create(8);
names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
names->write_data16(names, this->server->get_encoding(this->server));
names->wrap16(names);
@@ -769,7 +797,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
static private_key_t *find_private_key(private_tls_peer_t *this)
{
private_key_t *key = NULL;
- tls_reader_t *reader;
+ bio_reader_t *reader;
key_type_t type;
u_int8_t cert;
@@ -777,7 +805,7 @@ static private_key_t *find_private_key(private_tls_peer_t *this)
{
return NULL;
}
- reader = tls_reader_create(this->cert_types);
+ reader = bio_reader_create(this->cert_types);
while (reader->remaining(reader) && reader->read_uint8(reader, &cert))
{
switch (cert)
@@ -806,12 +834,12 @@ static private_key_t *find_private_key(private_tls_peer_t *this)
* Send Certificate
*/
static status_t send_certificate(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
enumerator_t *enumerator;
certificate_t *cert;
auth_rule_t rule;
- tls_writer_t *certs;
+ bio_writer_t *certs;
chunk_t data;
this->private = find_private_key(this);
@@ -823,7 +851,7 @@ static status_t send_certificate(private_tls_peer_t *this,
}
/* generate certificate payload */
- certs = tls_writer_create(256);
+ certs = bio_writer_create(256);
if (this->peer)
{
cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
@@ -867,7 +895,7 @@ static status_t send_certificate(private_tls_peer_t *this,
* Send client key exchange, using premaster encryption
*/
static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
public_key_t *public;
rng_t *rng;
@@ -886,6 +914,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
htoun16(premaster, TLS_1_2);
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
@@ -919,7 +948,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
* Send client key exchange, using DHE exchange
*/
static status_t send_key_exchange_dhe(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
chunk_t premaster, pub;
@@ -930,6 +959,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
return NEED_MORE;
}
this->crypto->derive_secrets(this->crypto, premaster,
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
chunk_clear(&premaster);
@@ -957,7 +987,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
* Send client key exchange, depending on suite
*/
static status_t send_key_exchange(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
if (this->dh)
{
@@ -970,7 +1000,7 @@ static status_t send_key_exchange(private_tls_peer_t *this,
* Send certificate verify
*/
static status_t send_certificate_verify(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
if (!this->private ||
!this->crypto->sign_handshake(this->crypto, this->private,
@@ -991,7 +1021,7 @@ static status_t send_certificate_verify(private_tls_peer_t *this,
* Send Finished
*/
static status_t send_finished(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
char buf[12];
@@ -1011,7 +1041,7 @@ static status_t send_finished(private_tls_peer_t *this,
}
METHOD(tls_handshake_t, build, status_t,
- private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
+ private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
{
switch (this->state)
{
@@ -1042,34 +1072,52 @@ METHOD(tls_handshake_t, build, status_t,
}
METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_peer_t *this)
+ private_tls_peer_t *this, bool inbound)
{
- if ((this->peer && this->state == STATE_VERIFY_SENT) ||
- (!this->peer && this->state == STATE_KEY_EXCHANGE_SENT))
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
+ if (this->resume)
+ {
+ return this->state == STATE_HELLO_RECEIVED;
+ }
+ return this->state == STATE_FINISHED_SENT;
+ }
+ else
+ {
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_RECEIVED;
+ }
+ if (this->peer)
+ {
+ return this->state == STATE_VERIFY_SENT;
+ }
+ return this->state == STATE_KEY_EXCHANGE_SENT;
}
- return FALSE;
}
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_peer_t *this)
+METHOD(tls_handshake_t, change_cipherspec, void,
+ private_tls_peer_t *this, bool inbound)
{
- if (this->state == STATE_FINISHED_SENT)
+ this->crypto->change_cipher(this->crypto, inbound);
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, TRUE);
this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
}
- return FALSE;
+ else
+ {
+ this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+ }
}
METHOD(tls_handshake_t, finished, bool,
private_tls_peer_t *this)
{
- return this->state == STATE_COMPLETE;
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_SENT;
+ }
+ return this->state == STATE_FINISHED_RECEIVED;
}
METHOD(tls_handshake_t, destroy, void,
@@ -1081,6 +1129,7 @@ METHOD(tls_handshake_t, destroy, void,
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->cert_types.ptr);
+ free(this->session.ptr);
free(this);
}