*/
tls_t *tls;
+ /**
+ * All handshake data concatentated
+ */
+ chunk_t handshake;
+
/**
* Connection state TLS PRF
*/
return 0;
}
-METHOD(tls_crypto_t, derive_master_secret, void,
+METHOD(tls_crypto_t, append_handshake, void,
+ private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data)
+{
+ u_int32_t header;
+
+ /* reconstruct handshake header */
+ header = htonl(data.len | (type << 24));
+ this->handshake = chunk_cat("mcc", this->handshake,
+ chunk_from_thing(header), data);
+}
+
+/**
+ * Create a hash of the stored handshake data
+ */
+static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash)
+{
+ if (this->tls->get_version(this->tls) >= TLS_1_2)
+ {
+ hasher_t *hasher;
+ suite_algs_t *alg;
+
+ alg = find_suite(this->suite);
+ if (!alg)
+ {
+ return FALSE;
+ }
+ hasher = lib->crypto->create_hasher(lib->crypto, alg->hash);
+ if (!hasher)
+ {
+ DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, alg->hash);
+ return FALSE;
+ }
+ hasher->allocate_hash(hasher, this->handshake, hash);
+ hasher->destroy(hasher);
+ }
+ else
+ {
+ hasher_t *md5, *sha1;
+ char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
+
+ md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
+ if (!md5)
+ {
+ DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_MD5);
+ return FALSE;
+ }
+ md5->get_hash(md5, this->handshake, buf);
+ md5->destroy(md5);
+ sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (!sha1)
+ {
+ DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_SHA1);
+ return FALSE;
+ }
+ sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
+ sha1->destroy(sha1);
+
+ *hash = chunk_clone(chunk_from_thing(buf));
+ }
+ return TRUE;
+}
+
+METHOD(tls_crypto_t, sign_handshake, bool,
+ private_tls_crypto_t *this, private_key_t *key, chunk_t *sig)
+{
+ if (this->tls->get_version(this->tls) >= TLS_1_2)
+ {
+ u_int16_t length;
+ u_int8_t hash_alg;
+ u_int8_t sig_alg;
+
+ if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig))
+ {
+ return FALSE;
+ }
+ /* TODO: signature scheme to hashsign algorithm mapping */
+ hash_alg = 2; /* sha1 */
+ sig_alg = 1; /* RSA */
+ length = htons(sig->len);
+ *sig = chunk_cat("cccm", chunk_from_thing(hash_alg),
+ chunk_from_thing(sig_alg), chunk_from_thing(length), *sig);
+ }
+ else
+ {
+ u_int16_t length;
+ chunk_t hash;
+
+ if (!hash_handshake(this, &hash))
+ {
+ return FALSE;
+ }
+ if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig))
+ {
+ free(hash.ptr);
+ return FALSE;
+ }
+ free(hash.ptr);
+ length = htons(sig->len);
+ *sig = chunk_cat("cm", chunk_from_thing(length), *sig);
+ }
+ return TRUE;
+}
+
+METHOD(tls_crypto_t, calculate_finished, bool,
+ private_tls_crypto_t *this, char *label, char out[12])
+{
+ chunk_t seed;
+
+ if (!this->prf)
+ {
+ return FALSE;
+ }
+ if (!hash_handshake(this, &seed))
+ {
+ return FALSE;
+ }
+ this->prf->get_bytes(this->prf, label, seed, 12, out);
+ free(seed.ptr);
+ 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)
{
this->prf->set_key(this->prf, chunk_from_thing(master));
memset(master, 0, sizeof(master));
- /* MSK for EAP-TLS */
- this->msk = chunk_alloc(64);
- this->prf->get_bytes(this->prf, "client EAP encryption", seed,
- this->msk.len, this->msk.ptr);
-
/* derive key block for key expansion */
mks = this->signer_out->get_key_size(this->signer_out);
if (this->crypter_out)
}
}
-METHOD(tls_crypto_t, get_prf, tls_prf_t*,
- private_tls_crypto_t *this)
+METHOD(tls_crypto_t, derive_eap_msk, void,
+ private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
{
- return this->prf;
+ 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, "client EAP encryption", seed,
+ this->msk.len, this->msk.ptr);
}
METHOD(tls_crypto_t, get_eap_msk, chunk_t,
DESTROY_IF(this->crypter_out);
free(this->iv_in.ptr);
free(this->iv_out.ptr);
+ free(this->handshake.ptr);
free(this->msk.ptr);
DESTROY_IF(this->prf);
free(this->suites);
.public = {
.get_cipher_suites = _get_cipher_suites,
.select_cipher_suite = _select_cipher_suite,
- .derive_master_secret = _derive_master_secret,
+ .append_handshake = _append_handshake,
+ .sign_handshake = _sign_handshake,
+ .calculate_finished = _calculate_finished,
+ .derive_secrets = _derive_secrets,
.change_cipher = _change_cipher,
- .get_prf = _get_prf,
+ .derive_eap_msk = _derive_eap_msk,
.get_eap_msk = _get_eap_msk,
.destroy = _destroy,
},
#include "tls.h"
#include "tls_prf.h"
+#include <credentials/keys/private_key.h>
+
/**
* TLS crypto helper functions.
*/
tls_cipher_suite_t *suites, int count);
/**
- * Derive the master secret and load it into the PRF.
+ * Store exchanged handshake data, used for cryptographic operations.
+ *
+ * @param type handshake sub type
+ * @param data data to append to handshake buffer
+ */
+ void (*append_handshake)(tls_crypto_t *this,
+ tls_handshake_type_t type, chunk_t data);
+
+ /**
+ * Create a signature of the handshake data using a given private key.
+ *
+ * @param key private key to use for signature
+ * @param sig allocated signature
+ * @return TRUE if signature create successfully
+ */
+ bool (*sign_handshake)(tls_crypto_t *this, private_key_t *key, chunk_t *sig);
+
+ /**
+ * Calculate the data of a TLS finished message.
+ *
+ * @param label ASCII label to use for calculation
+ * @param out buffer to write finished data to
+ * @return TRUE if calculation successful
+ */
+ bool (*calculate_finished)(tls_crypto_t *this, char *label, char out[12]);
+
+ /**
+ * Derive the master secret, MAC and encryption keys.
*
* @param premaster premaster secret
* @param client_random random data from client hello
* @param server_random random data from server hello
*/
- void (*derive_master_secret)(tls_crypto_t *this, chunk_t premaster,
- chunk_t client_random, chunk_t server_random);
+ void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster,
+ chunk_t client_random, chunk_t server_random);
/**
* Change the cipher used at protection layer.
void (*change_cipher)(tls_crypto_t *this, bool inbound);
/**
- * Get the connection state PRF.
+ * Derive the EAP-TLS MSK.
*
- * @return PRF, NULL if not supported
+ * @param client_random random data from client hello
+ * @param server_random random data from server hello
*/
- tls_prf_t* (*get_prf)(tls_crypto_t *this);
+ void (*derive_eap_msk)(tls_crypto_t *this,
+ chunk_t client_random, chunk_t server_random);
/**
* Get the MSK to use in EAP-TLS.
*/
peer_state_t state;
- /**
- * All handshake data concatentated
- */
- chunk_t handshake;
-
/**
* Hello random data selected by client
*/
private_key_t *private;
};
-/**
- * Append a handshake message to the handshake data buffer
- */
-static void append_handshake(private_tls_peer_t *this,
- tls_handshake_type_t type, chunk_t data)
-{
- u_int32_t header;
-
- /* reconstruct handshake header */
- header = htonl(data.len | (type << 24));
- this->handshake = chunk_cat("mcc", this->handshake,
- chunk_from_thing(header), data);
-}
-
/**
* Process a server hello message
*/
chunk_t random, session, ext = chunk_empty;
tls_cipher_suite_t suite;
- append_handshake(this, TLS_SERVER_HELLO, reader->peek(reader));
+ this->crypto->append_handshake(this->crypto,
+ TLS_SERVER_HELLO, reader->peek(reader));
if (!reader->read_uint16(reader, &version) ||
!reader->read_data(reader, sizeof(this->server_random), &random) ||
chunk_t data;
bool first = TRUE;
- append_handshake(this, TLS_CERTIFICATE, reader->peek(reader));
+ this->crypto->append_handshake(this->crypto,
+ TLS_CERTIFICATE, reader->peek(reader));
if (!reader->read_data24(reader, &data))
{
identification_t *id;
certificate_t *cert;
- append_handshake(this, TLS_CERTIFICATE_REQUEST, reader->peek(reader));
+ this->crypto->append_handshake(this->crypto,
+ TLS_CERTIFICATE_REQUEST, reader->peek(reader));
if (!reader->read_data8(reader, &types))
{
static status_t process_hello_done(private_tls_peer_t *this,
tls_reader_t *reader)
{
- append_handshake(this, TLS_SERVER_HELLO_DONE, reader->peek(reader));
+ this->crypto->append_handshake(this->crypto,
+ TLS_SERVER_HELLO_DONE, reader->peek(reader));
this->state = STATE_HELLO_DONE;
return NEED_MORE;
}
*/
static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
{
- chunk_t seed, received;
- tls_prf_t *prf;
- char data[12];
+ chunk_t received;
+ char buf[12];
- if (!reader->read_data(reader, sizeof(data), &received))
+ if (!reader->read_data(reader, sizeof(buf), &received))
{
DBG1(DBG_IKE, "received server finished too short");
return FAILED;
}
-
- if (this->tls->get_version(this->tls) >= TLS_1_2)
- {
- /* TODO: use hash of cipher suite only */
- seed = chunk_empty;
- }
- else
- {
- hasher_t *md5, *sha1;
- char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
-
- md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- if (!md5)
- {
- DBG1(DBG_IKE, "unable to create %N Finished, MD5 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- md5->get_hash(md5, this->handshake, buf);
- md5->destroy(md5);
- sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- if (!sha1)
- {
- DBG1(DBG_IKE, "unable to sign %N Finished, SHA1 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
- sha1->destroy(sha1);
-
- seed = chunk_clonea(chunk_from_thing(buf));
- }
-
- prf = this->crypto->get_prf(this->crypto);
- if (!prf)
+ if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
{
+ DBG1(DBG_IKE, "calculating server finished failed");
return FAILED;
}
- prf->get_bytes(prf, "server finished", seed, sizeof(data), data);
-
- if (!chunk_equals(received, chunk_from_thing(data)))
+ if (!chunk_equals(received, chunk_from_thing(buf)))
{
DBG1(DBG_IKE, "received server finished invalid");
return FAILED;
}
this->state = STATE_COMPLETE;
+ this->crypto->derive_eap_msk(this->crypto,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
return NEED_MORE;
}
*type = TLS_CLIENT_HELLO;
this->state = STATE_HELLO_SENT;
- append_handshake(this, *type, writer->get_buf(writer));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
return NEED_MORE;
}
*type = TLS_CERTIFICATE;
this->state = STATE_CERT_SENT;
- append_handshake(this, *type, writer->get_buf(writer));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
return NEED_MORE;
}
rng->destroy(rng);
htoun16(premaster, TLS_1_2);
- this->crypto->derive_master_secret(this->crypto, chunk_from_thing(premaster),
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
+ this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
enumerator = charon->credentials->create_public_enumerator(
charon->credentials, KEY_ANY, this->server, this->server_auth);
*type = TLS_CLIENT_KEY_EXCHANGE;
this->state = STATE_KEY_EXCHANGE_SENT;
- append_handshake(this, *type, writer->get_buf(writer));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
return NEED_MORE;
}
{
chunk_t signature;
- if (!this->private)
+ if (!this->private ||
+ !this->crypto->sign_handshake(this->crypto, this->private, &signature))
{
+ DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
return FAILED;
}
-
- if (this->tls->get_version(this->tls) >= TLS_1_2)
- {
- if (!this->private->sign(this->private, SIGN_RSA_EMSA_PKCS1_SHA1,
- this->handshake, &signature))
- {
- DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
- return FAILED;
- }
- /* TODO: signature scheme to hashsign algorithm mapping */
- writer->write_uint8(writer, 2); /* sha1 */
- writer->write_uint8(writer, 1); /* RSA */
- }
- else
- {
- hasher_t *md5, *sha1;
- char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
-
- md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- if (!md5)
- {
- DBG1(DBG_IKE, "unable to sign %N Verify, MD5 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- md5->get_hash(md5, this->handshake, buf);
- md5->destroy(md5);
- sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- if (!sha1)
- {
- DBG1(DBG_IKE, "unable to sign %N Verify, SHA1 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
- sha1->destroy(sha1);
-
- if (!this->private->sign(this->private, SIGN_RSA_EMSA_PKCS1_NULL,
- chunk_from_thing(buf), &signature))
- {
- DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
- return FAILED;
- }
- }
- writer->write_data16(writer, signature);
+ writer->write_data(writer, signature);
free(signature.ptr);
*type = TLS_CERTIFICATE_VERIFY;
this->state = STATE_VERIFY_SENT;
- append_handshake(this, *type, writer->get_buf(writer));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
return NEED_MORE;
}
static status_t send_finished(private_tls_peer_t *this,
tls_handshake_type_t *type, tls_writer_t *writer)
{
- chunk_t seed;
- tls_prf_t *prf;
- char data[12];
-
- if (this->tls->get_version(this->tls) >= TLS_1_2)
- {
- /* TODO: use hash of cipher suite only */
- seed = chunk_empty;
- }
- else
- {
- hasher_t *md5, *sha1;
- char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
-
- md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- if (!md5)
- {
- DBG1(DBG_IKE, "unable to create %N Finished, MD5 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- md5->get_hash(md5, this->handshake, buf);
- md5->destroy(md5);
- sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- if (!sha1)
- {
- DBG1(DBG_IKE, "unable to sign %N Finished, SHA1 not supported",
- tls_version_names, this->tls->get_version(this->tls));
- return FAILED;
- }
- sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
- sha1->destroy(sha1);
-
- seed = chunk_clonea(chunk_from_thing(buf));
- }
+ char buf[12];
- prf = this->crypto->get_prf(this->crypto);
- if (!prf)
+ if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
{
+ DBG1(DBG_IKE, "calculating client finished data failed");
return FAILED;
}
- prf->get_bytes(prf, "client finished", seed, sizeof(data), data);
- writer->write_data(writer, chunk_from_thing(data));
+ writer->write_data(writer, chunk_from_thing(buf));
*type = TLS_FINISHED;
this->state = STATE_FINISHED_SENT;
- append_handshake(this, *type, writer->get_buf(writer));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
return NEED_MORE;
}
private_tls_peer_t *this)
{
DESTROY_IF(this->private);
- free(this->handshake.ptr);
this->peer_auth->destroy(this->peer_auth);
this->server_auth->destroy(this->server_auth);
free(this);