Send a ClientHello to start TLS negotiation

This commit is contained in:
Martin Willi
2010-08-03 15:39:24 +02:00
parent 536dbc00b9
commit 698674c7f3
+86 -1
View File
@@ -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,
);