Derive master secret, create Finished message
This commit is contained in:
@@ -157,10 +157,10 @@ tls_t *tls_create(bool is_server, identification_t *server,
|
|||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.is_server = is_server,
|
.is_server = is_server,
|
||||||
.crypto = tls_crypto_create(),
|
|
||||||
.version = TLS_1_2,
|
.version = TLS_1_2,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this->crypto = tls_crypto_create(&this->public);
|
||||||
if (is_server)
|
if (is_server)
|
||||||
{
|
{
|
||||||
this->handshake = &tls_server_create(&this->public, this->crypto,
|
this->handshake = &tls_server_create(&this->public, this->crypto,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#include "tls_crypto.h"
|
#include "tls_crypto.h"
|
||||||
|
|
||||||
|
#include <daemon.h>
|
||||||
|
|
||||||
typedef struct private_tls_crypto_t private_tls_crypto_t;
|
typedef struct private_tls_crypto_t private_tls_crypto_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,16 +28,43 @@ struct private_tls_crypto_t {
|
|||||||
* Public tls_crypto_t interface.
|
* Public tls_crypto_t interface.
|
||||||
*/
|
*/
|
||||||
tls_crypto_t public;
|
tls_crypto_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of supported/acceptable cipher suites
|
||||||
|
*/
|
||||||
|
tls_cipher_suite_t *suites;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of supported suites
|
||||||
|
*/
|
||||||
|
int suite_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selected cipher suite
|
||||||
|
*/
|
||||||
|
tls_cipher_suite_t suite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TLS context
|
||||||
|
*/
|
||||||
|
tls_t *tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connection state TLS PRF
|
||||||
|
*/
|
||||||
|
tls_prf_t *prf;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(tls_crypto_t, get_cipher_suites, int,
|
/**
|
||||||
private_tls_crypto_t *this, tls_cipher_suite_t **suites)
|
* Initialize the cipher suite list
|
||||||
|
*/
|
||||||
|
static void build_cipher_suite_list(private_tls_crypto_t *this)
|
||||||
{
|
{
|
||||||
encryption_algorithm_t encr;
|
encryption_algorithm_t encr;
|
||||||
integrity_algorithm_t mac;
|
integrity_algorithm_t mac;
|
||||||
enumerator_t *encrs, *macs;
|
enumerator_t *encrs, *macs;
|
||||||
tls_cipher_suite_t buf[64];
|
tls_cipher_suite_t supported[64], unique[64];
|
||||||
int count = 0, i, j, res = 0;
|
int count = 0, i, j;
|
||||||
|
|
||||||
/* we assume that we support RSA, but no DHE yet */
|
/* we assume that we support RSA, but no DHE yet */
|
||||||
macs = lib->crypto->create_signer_enumerator(lib->crypto);
|
macs = lib->crypto->create_signer_enumerator(lib->crypto);
|
||||||
@@ -44,13 +73,13 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
|
|||||||
switch (mac)
|
switch (mac)
|
||||||
{
|
{
|
||||||
case AUTH_HMAC_SHA1_160:
|
case AUTH_HMAC_SHA1_160:
|
||||||
buf[count++] = TLS_RSA_WITH_NULL_SHA;
|
supported[count++] = TLS_RSA_WITH_NULL_SHA;
|
||||||
break;
|
break;
|
||||||
case AUTH_HMAC_SHA2_256_256:
|
case AUTH_HMAC_SHA2_256_256:
|
||||||
buf[count++] = TLS_RSA_WITH_NULL_SHA256;
|
supported[count++] = TLS_RSA_WITH_NULL_SHA256;
|
||||||
break;
|
break;
|
||||||
case AUTH_HMAC_MD5_128:
|
case AUTH_HMAC_MD5_128:
|
||||||
buf[count++] = TLS_RSA_WITH_NULL_MD5;
|
supported[count++] = TLS_RSA_WITH_NULL_MD5;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -64,12 +93,12 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
|
|||||||
switch (mac)
|
switch (mac)
|
||||||
{
|
{
|
||||||
case AUTH_HMAC_SHA1_160:
|
case AUTH_HMAC_SHA1_160:
|
||||||
buf[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
||||||
buf[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
supported[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
||||||
break;
|
break;
|
||||||
case AUTH_HMAC_SHA2_256_256:
|
case AUTH_HMAC_SHA2_256_256:
|
||||||
buf[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
||||||
buf[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -79,7 +108,7 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
|
|||||||
switch (mac)
|
switch (mac)
|
||||||
{
|
{
|
||||||
case AUTH_HMAC_SHA1_160:
|
case AUTH_HMAC_SHA1_160:
|
||||||
buf[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
|
supported[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -94,14 +123,14 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
|
|||||||
macs->destroy(macs);
|
macs->destroy(macs);
|
||||||
|
|
||||||
/* remove duplicates */
|
/* remove duplicates */
|
||||||
*suites = malloc(sizeof(tls_cipher_suite_t) * count);
|
this->suite_count = 0;
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
bool match = FALSE;
|
bool match = FALSE;
|
||||||
|
|
||||||
for (j = 0; j < res; j++)
|
for (j = 0; j < this->suite_count; j++)
|
||||||
{
|
{
|
||||||
if (buf[i] == (*suites)[j])
|
if (supported[i] == unique[j])
|
||||||
{
|
{
|
||||||
match = TRUE;
|
match = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -109,32 +138,122 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
|
|||||||
}
|
}
|
||||||
if (!match)
|
if (!match)
|
||||||
{
|
{
|
||||||
(*suites)[res++] = buf[i];
|
unique[this->suite_count++] = supported[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
free(this->suites);
|
||||||
|
this->suites = malloc(sizeof(tls_cipher_suite_t) * this->suite_count);
|
||||||
|
memcpy(this->suites, unique, sizeof(tls_cipher_suite_t) * this->suite_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, get_cipher_suites, int,
|
||||||
|
private_tls_crypto_t *this, tls_cipher_suite_t **suites)
|
||||||
|
{
|
||||||
|
*suites = this->suites;
|
||||||
|
return this->suite_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t,
|
||||||
|
private_tls_crypto_t *this, tls_cipher_suite_t *suites, int count)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < this->suite_count; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < count; j++)
|
||||||
|
{
|
||||||
|
if (this->suites[i] == suites[j])
|
||||||
|
{
|
||||||
|
this->suite = this->suites[i];
|
||||||
|
return this->suite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, derive_master_secret, void,
|
||||||
|
private_tls_crypto_t *this, chunk_t premaster,
|
||||||
|
chunk_t client_random, chunk_t server_random)
|
||||||
|
{
|
||||||
|
if (!this->prf)
|
||||||
|
{
|
||||||
|
if (this->tls->get_version(this->tls) < TLS_1_2)
|
||||||
|
{
|
||||||
|
this->prf = tls_prf_create_10();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (this->suite)
|
||||||
|
{
|
||||||
|
case TLS_RSA_WITH_NULL_MD5:
|
||||||
|
this->prf = tls_prf_create_12(PRF_HMAC_MD5);
|
||||||
|
break;
|
||||||
|
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||||
|
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||||
|
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||||
|
case TLS_RSA_WITH_NULL_SHA:
|
||||||
|
this->prf = tls_prf_create_12(PRF_HMAC_SHA1);
|
||||||
|
break;
|
||||||
|
case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
||||||
|
case TLS_RSA_WITH_NULL_SHA256:
|
||||||
|
this->prf = tls_prf_create_12(PRF_HMAC_SHA2_256);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG1(DBG_IKE, "PRF for cipher suite unknown");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this->prf)
|
||||||
|
{
|
||||||
|
char master[48];
|
||||||
|
chunk_t seed;
|
||||||
|
|
||||||
|
seed = chunk_cata("cc", client_random, server_random);
|
||||||
|
this->prf->set_key(this->prf, premaster);
|
||||||
|
this->prf->get_bytes(this->prf, "master secret", seed,
|
||||||
|
sizeof(master), master);
|
||||||
|
|
||||||
|
this->prf->set_key(this->prf, chunk_from_thing(master));
|
||||||
|
memset(master, 0, sizeof(master));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tls_crypto_t, get_prf, tls_prf_t*,
|
||||||
|
private_tls_crypto_t *this)
|
||||||
|
{
|
||||||
|
|
||||||
|
return this->prf;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(tls_crypto_t, destroy, void,
|
METHOD(tls_crypto_t, destroy, void,
|
||||||
private_tls_crypto_t *this)
|
private_tls_crypto_t *this)
|
||||||
{
|
{
|
||||||
|
free(this->suites);
|
||||||
|
DESTROY_IF(this->prf);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
tls_crypto_t *tls_crypto_create()
|
tls_crypto_t *tls_crypto_create(tls_t *tls)
|
||||||
{
|
{
|
||||||
private_tls_crypto_t *this;
|
private_tls_crypto_t *this;
|
||||||
|
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.get_cipher_suites = _get_cipher_suites,
|
.get_cipher_suites = _get_cipher_suites,
|
||||||
|
.select_cipher_suite = _select_cipher_suite,
|
||||||
|
.derive_master_secret = _derive_master_secret,
|
||||||
|
.get_prf = _get_prf,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
|
.tls = tls,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
build_cipher_suite_list(this);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
typedef struct tls_crypto_t tls_crypto_t;
|
typedef struct tls_crypto_t tls_crypto_t;
|
||||||
|
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "tls_prf.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TLS crypto helper functions.
|
* TLS crypto helper functions.
|
||||||
@@ -33,11 +34,38 @@ struct tls_crypto_t {
|
|||||||
/**
|
/**
|
||||||
* Get a list of supported TLS cipher suites.
|
* Get a list of supported TLS cipher suites.
|
||||||
*
|
*
|
||||||
* @param suites allocated list of suites
|
* @param suites list of suites, points to internal data
|
||||||
* @return number of suites returned
|
* @return number of suites returned
|
||||||
*/
|
*/
|
||||||
int (*get_cipher_suites)(tls_crypto_t *this, tls_cipher_suite_t **suites);
|
int (*get_cipher_suites)(tls_crypto_t *this, tls_cipher_suite_t **suites);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select and store a cipher suite from a given list of candidates.
|
||||||
|
*
|
||||||
|
* @param suites list of candidates to select from
|
||||||
|
* @param count number of suites
|
||||||
|
* @return selected suite, 0 if none acceptable
|
||||||
|
*/
|
||||||
|
tls_cipher_suite_t (*select_cipher_suite)(tls_crypto_t *this,
|
||||||
|
tls_cipher_suite_t *suites, int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the master secret and load it into the PRF.
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the connection state PRF.
|
||||||
|
*
|
||||||
|
* @return PRF, NULL if not supported
|
||||||
|
*/
|
||||||
|
tls_prf_t* (*get_prf)(tls_crypto_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a tls_crypto_t.
|
* Destroy a tls_crypto_t.
|
||||||
*/
|
*/
|
||||||
@@ -47,6 +75,6 @@ struct tls_crypto_t {
|
|||||||
/**
|
/**
|
||||||
* Create a tls_crypto instance.
|
* Create a tls_crypto instance.
|
||||||
*/
|
*/
|
||||||
tls_crypto_t *tls_crypto_create();
|
tls_crypto_t *tls_crypto_create(tls_t *tls);
|
||||||
|
|
||||||
#endif /** TLS_CRYPTO_H_ @}*/
|
#endif /** TLS_CRYPTO_H_ @}*/
|
||||||
|
|||||||
@@ -72,6 +72,16 @@ struct private_tls_peer_t {
|
|||||||
*/
|
*/
|
||||||
chunk_t handshake;
|
chunk_t handshake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hello random data selected by client
|
||||||
|
*/
|
||||||
|
char client_random[32];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hello random data selected by server
|
||||||
|
*/
|
||||||
|
char server_random[32];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auth helper for peer authentication
|
* Auth helper for peer authentication
|
||||||
*/
|
*/
|
||||||
@@ -110,14 +120,13 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
|||||||
{
|
{
|
||||||
u_int8_t compression;
|
u_int8_t compression;
|
||||||
u_int16_t version, cipher;
|
u_int16_t version, cipher;
|
||||||
u_int32_t gmt;
|
|
||||||
chunk_t random, session, ext = chunk_empty;
|
chunk_t random, session, ext = chunk_empty;
|
||||||
|
tls_cipher_suite_t suite;
|
||||||
|
|
||||||
append_handshake(this, TLS_SERVER_HELLO, reader->peek(reader));
|
append_handshake(this, TLS_SERVER_HELLO, reader->peek(reader));
|
||||||
|
|
||||||
if (!reader->read_uint16(reader, &version) ||
|
if (!reader->read_uint16(reader, &version) ||
|
||||||
!reader->read_uint32(reader, &gmt) ||
|
!reader->read_data(reader, sizeof(this->server_random), &random) ||
|
||||||
!reader->read_data(reader, 28, &random) ||
|
|
||||||
!reader->read_data8(reader, &session) ||
|
!reader->read_data8(reader, &session) ||
|
||||||
!reader->read_uint16(reader, &cipher) ||
|
!reader->read_uint16(reader, &cipher) ||
|
||||||
!reader->read_uint8(reader, &compression) ||
|
!reader->read_uint8(reader, &compression) ||
|
||||||
@@ -126,10 +135,19 @@ static status_t process_server_hello(private_tls_peer_t *this,
|
|||||||
DBG1(DBG_IKE, "received invalid ServerHello");
|
DBG1(DBG_IKE, "received invalid ServerHello");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(this->server_random, random.ptr, sizeof(this->server_random));
|
||||||
|
|
||||||
if (version < this->tls->get_version(this->tls))
|
if (version < this->tls->get_version(this->tls))
|
||||||
{
|
{
|
||||||
this->tls->set_version(this->tls, version);
|
this->tls->set_version(this->tls, version);
|
||||||
}
|
}
|
||||||
|
suite = cipher;
|
||||||
|
if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "received cipher suite inacceptable");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,19 +307,18 @@ static status_t send_hello(private_tls_peer_t *this,
|
|||||||
tls_cipher_suite_t *suite;
|
tls_cipher_suite_t *suite;
|
||||||
int count, i;
|
int count, i;
|
||||||
rng_t *rng;
|
rng_t *rng;
|
||||||
char random[28];
|
|
||||||
|
|
||||||
|
htoun32(&this->client_random, time(NULL));
|
||||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
if (!rng)
|
if (!rng)
|
||||||
{
|
{
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
rng->get_bytes(rng, sizeof(random), random);
|
rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4);
|
||||||
rng->destroy(rng);
|
rng->destroy(rng);
|
||||||
|
|
||||||
writer->write_uint16(writer, this->tls->get_version(this->tls));
|
writer->write_uint16(writer, this->tls->get_version(this->tls));
|
||||||
writer->write_uint32(writer, time(NULL));
|
writer->write_data(writer, chunk_from_thing(this->client_random));
|
||||||
writer->write_data(writer, chunk_from_thing(random));
|
|
||||||
/* session identifier => none */
|
/* session identifier => none */
|
||||||
writer->write_data8(writer, chunk_empty);
|
writer->write_data8(writer, chunk_empty);
|
||||||
|
|
||||||
@@ -311,7 +328,6 @@ static status_t send_hello(private_tls_peer_t *this,
|
|||||||
{
|
{
|
||||||
writer->write_uint16(writer, suite[i]);
|
writer->write_uint16(writer, suite[i]);
|
||||||
}
|
}
|
||||||
free(suite);
|
|
||||||
/* NULL compression only */
|
/* NULL compression only */
|
||||||
writer->write_uint8(writer, 1);
|
writer->write_uint8(writer, 1);
|
||||||
writer->write_uint8(writer, 0);
|
writer->write_uint8(writer, 0);
|
||||||
@@ -399,6 +415,10 @@ static status_t send_key_exchange(private_tls_peer_t *this,
|
|||||||
rng->destroy(rng);
|
rng->destroy(rng);
|
||||||
htoun16(premaster, TLS_1_2);
|
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));
|
||||||
|
|
||||||
enumerator = charon->credentials->create_public_enumerator(
|
enumerator = charon->credentials->create_public_enumerator(
|
||||||
charon->credentials, KEY_ANY, this->server, this->server_auth);
|
charon->credentials, KEY_ANY, this->server, this->server_auth);
|
||||||
while (enumerator->enumerate(enumerator, ¤t, &auth))
|
while (enumerator->enumerate(enumerator, ¤t, &auth))
|
||||||
@@ -501,9 +521,53 @@ static status_t send_certificate_verify(private_tls_peer_t *this,
|
|||||||
static status_t send_finished(private_tls_peer_t *this,
|
static status_t send_finished(private_tls_peer_t *this,
|
||||||
tls_handshake_type_t *type, tls_writer_t *writer)
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
prf = this->crypto->get_prf(this->crypto);
|
||||||
|
if (!prf)
|
||||||
|
{
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
prf->get_bytes(prf, "client finished", seed, sizeof(data), data);
|
||||||
|
|
||||||
|
writer->write_data(writer, chunk_from_thing(data));
|
||||||
|
|
||||||
*type = TLS_FINISHED;
|
*type = TLS_FINISHED;
|
||||||
this->state = STATE_FINISHED_SENT;
|
this->state = STATE_FINISHED_SENT;
|
||||||
/* TODO: finished message */
|
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user