Implemented TLS session resumption both as client and as server
This commit is contained in:
+2
-2
@@ -437,7 +437,7 @@ METHOD(tls_t, destroy, void,
|
||||
*/
|
||||
tls_t *tls_create(bool is_server, identification_t *server,
|
||||
identification_t *peer, tls_purpose_t purpose,
|
||||
tls_application_t *application)
|
||||
tls_application_t *application, tls_cache_t *cache)
|
||||
{
|
||||
private_tls_t *this;
|
||||
|
||||
@@ -472,7 +472,7 @@ tls_t *tls_create(bool is_server, identification_t *server,
|
||||
.purpose = purpose,
|
||||
);
|
||||
|
||||
this->crypto = tls_crypto_create(&this->public);
|
||||
this->crypto = tls_crypto_create(&this->public, cache);
|
||||
this->alert = tls_alert_create();
|
||||
if (is_server)
|
||||
{
|
||||
|
||||
+3
-1
@@ -35,6 +35,7 @@ typedef struct tls_t tls_t;
|
||||
#include <library.h>
|
||||
|
||||
#include "tls_application.h"
|
||||
#include "tls_cache.h"
|
||||
|
||||
/**
|
||||
* TLS/SSL version numbers
|
||||
@@ -240,10 +241,11 @@ void libtls_init(void);
|
||||
* @param peer peer identity, NULL for no client authentication
|
||||
* @param purpose purpose this TLS stack instance is used for
|
||||
* @param application higher layer application or NULL if none
|
||||
* @param cache session cache to use, or NULL
|
||||
* @return TLS stack
|
||||
*/
|
||||
tls_t *tls_create(bool is_server, identification_t *server,
|
||||
identification_t *peer, tls_purpose_t purpose,
|
||||
tls_application_t *application);
|
||||
tls_application_t *application, tls_cache_t *cache);
|
||||
|
||||
#endif /** TLS_H_ @}*/
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct tls_compression_t tls_compression_t;
|
||||
|
||||
#include "tls.h"
|
||||
#include "tls_alert.h"
|
||||
#include "tls_fragmentation.h"
|
||||
|
||||
typedef struct tls_compression_t tls_compression_t;
|
||||
|
||||
/**
|
||||
* TLS record protocol compression layer.
|
||||
*/
|
||||
|
||||
+81
-23
@@ -369,6 +369,11 @@ struct private_tls_crypto_t {
|
||||
*/
|
||||
tls_t *tls;
|
||||
|
||||
/**
|
||||
* TLS session cache
|
||||
*/
|
||||
tls_cache_t *cache;
|
||||
|
||||
/**
|
||||
* All handshake data concatentated
|
||||
*/
|
||||
@@ -1462,13 +1467,15 @@ METHOD(tls_crypto_t, calculate_finished, bool,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, derive_secrets, void,
|
||||
private_tls_crypto_t *this, chunk_t premaster,
|
||||
chunk_t client_random, chunk_t server_random)
|
||||
/**
|
||||
* Derive master secret from premaster, optionally save session
|
||||
*/
|
||||
static void derive_master(private_tls_crypto_t *this, chunk_t premaster,
|
||||
chunk_t session, identification_t *id,
|
||||
chunk_t client_random, chunk_t server_random)
|
||||
{
|
||||
char master[48];
|
||||
chunk_t seed, block, client_write, server_write;
|
||||
int mks, eks = 0, ivs = 0;
|
||||
chunk_t seed;
|
||||
|
||||
/* derive master secret */
|
||||
seed = chunk_cata("cc", client_random, server_random);
|
||||
@@ -1477,7 +1484,22 @@ METHOD(tls_crypto_t, derive_secrets, void,
|
||||
sizeof(master), master);
|
||||
|
||||
this->prf->set_key(this->prf, chunk_from_thing(master));
|
||||
memset(master, 0, sizeof(master));
|
||||
if (this->cache && session.len)
|
||||
{
|
||||
this->cache->create(this->cache, session, id, chunk_from_thing(master),
|
||||
this->suite);
|
||||
}
|
||||
memwipe(master, sizeof(master));
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand key material from master secret
|
||||
*/
|
||||
static void expand_keys(private_tls_crypto_t *this,
|
||||
chunk_t client_random, chunk_t server_random)
|
||||
{
|
||||
chunk_t seed, block, client_write, server_write;
|
||||
int mks, eks = 0, ivs = 0;
|
||||
|
||||
/* derive key block for key expansion */
|
||||
mks = this->signer_out->get_key_size(this->signer_out);
|
||||
@@ -1546,6 +1568,55 @@ METHOD(tls_crypto_t, derive_secrets, void,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* EAP-MSK */
|
||||
if (this->msk_label)
|
||||
{
|
||||
this->msk = chunk_alloc(64);
|
||||
this->prf->get_bytes(this->prf, this->msk_label, seed,
|
||||
this->msk.len, this->msk.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, derive_secrets, void,
|
||||
private_tls_crypto_t *this, chunk_t premaster, chunk_t session,
|
||||
identification_t *id, chunk_t client_random, chunk_t server_random)
|
||||
{
|
||||
derive_master(this, premaster, session, id, client_random, server_random);
|
||||
expand_keys(this, client_random, server_random);
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t,
|
||||
private_tls_crypto_t *this, chunk_t session, identification_t *id,
|
||||
chunk_t client_random, chunk_t server_random)
|
||||
{
|
||||
chunk_t master;
|
||||
|
||||
if (this->cache && session.len)
|
||||
{
|
||||
this->suite = this->cache->lookup(this->cache, session, id, &master);
|
||||
if (this->suite)
|
||||
{
|
||||
select_cipher_suite(this, &this->suite, 1, KEY_ANY);
|
||||
if (this->suite)
|
||||
{
|
||||
this->prf->set_key(this->prf, master);
|
||||
expand_keys(this, client_random, server_random);
|
||||
}
|
||||
chunk_clear(&master);
|
||||
}
|
||||
}
|
||||
return this->suite;
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, get_session, chunk_t,
|
||||
private_tls_crypto_t *this, identification_t *server)
|
||||
{
|
||||
if (this->cache)
|
||||
{
|
||||
return this->cache->check(this->cache, server);
|
||||
}
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, change_cipher, void,
|
||||
@@ -1566,21 +1637,6 @@ METHOD(tls_crypto_t, change_cipher, void,
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, derive_eap_msk, void,
|
||||
private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
|
||||
{
|
||||
if (this->msk_label)
|
||||
{
|
||||
chunk_t seed;
|
||||
|
||||
seed = chunk_cata("cc", client_random, server_random);
|
||||
free(this->msk.ptr);
|
||||
this->msk = chunk_alloc(64);
|
||||
this->prf->get_bytes(this->prf, this->msk_label, seed,
|
||||
this->msk.len, this->msk.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(tls_crypto_t, get_eap_msk, chunk_t,
|
||||
private_tls_crypto_t *this)
|
||||
{
|
||||
@@ -1606,7 +1662,7 @@ METHOD(tls_crypto_t, destroy, void,
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
tls_crypto_t *tls_crypto_create(tls_t *tls)
|
||||
tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
|
||||
{
|
||||
private_tls_crypto_t *this;
|
||||
enumerator_t *enumerator;
|
||||
@@ -1628,12 +1684,14 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
|
||||
.verify_handshake = _verify_handshake,
|
||||
.calculate_finished = _calculate_finished,
|
||||
.derive_secrets = _derive_secrets,
|
||||
.resume_session = _resume_session,
|
||||
.get_session = _get_session,
|
||||
.change_cipher = _change_cipher,
|
||||
.derive_eap_msk = _derive_eap_msk,
|
||||
.get_eap_msk = _get_eap_msk,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.tls = tls,
|
||||
.cache = cache,
|
||||
);
|
||||
|
||||
enumerator = lib->creds->create_builder_enumerator(lib->creds);
|
||||
|
||||
+30
-10
@@ -511,12 +511,37 @@ struct tls_crypto_t {
|
||||
* Derive the master secret, MAC and encryption keys.
|
||||
*
|
||||
* @param premaster premaster secret
|
||||
* @param session session identifier to cache master secret
|
||||
* @param id identity the session is bound to
|
||||
* @param client_random random data from client hello
|
||||
* @param server_random random data from server hello
|
||||
*/
|
||||
void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster,
|
||||
chunk_t session, identification_t *id,
|
||||
chunk_t client_random, chunk_t server_random);
|
||||
|
||||
/**
|
||||
* Try to resume a TLS session, derive key material.
|
||||
*
|
||||
* @param session session identifier
|
||||
* @param id identity the session is bound to
|
||||
* @param client_random random data from client hello
|
||||
* @param server_random random data from server hello
|
||||
* @param
|
||||
*/
|
||||
tls_cipher_suite_t (*resume_session)(tls_crypto_t *this, chunk_t session,
|
||||
identification_t *id,
|
||||
chunk_t client_random,
|
||||
chunk_t server_random);
|
||||
|
||||
/**
|
||||
* Check if we have a session to resume as a client.
|
||||
*
|
||||
* @param id server identity to get a session for
|
||||
* @return allocated session identifier, or chunk_empty
|
||||
*/
|
||||
chunk_t (*get_session)(tls_crypto_t *this, identification_t *id);
|
||||
|
||||
/**
|
||||
* Change the cipher used at protection layer.
|
||||
*
|
||||
@@ -524,15 +549,6 @@ struct tls_crypto_t {
|
||||
*/
|
||||
void (*change_cipher)(tls_crypto_t *this, bool inbound);
|
||||
|
||||
/**
|
||||
* Derive the EAP-TLS MSK.
|
||||
*
|
||||
* @param client_random random data from client hello
|
||||
* @param server_random random data from server hello
|
||||
*/
|
||||
void (*derive_eap_msk)(tls_crypto_t *this,
|
||||
chunk_t client_random, chunk_t server_random);
|
||||
|
||||
/**
|
||||
* Get the MSK to use in EAP-TLS.
|
||||
*
|
||||
@@ -548,7 +564,11 @@ struct tls_crypto_t {
|
||||
|
||||
/**
|
||||
* Create a tls_crypto instance.
|
||||
*
|
||||
* @param tls TLS stack
|
||||
* @param tls_cache TLS session cache
|
||||
* @return TLS crypto helper
|
||||
*/
|
||||
tls_crypto_t *tls_crypto_create(tls_t *tls);
|
||||
tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache);
|
||||
|
||||
#endif /** TLS_CRYPTO_H_ @}*/
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct tls_fragmentation_t tls_fragmentation_t;
|
||||
|
||||
#include "tls.h"
|
||||
#include "tls_alert.h"
|
||||
#include "tls_handshake.h"
|
||||
|
||||
typedef struct tls_fragmentation_t tls_fragmentation_t;
|
||||
|
||||
/**
|
||||
* TLS record protocol fragmentation layer.
|
||||
*/
|
||||
|
||||
+60
-17
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -109,6 +109,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
|
||||
*/
|
||||
@@ -129,7 +139,7 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
||||
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;
|
||||
}
|
||||
@@ -599,10 +627,9 @@ static status_t process_finished(private_tls_peer_t *this, bio_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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
@@ -1046,10 +1076,18 @@ METHOD(tls_handshake_t, cipherspec_changed, bool,
|
||||
{
|
||||
if (inbound)
|
||||
{
|
||||
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;
|
||||
@@ -1075,7 +1113,11 @@ METHOD(tls_handshake_t, change_cipherspec, void,
|
||||
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,
|
||||
@@ -1087,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct tls_protection_t tls_protection_t;
|
||||
|
||||
#include "tls.h"
|
||||
#include "tls_alert.h"
|
||||
#include "tls_compression.h"
|
||||
|
||||
typedef struct tls_protection_t tls_protection_t;
|
||||
|
||||
/**
|
||||
* TLS record protocol protection layer.
|
||||
*/
|
||||
|
||||
+83
-41
@@ -22,6 +22,10 @@
|
||||
|
||||
typedef struct private_tls_server_t private_tls_server_t;
|
||||
|
||||
/**
|
||||
* Size of a session ID
|
||||
*/
|
||||
#define SESSION_ID_SIZE 16
|
||||
|
||||
typedef enum {
|
||||
STATE_INIT,
|
||||
@@ -120,6 +124,16 @@ struct private_tls_server_t {
|
||||
*/
|
||||
tls_version_t client_version;
|
||||
|
||||
/**
|
||||
* TLS session identifier
|
||||
*/
|
||||
chunk_t session;
|
||||
|
||||
/**
|
||||
* Do we resume a session?
|
||||
*/
|
||||
bool resume;
|
||||
|
||||
/**
|
||||
* Hash and signature algorithms supported by peer
|
||||
*/
|
||||
@@ -199,6 +213,7 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||
bio_reader_t *extensions;
|
||||
tls_cipher_suite_t *suites;
|
||||
int count, i;
|
||||
rng_t *rng;
|
||||
|
||||
this->crypto->append_handshake(this->crypto,
|
||||
TLS_CLIENT_HELLO, reader->peek(reader));
|
||||
@@ -249,6 +264,17 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||
|
||||
memcpy(this->client_random, random.ptr, sizeof(this->client_random));
|
||||
|
||||
htoun32(&this->server_random, time(NULL));
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_TLS, "no suitable RNG found to generate server random");
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||
return NEED_MORE;
|
||||
}
|
||||
rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
|
||||
rng->destroy(rng);
|
||||
|
||||
if (!this->tls->set_version(this->tls, version))
|
||||
{
|
||||
DBG1(DBG_TLS, "negotiated version %N not supported",
|
||||
@@ -256,24 +282,44 @@ static status_t process_client_hello(private_tls_server_t *this,
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
|
||||
return NEED_MORE;
|
||||
}
|
||||
count = ciphers.len / sizeof(u_int16_t);
|
||||
suites = alloca(count * sizeof(tls_cipher_suite_t));
|
||||
DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
|
||||
DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
|
||||
}
|
||||
|
||||
if (!select_suite_and_key(this, suites, count))
|
||||
{
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||
return NEED_MORE;
|
||||
}
|
||||
DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
|
||||
tls_version_names, this->tls->get_version(this->tls),
|
||||
tls_cipher_suite_names, this->suite);
|
||||
this->client_version = version;
|
||||
this->suite = this->crypto->resume_session(this->crypto, session, this->peer,
|
||||
chunk_from_thing(this->client_random),
|
||||
chunk_from_thing(this->server_random));
|
||||
if (this->suite)
|
||||
{
|
||||
this->session = chunk_clone(session);
|
||||
this->resume = TRUE;
|
||||
DBG1(DBG_TLS, "resumed %N using suite %N",
|
||||
tls_version_names, this->tls->get_version(this->tls),
|
||||
tls_cipher_suite_names, this->suite);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = ciphers.len / sizeof(u_int16_t);
|
||||
suites = alloca(count * sizeof(tls_cipher_suite_t));
|
||||
DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
|
||||
DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
|
||||
}
|
||||
if (!select_suite_and_key(this, suites, count))
|
||||
{
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
|
||||
return NEED_MORE;
|
||||
}
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
|
||||
if (rng)
|
||||
{
|
||||
rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session);
|
||||
rng->destroy(rng);
|
||||
}
|
||||
DBG1(DBG_TLS, "negotiated %N using suite %N",
|
||||
tls_version_names, this->tls->get_version(this->tls),
|
||||
tls_cipher_suite_names, this->suite);
|
||||
}
|
||||
this->state = STATE_HELLO_RECEIVED;
|
||||
return NEED_MORE;
|
||||
}
|
||||
@@ -391,6 +437,7 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this,
|
||||
}
|
||||
|
||||
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
|
||||
this->session, this->peer,
|
||||
chunk_from_thing(this->client_random),
|
||||
chunk_from_thing(this->server_random));
|
||||
|
||||
@@ -439,6 +486,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
|
||||
}
|
||||
|
||||
this->crypto->derive_secrets(this->crypto, premaster,
|
||||
this->session, this->peer,
|
||||
chunk_from_thing(this->client_random),
|
||||
chunk_from_thing(this->server_random));
|
||||
chunk_clear(&premaster);
|
||||
@@ -576,10 +624,7 @@ METHOD(tls_handshake_t, process, status_t,
|
||||
expected = TLS_CERTIFICATE_VERIFY;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
return INVALID_STATE;
|
||||
}
|
||||
return INVALID_STATE;
|
||||
case STATE_CIPHERSPEC_CHANGED_IN:
|
||||
if (type == TLS_FINISHED)
|
||||
{
|
||||
@@ -605,27 +650,12 @@ METHOD(tls_handshake_t, process, status_t,
|
||||
static status_t send_server_hello(private_tls_server_t *this,
|
||||
tls_handshake_type_t *type, bio_writer_t *writer)
|
||||
{
|
||||
tls_version_t version;
|
||||
rng_t *rng;
|
||||
|
||||
htoun32(&this->server_random, time(NULL));
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_TLS, "no suitable RNG found to generate server random");
|
||||
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||
return FAILED;
|
||||
}
|
||||
rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
|
||||
rng->destroy(rng);
|
||||
|
||||
/* TLS version */
|
||||
version = this->tls->get_version(this->tls);
|
||||
writer->write_uint16(writer, version);
|
||||
writer->write_uint16(writer, this->tls->get_version(this->tls));
|
||||
writer->write_data(writer, chunk_from_thing(this->server_random));
|
||||
|
||||
/* session identifier => none, we don't support session resumption */
|
||||
writer->write_data8(writer, chunk_empty);
|
||||
/* session identifier if we have one */
|
||||
writer->write_data8(writer, this->session);
|
||||
|
||||
/* add selected TLS cipher suite */
|
||||
writer->write_uint16(writer, this->suite);
|
||||
@@ -914,9 +944,8 @@ static status_t send_finished(private_tls_server_t *this,
|
||||
|
||||
*type = TLS_FINISHED;
|
||||
this->state = STATE_FINISHED_SENT;
|
||||
this->crypto->derive_eap_msk(this->crypto,
|
||||
chunk_from_thing(this->client_random),
|
||||
chunk_from_thing(this->server_random));
|
||||
this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
@@ -960,6 +989,10 @@ METHOD(tls_handshake_t, cipherspec_changed, bool,
|
||||
{
|
||||
if (inbound)
|
||||
{
|
||||
if (this->resume)
|
||||
{
|
||||
return this->state == STATE_FINISHED_SENT;
|
||||
}
|
||||
if (this->peer)
|
||||
{
|
||||
return this->state == STATE_CERT_VERIFY_RECEIVED;
|
||||
@@ -968,6 +1001,10 @@ METHOD(tls_handshake_t, cipherspec_changed, bool,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->resume)
|
||||
{
|
||||
return this->state == STATE_HELLO_SENT;
|
||||
}
|
||||
return this->state == STATE_FINISHED_RECEIVED;
|
||||
}
|
||||
return FALSE;
|
||||
@@ -990,6 +1027,10 @@ METHOD(tls_handshake_t, change_cipherspec, void,
|
||||
METHOD(tls_handshake_t, finished, bool,
|
||||
private_tls_server_t *this)
|
||||
{
|
||||
if (this->resume)
|
||||
{
|
||||
return this->state == STATE_FINISHED_RECEIVED;
|
||||
}
|
||||
return this->state == STATE_FINISHED_SENT;
|
||||
}
|
||||
|
||||
@@ -1002,6 +1043,7 @@ METHOD(tls_handshake_t, destroy, void,
|
||||
this->server_auth->destroy(this->server_auth);
|
||||
free(this->hashsig.ptr);
|
||||
free(this->curves.ptr);
|
||||
free(this->session.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ METHOD(tls_socket_t, destroy, void,
|
||||
* See header
|
||||
*/
|
||||
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
|
||||
identification_t *peer, int fd)
|
||||
identification_t *peer, int fd, tls_cache_t *cache)
|
||||
{
|
||||
private_tls_socket_t *this;
|
||||
|
||||
@@ -215,7 +215,7 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
|
||||
);
|
||||
|
||||
this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_GENERIC,
|
||||
&this->app.application);
|
||||
&this->app.application, cache);
|
||||
if (!this->tls)
|
||||
{
|
||||
free(this);
|
||||
|
||||
@@ -74,9 +74,10 @@ struct tls_socket_t {
|
||||
* @param server server identity
|
||||
* @param peer client identity, NULL for no client authentication
|
||||
* @param fd socket to read/write from
|
||||
* @param cache session cache to use, or NULL
|
||||
* @return TLS socket wrapper
|
||||
*/
|
||||
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
|
||||
identification_t *peer, int fd);
|
||||
identification_t *peer, int fd, tls_cache_t *cache);
|
||||
|
||||
#endif /** TLS_SOCKET_H_ @}*/
|
||||
|
||||
Reference in New Issue
Block a user