From 134efe1a25c87eda7de290136f513d5ff8d211ac Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Fri, 18 Nov 2011 17:19:37 +0200 Subject: [PATCH] tls: refactor tls_server_hello() Move each client response message to own function which is called by tls_server_hello(). --- src/core/sipe-tls.c | 183 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 76 deletions(-) diff --git a/src/core/sipe-tls.c b/src/core/sipe-tls.c index d5022a79..246924f4 100644 --- a/src/core/sipe-tls.c +++ b/src/core/sipe-tls.c @@ -737,95 +737,71 @@ static void compile_msg(struct tls_internal_state *state, state->common.out_length); } -static gboolean tls_client_hello(struct tls_internal_state *state) +static struct Certificate_host *tls_client_certificate(struct tls_internal_state *state, + gsize *cumulative_length) { - guint32 now = time(NULL); - guint32 now_N = GUINT32_TO_BE(now); - struct ClientHello_host msg = { - { TLS_PROTOCOL_VERSION_1_0 }, - { 0, { } }, - { 0 /* empty SessionID */ }, - { 3, - { - TLS_RSA_WITH_RC4_128_MD5, - TLS_RSA_WITH_RC4_128_SHA, - TLS_RSA_EXPORT_WITH_RC4_40_MD5 - } - }, - { 1, - { - TLS_COMP_METHOD_NULL - } - } - }; - - /* First 4 bytes of client_random is the current timestamp */ - sipe_svc_fill_random(&state->client_random, - TLS_DATATYPE_RANDOM_LENGTH * 8); /* -> bits */ - memcpy(state->client_random.buffer, &now_N, sizeof(now_N)); - memcpy((guchar *) msg.random.random, state->client_random.buffer, - TLS_DATATYPE_RANDOM_LENGTH); - - compile_msg(state, - sizeof(msg), - 1, - &ClientHello_m, &msg); + struct Certificate_host *certificate; + gsize certificate_length = sipe_cert_crypto_raw_length(state->certificate); - if (sipe_backend_debug_enabled()) - state->debug = g_string_new(""); + /* setup our response */ + /* Client Certificate is VECTOR_MAX24 of VECTOR_MAX24s */ + certificate = g_malloc0(sizeof(struct Certificate_host) + 3 + + certificate_length); + certificate->certificate.elements = certificate_length + 3; + lowlevel_integer_to_tls((guchar *) certificate->certificate.placeholder, 3, + certificate_length); + memcpy((guchar *) certificate->certificate.placeholder + 3, + sipe_cert_crypto_raw(state->certificate), + certificate_length); - state->state = TLS_HANDSHAKE_STATE_SERVER_HELLO; - return(tls_record_parse(state, FALSE)); + *cumulative_length += sizeof(struct Certificate_host) + certificate_length; + return(certificate); } -static gboolean tls_server_hello(struct tls_internal_state *state) +static struct ClientKeyExchange_host *tls_client_key_exchange(struct tls_internal_state *state, + gsize *cumulative_length) { struct tls_parsed_array *server_random; struct tls_parsed_array *server_certificate; - gsize server_certificate_length; - struct Certificate_host *certificate; - gsize certificate_length = sipe_cert_crypto_raw_length(state->certificate); struct ClientKeyExchange_host *exchange; - - if (!tls_record_parse(state, TRUE)) - return(FALSE); + gsize server_certificate_length; /* check for required data fields */ server_random = g_hash_table_lookup(state->data, "Random"); if (!server_random) { - SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: no server random"); - return(FALSE); + SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: no server random"); + return(NULL); } server_certificate = g_hash_table_lookup(state->data, "Certificate"); /* Server Certificate is VECTOR_MAX24 of VECTOR_MAX24s */ if (!server_certificate || (server_certificate->length < 3)) { - SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: no server certificate"); + SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: no server certificate"); return(FALSE); } - SIPE_DEBUG_INFO("tls_server_hello: server certificate list %" G_GSIZE_FORMAT" bytes", + SIPE_DEBUG_INFO("tls_client_key_exchange: server certificate list %" G_GSIZE_FORMAT" bytes", server_certificate->length); /* first certificate is the server certificate */ server_certificate_length = lowlevel_integer_to_host(server_certificate->data, 3); - SIPE_DEBUG_INFO("tls_server_hello: server certificate %" G_GSIZE_FORMAT" bytes", + SIPE_DEBUG_INFO("tls_client_key_exchange: server certificate %" G_GSIZE_FORMAT" bytes", server_certificate_length); if ((server_certificate_length + 3) > server_certificate->length) { - SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: truncated server certificate"); + SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: truncated server certificate"); } state->server_certificate = sipe_cert_crypto_import(server_certificate->data + 3, server_certificate_length); if (!state->server_certificate) { - SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: corrupted server certificate"); + SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: corrupted server certificate"); return(FALSE); } /* server public key modulus length */ server_certificate_length = sipe_cert_crypto_modulus_length(state->server_certificate); if (server_certificate_length < TLS_DATATYPE_PREMASTER_SECRET_LENGTH) { - SIPE_DEBUG_ERROR("tls_server_hello: server public key strength too low (%" G_GSIZE_FORMAT ")", + SIPE_DEBUG_ERROR("tls_client_key_exchange: server public key strength too low (%" G_GSIZE_FORMAT ")", server_certificate_length); return(FALSE); } - SIPE_DEBUG_INFO("tls_server_hello: server public key strength = %" G_GSIZE_FORMAT, + SIPE_DEBUG_INFO("tls_client_key_exchange: server public key strength = %" G_GSIZE_FORMAT, server_certificate_length); /* found all the required fields */ @@ -833,20 +809,6 @@ static gboolean tls_server_hello(struct tls_internal_state *state) state->server_random.buffer = g_memdup(server_random->data, server_random->length); - /* done with parsed data */ - free_parse_data(state); - - /* setup our response */ - /* Client Certificate is VECTOR_MAX24 of VECTOR_MAX24s */ - certificate = g_malloc0(sizeof(struct Certificate_host) + 3 + - certificate_length); - certificate->certificate.elements = certificate_length + 3; - lowlevel_integer_to_tls((guchar *) certificate->certificate.placeholder, 3, - certificate_length); - memcpy((guchar *) certificate->certificate.placeholder + 3, - sipe_cert_crypto_raw(state->certificate), - certificate_length); - /* ClientKeyExchange */ exchange = g_malloc0(sizeof(struct ClientKeyExchange_host) + server_certificate_length); @@ -859,22 +821,89 @@ static gboolean tls_server_hello(struct tls_internal_state *state) TLS_DATATYPE_PREMASTER_SECRET_LENGTH, state->premaster_secret.buffer, (guchar *) exchange->secret.placeholder)) { - /* TBD... error handling */ - SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: encryption of pre-master secret failed"); + SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: encryption of pre-master secret failed"); + g_free(exchange); + return(NULL); } + *cumulative_length += sizeof(struct ClientKeyExchange_host) + server_certificate_length; + return(exchange); +} + +/* + * TLS state handling + */ + +static gboolean tls_client_hello(struct tls_internal_state *state) +{ + guint32 now = time(NULL); + guint32 now_N = GUINT32_TO_BE(now); + struct ClientHello_host msg = { + { TLS_PROTOCOL_VERSION_1_0 }, + { 0, { } }, + { 0 /* empty SessionID */ }, + { 3, + { + TLS_RSA_WITH_RC4_128_MD5, + TLS_RSA_WITH_RC4_128_SHA, + TLS_RSA_EXPORT_WITH_RC4_40_MD5 + } + }, + { 1, + { + TLS_COMP_METHOD_NULL + } + } + }; + + /* First 4 bytes of client_random is the current timestamp */ + sipe_svc_fill_random(&state->client_random, + TLS_DATATYPE_RANDOM_LENGTH * 8); /* -> bits */ + memcpy(state->client_random.buffer, &now_N, sizeof(now_N)); + memcpy((guchar *) msg.random.random, state->client_random.buffer, + TLS_DATATYPE_RANDOM_LENGTH); + compile_msg(state, - sizeof(struct Certificate_host) + certificate_length + - sizeof(struct ClientKeyExchange_host) + server_certificate_length, - 2, - &Certificate_m, certificate, - &ClientKeyExchange_m, exchange); + sizeof(msg), + 1, + &ClientHello_m, &msg); + + if (sipe_backend_debug_enabled()) + state->debug = g_string_new(""); + + state->state = TLS_HANDSHAKE_STATE_SERVER_HELLO; + return(tls_record_parse(state, FALSE)); +} + +static gboolean tls_server_hello(struct tls_internal_state *state) +{ + struct Certificate_host *certificate = NULL; + struct ClientKeyExchange_host *exchange = NULL; + gsize length = 0; + gboolean success = FALSE; + + if (!tls_record_parse(state, TRUE)) + return(FALSE); + + if (((certificate = tls_client_certificate(state, &length)) != NULL) && + ((exchange = tls_client_key_exchange(state, &length)) != NULL)) { + + compile_msg(state, + length, + 2, + &Certificate_m, certificate, + &ClientKeyExchange_m, exchange); + + success = tls_record_parse(state, FALSE); + if (success) + state->state = TLS_HANDSHAKE_STATE_FINISHED; + } g_free(exchange); g_free(certificate); + free_parse_data(state); - state->state = TLS_HANDSHAKE_STATE_FINISHED; - return(tls_record_parse(state, FALSE)); + return(success); } static gboolean tls_finished(struct tls_internal_state *state) @@ -893,7 +922,9 @@ static gboolean tls_finished(struct tls_internal_state *state) return(TRUE); } -/* Public API */ +/* + * TLS public API + */ struct sipe_tls_state *sipe_tls_start(gpointer certificate) { -- 2.11.4.GIT