Send a ClientHello to start TLS negotiation
This commit is contained in:
@@ -21,6 +21,11 @@
|
||||
|
||||
typedef struct private_tls_peer_t private_tls_peer_t;
|
||||
|
||||
typedef enum {
|
||||
STATE_INIT,
|
||||
STATE_HELLO_SENT,
|
||||
} peer_state_t;
|
||||
|
||||
/**
|
||||
* Private data of an tls_peer_t object.
|
||||
*/
|
||||
@@ -35,6 +40,11 @@ struct private_tls_peer_t {
|
||||
* TLS crypto context
|
||||
*/
|
||||
tls_crypto_t *crypto;
|
||||
|
||||
/**
|
||||
* State we are in
|
||||
*/
|
||||
peer_state_t state;
|
||||
};
|
||||
|
||||
METHOD(tls_handshake_t, process, status_t,
|
||||
@@ -43,10 +53,84 @@ METHOD(tls_handshake_t, process, status_t,
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Client Hello using a given set of ciphers
|
||||
*/
|
||||
static chunk_t build_hello(int count, tls_cipher_suite_t *suite, rng_t *rng)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct __attribute__((packed)) {
|
||||
u_int16_t version;
|
||||
struct __attribute__((packed)) {
|
||||
u_int32_t gmt;
|
||||
u_int8_t bytes[28];
|
||||
} random;
|
||||
struct __attribute__((packed)) {
|
||||
/* never send a session identifier */
|
||||
u_int8_t len;
|
||||
u_int8_t id[0];
|
||||
} session;
|
||||
struct __attribute__((packed)) {
|
||||
u_int16_t len;
|
||||
u_int16_t suite[count];
|
||||
} cipher;
|
||||
struct __attribute__((packed)) {
|
||||
/* currently NULL compression only */
|
||||
u_int8_t len;
|
||||
u_int8_t method[1];
|
||||
} compression;
|
||||
u_int8_t extensions[0];
|
||||
} hello;
|
||||
|
||||
htoun16(&hello.session.len, 0);
|
||||
htoun16(&hello.version, TLS_1_2);
|
||||
htoun32(&hello.random.gmt, time(NULL));
|
||||
rng->get_bytes(rng, sizeof(hello.random.bytes), (char*)&hello.random.bytes);
|
||||
htoun16(&hello.cipher.len, count * 2);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
htoun16(&hello.cipher.suite[i], suite[i]);
|
||||
}
|
||||
hello.compression.len = 1;
|
||||
hello.compression.method[0] = 0;
|
||||
return chunk_clone(chunk_create((char*)&hello, sizeof(hello)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a client hello
|
||||
*/
|
||||
static status_t send_hello(private_tls_peer_t *this,
|
||||
tls_handshake_type_t *type, chunk_t *data)
|
||||
{
|
||||
tls_cipher_suite_t *suite;
|
||||
int count;
|
||||
rng_t *rng;
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
count = this->crypto->get_cipher_suites(this->crypto, &suite);
|
||||
*data = build_hello(count, suite, rng);
|
||||
*type = TLS_CLIENT_HELLO;
|
||||
free(suite);
|
||||
rng->destroy(rng);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(tls_handshake_t, build, status_t,
|
||||
private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data)
|
||||
{
|
||||
return INVALID_STATE;
|
||||
switch (this->state)
|
||||
{
|
||||
case STATE_INIT:
|
||||
this->state = STATE_HELLO_SENT;
|
||||
return send_hello(this, type, data);
|
||||
default:
|
||||
return INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(tls_handshake_t, destroy, void,
|
||||
@@ -68,6 +152,7 @@ tls_peer_t *tls_peer_create(tls_crypto_t *crypto)
|
||||
.build = _build,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.state = STATE_INIT,
|
||||
.crypto = crypto,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user