tls: add Client Certificate message
[siplcs.git] / src / core / sipe-tls.c
blob60d4c1b61f4a1e806ac8e3125c8e7ae9394de374
1 /**
2 * @file sipe-tls.c
4 * pidgin-sipe
6 * Copyright (C) 2011 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * TLS Protocol Version 1.0/1.1 - Handshake Messages
26 * TLS-DSK uses the handshake messages during authentication and session key
27 * exchange. This module *ONLY* implements this part of the TLS specification!
29 * Specification references:
31 * - RFC2246: http://www.ietf.org/rfc/rfc2246.txt
32 * - RFC3546: http://www.ietf.org/rfc/rfc3546.txt
33 * - RFC4346: http://www.ietf.org/rfc/rfc4346.txt
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
40 #include <glib.h>
42 #include "sipe-common.h"
43 #include "sipe-backend.h"
44 #include "sipe-cert-crypto.h"
45 #include "sipe-svc.h"
46 #include "sipe-tls.h"
49 * Private part of TLS state tracking
51 enum tls_handshake_state {
52 TLS_HANDSHAKE_STATE_START,
53 TLS_HANDSHAKE_STATE_SERVER_HELLO,
54 TLS_HANDSHAKE_STATE_FINISHED,
55 TLS_HANDSHAKE_STATE_COMPLETED,
56 TLS_HANDSHAKE_STATE_FAILED
59 struct tls_internal_state {
60 struct sipe_tls_state common;
61 gpointer certificate;
62 enum tls_handshake_state state;
63 guchar *msg_current;
64 gsize msg_remainder;
65 GHashTable *data;
66 GString *debug;
67 struct sipe_svc_random client_random;
68 struct sipe_svc_random server_random;
72 * TLS messages & layout descriptors
75 /* constants */
76 #define TLS_VECTOR_MAX8 255 /* 2^8 - 1 */
77 #define TLS_VECTOR_MAX16 65535 /* 2^16 - 1 */
78 #define TLS_VECTOR_MAX24 16777215 /* 2^24 - 1 */
80 #define TLS_DATATYPE_RANDOM_LENGTH 32
82 #define TLS_PROTOCOL_VERSION_1_0 0x0301
83 #define TLS_PROTOCOL_VERSION_1_1 0x0302
85 /* CipherSuites */
86 #define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003
87 #define TLS_RSA_WITH_RC4_128_MD5 0x0004
88 #define TLS_RSA_WITH_RC4_128_SHA 0x0005
90 /* CompressionMethods */
91 #define TLS_COMP_METHOD_NULL 0
93 #define TLS_RECORD_HEADER_LENGTH 5
94 #define TLS_RECORD_OFFSET_TYPE 0
95 #define TLS_RECORD_TYPE_HANDSHAKE 22
96 #define TLS_RECORD_OFFSET_VERSION 1
97 #define TLS_RECORD_OFFSET_LENGTH 3
99 #define TLS_HANDSHAKE_HEADER_LENGTH 4
100 #define TLS_HANDSHAKE_OFFSET_TYPE 0
101 #define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 1
102 #define TLS_HANDSHAKE_TYPE_SERVER_HELLO 2
103 #define TLS_HANDSHAKE_TYPE_CERTIFICATE 11
104 #define TLS_HANDSHAKE_TYPE_CERTIFICATE_REQ 13
105 #define TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE 14
106 #define TLS_HANDSHAKE_OFFSET_LENGTH 1
108 struct layout_descriptor;
109 typedef gboolean parse_func(struct tls_internal_state *state,
110 const struct layout_descriptor *desc);
112 /* Defines the strictest alignment requirement */
113 struct tls_compile_integer;
114 typedef void compile_func(struct tls_internal_state *state,
115 const struct layout_descriptor *desc,
116 const struct tls_compile_integer *data);
118 struct layout_descriptor {
119 const gchar *label;
120 parse_func *parser;
121 compile_func *compiler;
122 gsize min; /* 0 for fixed/array */
123 gsize max;
124 gsize offset;
127 #define TLS_LAYOUT_DESCRIPTOR_END { NULL, NULL, NULL, 0, 0, 0 }
128 #define TLS_LAYOUT_IS_VALID(desc) (desc->label)
130 struct msg_descriptor {
131 const struct msg_descriptor *next;
132 const gchar *description;
133 const struct layout_descriptor *layouts;
134 guint type;
137 /* parsed data */
138 struct tls_parsed_integer {
139 guint value;
142 struct tls_parsed_array {
143 gsize length; /* bytes */
144 const guchar data[0];
147 /* compile data */
148 struct tls_compile_integer {
149 gsize value;
152 struct tls_compile_array {
153 gsize elements; /* unused */
154 guchar placeholder[];
157 struct tls_compile_random {
158 gsize elements; /* unused */
159 guchar random[TLS_DATATYPE_RANDOM_LENGTH];
162 struct tls_compile_vector {
163 gsize elements; /* VECTOR */
164 guint placeholder[];
167 struct tls_compile_sessionid {
168 gsize elements; /* VECTOR */
171 struct tls_compile_cipher {
172 gsize elements; /* VECTOR */
173 guint suites[3];
176 struct tls_compile_compression {
177 gsize elements; /* VECTOR */
178 guint methods[1];
182 * TLS message debugging
184 static void debug_hex(struct tls_internal_state *state,
185 gsize alternative_length)
187 GString *str = state->debug;
188 const guchar *bytes;
189 gsize length;
190 gint count;
192 if (!str) return;
194 bytes = state->msg_current;
195 length = alternative_length ? alternative_length : state->msg_remainder;
196 count = -1;
198 while (length-- > 0) {
199 if (++count == 0) {
200 /* do nothing */;
201 } else if ((count % 16) == 0) {
202 g_string_append(str, "\n");
203 } else if ((count % 8) == 0) {
204 g_string_append(str, " ");
206 g_string_append_printf(str, " %02X", *bytes++);
208 g_string_append(str, "\n");
211 #define debug_print(state, string) \
212 if (state->debug) g_string_append(state->debug, string)
213 #define debug_printf(state, format, ...) \
214 if (state->debug) g_string_append_printf(state->debug, format, __VA_ARGS__)
217 * TLS data parsers
219 * Low-level data conversion routines
221 * - host alignment agnostic, i.e. can fetch a word from uneven address
222 * - TLS -> host endianess conversion
223 * - no length check, caller has to do it
224 * - don't modify state
226 static guint lowlevel_integer_to_host(const guchar *bytes,
227 gsize length)
229 guint sum = 0;
230 while (length--) sum = (sum << 8) + *bytes++;
231 return(sum);
235 * Generic data type parser routines
237 static gboolean msg_remainder_check(struct tls_internal_state *state,
238 const gchar *label,
239 gsize length)
241 if (length > state->msg_remainder) {
242 SIPE_DEBUG_ERROR("msg_remainder_check: '%s' expected %" G_GSIZE_FORMAT " bytes, remaining %" G_GSIZE_FORMAT,
243 label, length, state->msg_remainder);
244 return(FALSE);
246 return(TRUE);
249 static gboolean parse_integer_quiet(struct tls_internal_state *state,
250 const gchar *label,
251 gsize length,
252 guint *result)
254 if (!msg_remainder_check(state, label, length)) return(FALSE);
255 *result = lowlevel_integer_to_host(state->msg_current, length);
256 state->msg_current += length;
257 state->msg_remainder -= length;
258 return(TRUE);
261 static gboolean parse_integer(struct tls_internal_state *state,
262 const struct layout_descriptor *desc)
264 guint value;
265 if (!parse_integer_quiet(state, desc->label, desc->max, &value))
266 return(FALSE);
267 debug_printf(state, "%s/INTEGER%" G_GSIZE_FORMAT " = %d\n",
268 desc->label, desc->max, value);
269 if (state->data) {
270 struct tls_parsed_integer *save = g_new0(struct tls_parsed_integer, 1);
271 save->value = value;
272 g_hash_table_insert(state->data, (gpointer) desc->label, save);
274 return(TRUE);
277 static gboolean parse_array(struct tls_internal_state *state,
278 const struct layout_descriptor *desc)
280 if (!msg_remainder_check(state, desc->label, desc->max))
281 return(FALSE);
282 debug_printf(state, "%s/ARRAY[%" G_GSIZE_FORMAT "]\n",
283 desc->label, desc->max);
284 if (state->data) {
285 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
286 desc->max);
287 save->length = desc->max;
288 memcpy((guchar *)save->data, state->msg_current, desc->max);
289 g_hash_table_insert(state->data, (gpointer) desc->label, save);
292 state->msg_current += desc->max;
293 state->msg_remainder -= desc->max;
294 return(TRUE);
297 static gboolean parse_vector(struct tls_internal_state *state,
298 const struct layout_descriptor *desc)
300 guint length;
301 if (!parse_integer_quiet(state, desc->label,
302 (desc->max > TLS_VECTOR_MAX16) ? 3 :
303 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1,
304 &length))
305 return(FALSE);
306 if (length < desc->min) {
307 SIPE_DEBUG_ERROR("parse_vector: '%s' too short %d, expected %" G_GSIZE_FORMAT,
308 desc->label, length, desc->min);
309 return(FALSE);
311 debug_printf(state, "%s/VECTOR<%d>\n", desc->label, length);
312 if (state->data) {
313 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
314 length);
315 save->length = length;
316 memcpy((guchar *)save->data, state->msg_current, length);
317 g_hash_table_insert(state->data, (gpointer) desc->label, save);
319 state->msg_current += length;
320 state->msg_remainder -= length;
321 return(TRUE);
325 * Specific data type parser routines
328 /* TBD... */
331 * TLS data compilers
333 * Low-level data conversion routines
335 * - host alignment agnostic, i.e. can fetch a word from uneven address
336 * - host -> TLS host endianess conversion
337 * - don't modify state
339 static void lowlevel_integer_to_tls(guchar *bytes,
340 gsize length,
341 guint value)
343 while (length--) {
344 bytes[length] = value & 0xFF;
345 value >>= 8;
350 * Generic data type compiler routines
352 static void compile_integer(struct tls_internal_state *state,
353 const struct layout_descriptor *desc,
354 const struct tls_compile_integer *data)
356 lowlevel_integer_to_tls(state->msg_current, desc->max, data->value);
357 state->msg_current += desc->max;
358 state->msg_remainder += desc->max;
361 static void compile_array(struct tls_internal_state *state,
362 const struct layout_descriptor *desc,
363 const struct tls_compile_integer *data)
365 const struct tls_compile_array *array = (struct tls_compile_array *) data;
366 memcpy(state->msg_current, array->placeholder, desc->max);
367 state->msg_current += desc->max;
368 state->msg_remainder += desc->max;
371 static void compile_vector(struct tls_internal_state *state,
372 const struct layout_descriptor *desc,
373 const struct tls_compile_integer *data)
375 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
376 gsize length = vector->elements;
377 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
378 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
380 lowlevel_integer_to_tls(state->msg_current, length_field, length);
381 state->msg_current += length_field;
382 state->msg_remainder += length_field;
383 memcpy(state->msg_current, vector->placeholder, length);
384 state->msg_current += length;
385 state->msg_remainder += length;
388 static void compile_vector_int2(struct tls_internal_state *state,
389 const struct layout_descriptor *desc,
390 const struct tls_compile_integer *data)
392 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
393 gsize elements = vector->elements;
394 gsize length = elements * sizeof(guint16);
395 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
396 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
397 const guint *p = vector->placeholder;
399 lowlevel_integer_to_tls(state->msg_current, length_field, length);
400 state->msg_current += length_field;
401 state->msg_remainder += length_field;
402 while (elements--) {
403 lowlevel_integer_to_tls(state->msg_current, sizeof(guint16), *p++);
404 state->msg_current += sizeof(guint16);
405 state->msg_remainder += sizeof(guint16);
410 * Specific data type compiler routines
413 /* TBD... */
416 * TLS handshake message layout descriptors
418 struct ClientHello_host {
419 const struct tls_compile_integer protocol_version;
420 const struct tls_compile_random random;
421 const struct tls_compile_sessionid sessionid;
422 const struct tls_compile_cipher cipher;
423 const struct tls_compile_compression compression;
425 #define CLIENTHELLO_OFFSET(a) offsetof(struct ClientHello_host, a)
427 static const struct layout_descriptor const ClientHello_l[] = {
428 { "Client Protocol Version", parse_integer, compile_integer, 0, 2, CLIENTHELLO_OFFSET(protocol_version) },
429 { "Random", parse_array, compile_array, 0, TLS_DATATYPE_RANDOM_LENGTH, CLIENTHELLO_OFFSET(random) },
430 { "SessionID", parse_vector, compile_vector, 0, 32, CLIENTHELLO_OFFSET(sessionid) },
431 { "CipherSuite", parse_vector, compile_vector_int2, 2, TLS_VECTOR_MAX16, CLIENTHELLO_OFFSET(cipher)},
432 { "CompressionMethod", parse_vector, compile_vector, 1, TLS_VECTOR_MAX8, CLIENTHELLO_OFFSET(compression) },
433 TLS_LAYOUT_DESCRIPTOR_END
435 static const struct msg_descriptor const ClientHello_m = {
436 NULL, "Client Hello", ClientHello_l, TLS_HANDSHAKE_TYPE_CLIENT_HELLO
439 static const struct layout_descriptor const ServerHello_l[] = {
440 { "Server Protocol Version", parse_integer, NULL, 0, 2, 0 },
441 { "Random", parse_array, NULL, 0, TLS_DATATYPE_RANDOM_LENGTH, 0 },
442 { "SessionID", parse_vector, NULL, 0, 32, 0 },
443 { "CipherSuite", parse_integer, NULL, 0, 2, 0 },
444 { "CompressionMethod", parse_integer, NULL, 0, 1, 0 },
445 TLS_LAYOUT_DESCRIPTOR_END
447 static const struct msg_descriptor const ServerHello_m = {
448 &ClientHello_m, "Server Hello", ServerHello_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO
451 struct Certificate_host {
452 struct tls_compile_vector certificate;
454 #define CERTIFICATE_OFFSET(a) offsetof(struct Certificate_host, a)
456 static const struct layout_descriptor const Certificate_l[] = {
457 { "Certificate", parse_vector, compile_vector, 0, TLS_VECTOR_MAX24, CERTIFICATE_OFFSET(certificate) },
458 TLS_LAYOUT_DESCRIPTOR_END
460 static const struct msg_descriptor const Certificate_m = {
461 &ServerHello_m, "Certificate", Certificate_l, TLS_HANDSHAKE_TYPE_CERTIFICATE
464 static const struct layout_descriptor const CertificateRequest_l[] = {
465 { "CertificateType", parse_vector, NULL, 1, TLS_VECTOR_MAX8, 0 },
466 { "DistinguishedName", parse_vector, NULL, 0, TLS_VECTOR_MAX16, 0 },
467 TLS_LAYOUT_DESCRIPTOR_END
469 static const struct msg_descriptor const CertificateRequest_m = {
470 &Certificate_m, "Certificate Request", CertificateRequest_l, TLS_HANDSHAKE_TYPE_CERTIFICATE_REQ
473 static const struct layout_descriptor const ServerHelloDone_l[] = {
474 TLS_LAYOUT_DESCRIPTOR_END
476 static const struct msg_descriptor const ServerHelloDone_m = {
477 &CertificateRequest_m, "Server Hello Done", ServerHelloDone_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE
480 #define HANDSHAKE_MSG_DESCRIPTORS &ServerHelloDone_m
483 * TLS message parsers
485 static gboolean handshake_parse(struct tls_internal_state *state)
487 const guchar *bytes = state->msg_current;
488 gsize length = state->msg_remainder;
489 gboolean success = FALSE;
491 while (length > 0) {
492 const struct msg_descriptor *desc;
493 gsize msg_length;
494 guint msg_type;
496 /* header check */
497 if (length < TLS_HANDSHAKE_HEADER_LENGTH) {
498 debug_print(state, "CORRUPTED HANDSHAKE HEADER");
499 break;
502 /* msg length check */
503 msg_length = lowlevel_integer_to_host(bytes + TLS_HANDSHAKE_OFFSET_LENGTH,
505 if (msg_length > length) {
506 debug_print(state, "HANDSHAKE MESSAGE TOO LONG");
507 break;
510 /* msg type */
511 msg_type = bytes[TLS_HANDSHAKE_OFFSET_TYPE];
512 for (desc = HANDSHAKE_MSG_DESCRIPTORS;
513 desc;
514 desc = desc->next)
515 if (msg_type == desc->type)
516 break;
518 debug_printf(state, "TLS handshake (%" G_GSIZE_FORMAT " bytes) (%d)",
519 msg_length, msg_type);
521 state->msg_current = (guchar *) bytes + TLS_HANDSHAKE_HEADER_LENGTH;
522 state->msg_remainder = msg_length;
524 if (desc->layouts) {
525 const struct layout_descriptor *ldesc = desc->layouts;
527 debug_printf(state, "%s\n", desc->description);
528 while (TLS_LAYOUT_IS_VALID(ldesc)) {
529 success = ldesc->parser(state, ldesc);
530 if (!success)
531 break;
532 ldesc++;
534 if (!success)
535 break;
536 } else {
537 debug_print(state, "ignored\n");
538 debug_hex(state, 0);
541 /* next message */
542 bytes += TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
543 length -= TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
544 if (length > 0) {
545 debug_print(state, "------\n");
546 } else {
547 success = TRUE;
551 return(success);
554 static void free_parse_data(struct tls_internal_state *state)
556 if (state->data) {
557 g_hash_table_destroy(state->data);
558 state->data = NULL;
562 /* NOTE: we don't support record fragmentation */
563 static gboolean tls_record_parse(struct tls_internal_state *state,
564 gboolean incoming)
566 const guchar *bytes = incoming ? state->common.in_buffer : state->common.out_buffer;
567 gsize length = incoming ? state->common.in_length : state->common.out_length;
568 guint version;
569 const gchar *version_str;
570 gsize record_length;
571 gboolean success = FALSE;
573 debug_printf(state, "TLS MESSAGE %s\n", incoming ? "INCOMING" : "OUTGOING");
575 /* truncated header check */
576 if (length < TLS_RECORD_HEADER_LENGTH) {
577 SIPE_DEBUG_ERROR("tls_record_parse: too short TLS record header (%" G_GSIZE_FORMAT " bytes)",
578 length);
579 return(FALSE);
582 /* protocol version check */
583 version = lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_VERSION, 2);
584 if (version < TLS_PROTOCOL_VERSION_1_0) {
585 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: SSL1/2/3 not supported");
586 return(FALSE);
588 switch (version) {
589 case TLS_PROTOCOL_VERSION_1_0:
590 version_str = "1.0 (RFC2246)";
591 break;
592 case TLS_PROTOCOL_VERSION_1_1:
593 version_str = "1.1 (RFC4346)";
594 break;
595 default:
596 version_str = "<future protocol version>";
597 break;
600 /* record length check */
601 record_length = TLS_RECORD_HEADER_LENGTH +
602 lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_LENGTH, 2);
603 if (record_length > length) {
604 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: record too long");
605 return(FALSE);
608 /* TLS record header OK */
609 debug_printf(state, "TLS %s record (%" G_GSIZE_FORMAT " bytes)\n",
610 version_str, length);
611 state->msg_current = (guchar *) bytes + TLS_RECORD_HEADER_LENGTH;
612 state->msg_remainder = length - TLS_RECORD_HEADER_LENGTH;
614 /* Collect parser data for incoming messages */
615 if (incoming)
616 state->data = g_hash_table_new_full(g_str_hash, g_str_equal,
617 NULL, g_free);
619 switch (bytes[TLS_RECORD_OFFSET_TYPE]) {
620 case TLS_RECORD_TYPE_HANDSHAKE:
621 success = handshake_parse(state);
622 break;
624 default:
625 debug_print(state, "Unsupported TLS message\n");
626 debug_hex(state, 0);
627 break;
630 if (!success)
631 free_parse_data(state);
633 if (state->debug) {
634 SIPE_DEBUG_INFO_NOFORMAT(state->debug->str);
635 g_string_truncate(state->debug, 0);
638 return(success);
642 * TLS message compiler
644 static void compile_msg(struct tls_internal_state *state,
645 gsize size,
646 gsize messages,
647 ...)
650 * Estimate the size of the compiled message
652 * The data structures in the host format have zero or more padding
653 * bytes added by the compiler to ensure correct element alignments.
654 * So the sizeof() of the data structure is always equal or greater
655 * than the space needed for the compiled data. By adding the space
656 * required for the headers we arrive at a safe estimate
658 * Therefore we don't need space checks in the compiler functions
660 gsize total_size = size +
661 TLS_RECORD_HEADER_LENGTH +
662 TLS_HANDSHAKE_HEADER_LENGTH * messages;
663 guchar *buffer = g_malloc0(total_size);
664 va_list ap;
666 SIPE_DEBUG_INFO("compile_msg: buffer size %" G_GSIZE_FORMAT,
667 total_size);
669 state->msg_current = buffer + TLS_RECORD_HEADER_LENGTH;
670 state->msg_remainder = 0;
672 va_start(ap, messages);
673 while (messages--) {
674 const struct msg_descriptor *desc = va_arg(ap, struct msg_descriptor *);
675 const guchar *data = va_arg(ap, gpointer);
676 const struct layout_descriptor *ldesc = desc->layouts;
677 guchar *handshake = state->msg_current;
678 gsize length;
680 /* add TLS handshake header */
681 handshake[TLS_HANDSHAKE_OFFSET_TYPE] = desc->type;
682 state->msg_current += TLS_HANDSHAKE_HEADER_LENGTH;
683 state->msg_remainder += TLS_HANDSHAKE_HEADER_LENGTH;
685 while (TLS_LAYOUT_IS_VALID(ldesc)) {
687 * Avoid "cast increases required alignment" errors
689 * (void *) tells the compiler that we know what we're
690 * doing, i.e. we know that the calculated address
691 * points to correctly aligned data.
693 ldesc->compiler(state, ldesc,
694 (void *) (data + ldesc->offset));
695 ldesc++;
698 length = state->msg_current - handshake - TLS_HANDSHAKE_HEADER_LENGTH;
699 lowlevel_integer_to_tls(handshake + TLS_HANDSHAKE_OFFSET_LENGTH,
700 3, length);
701 SIPE_DEBUG_INFO("compile_msg: (%d)%s, size %" G_GSIZE_FORMAT,
702 desc->type, desc->description, length);
706 va_end(ap);
708 /* add TLS record header */
709 buffer[TLS_RECORD_OFFSET_TYPE] = TLS_RECORD_TYPE_HANDSHAKE;
710 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_VERSION, 2,
711 TLS_PROTOCOL_VERSION_1_0);
712 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_LENGTH, 2,
713 state->msg_remainder);
715 state->common.out_buffer = buffer;
716 state->common.out_length = state->msg_remainder + TLS_RECORD_HEADER_LENGTH;
718 SIPE_DEBUG_INFO("compile_msg: compiled size %" G_GSIZE_FORMAT,
719 state->common.out_length);
722 static gboolean tls_client_hello(struct tls_internal_state *state)
724 guint32 now = time(NULL);
725 guint32 now_N = GUINT32_TO_BE(now);
726 struct ClientHello_host msg = {
727 { TLS_PROTOCOL_VERSION_1_0 },
728 { 0, { } },
729 { 0 /* empty SessionID */ },
730 { 3,
732 TLS_RSA_WITH_RC4_128_MD5,
733 TLS_RSA_WITH_RC4_128_SHA,
734 TLS_RSA_EXPORT_WITH_RC4_40_MD5
737 { 1,
739 TLS_COMP_METHOD_NULL
744 /* First 4 bytes of client_random is the current timestamp */
745 sipe_svc_fill_random(&state->client_random,
746 TLS_DATATYPE_RANDOM_LENGTH * 8); /* -> bits */
747 memcpy(state->client_random.buffer, &now_N, sizeof(now_N));
748 memcpy((guchar *) msg.random.random, state->client_random.buffer,
749 TLS_DATATYPE_RANDOM_LENGTH);
751 compile_msg(state,
752 sizeof(msg),
754 &ClientHello_m, &msg);
756 if (sipe_backend_debug_enabled())
757 state->debug = g_string_new("");
759 state->state = TLS_HANDSHAKE_STATE_SERVER_HELLO;
760 return(tls_record_parse(state, FALSE));
763 static gboolean tls_server_hello(struct tls_internal_state *state)
765 struct tls_parsed_array *server_random;
766 struct Certificate_host *certificate;
767 gsize certificate_length = sipe_cert_crypto_raw_length(state->certificate);
769 if (!tls_record_parse(state, TRUE))
770 return(FALSE);
772 /* check for required data fields */
773 server_random = g_hash_table_lookup(state->data, "Random");
774 if (!server_random) {
775 SIPE_DEBUG_ERROR_NOFORMAT("tls_server_hello: no server random");
776 return(FALSE);
779 /* found all the required fields */
780 state->server_random.length = server_random->length;
781 state->server_random.buffer = g_memdup(server_random->data,
782 server_random->length);
784 /* done with parsed data */
785 free_parse_data(state);
787 /* setup our response */
788 certificate = g_malloc0(sizeof(struct Certificate_host) +
789 certificate_length);
790 certificate->certificate.elements = certificate_length;
791 memcpy(certificate->certificate.placeholder,
792 sipe_cert_crypto_raw(state->certificate),
793 certificate_length);
795 compile_msg(state,
796 sizeof(struct Certificate_host) +
797 certificate_length,
799 &Certificate_m, certificate);
801 g_free(certificate);
803 state->state = TLS_HANDSHAKE_STATE_FINISHED;
804 return(tls_record_parse(state, FALSE));
807 static gboolean tls_finished(struct tls_internal_state *state)
809 if (!tls_record_parse(state, TRUE))
810 return(FALSE);
812 /* TBD: data is really not needed? */
813 free_parse_data(state);
815 state->common.out_buffer = NULL;
816 state->common.out_length = 0;
817 state->state = TLS_HANDSHAKE_STATE_COMPLETED;
819 /* temporary */
820 return(TRUE);
823 /* Public API */
825 struct sipe_tls_state *sipe_tls_start(gpointer certificate)
827 struct tls_internal_state *state;
829 if (!certificate)
830 return(NULL);
832 state = g_new0(struct tls_internal_state, 1);
833 state->certificate = certificate;
834 state->state = TLS_HANDSHAKE_STATE_START;
836 return((struct sipe_tls_state *) state);
839 gboolean sipe_tls_next(struct sipe_tls_state *state)
841 struct tls_internal_state *internal = (struct tls_internal_state *) state;
842 gboolean success = FALSE;
844 if (!state)
845 return(FALSE);
847 state->out_buffer = NULL;
849 switch (internal->state) {
850 case TLS_HANDSHAKE_STATE_START:
851 success = tls_client_hello(internal);
852 break;
854 case TLS_HANDSHAKE_STATE_SERVER_HELLO:
855 success = tls_server_hello(internal);
856 break;
858 case TLS_HANDSHAKE_STATE_FINISHED:
859 success = tls_finished(internal);
860 break;
862 case TLS_HANDSHAKE_STATE_COMPLETED:
863 case TLS_HANDSHAKE_STATE_FAILED:
864 /* This should not happen */
865 SIPE_DEBUG_ERROR_NOFORMAT("sipe_tls_next: called in incorrect state!");
866 break;
869 if (!success) {
870 internal->state = TLS_HANDSHAKE_STATE_FAILED;
873 return(success);
876 void sipe_tls_free(struct sipe_tls_state *state)
878 if (state) {
879 struct tls_internal_state *internal = (struct tls_internal_state *) state;
881 free_parse_data(internal);
882 if (internal->debug)
883 g_string_free(internal->debug, TRUE);
884 sipe_svc_free_random(&internal->client_random);
885 g_free(internal->server_random.buffer);
886 g_free(state->session_key);
887 g_free(state->out_buffer);
888 g_free(state);
893 Local Variables:
894 mode: c
895 c-file-style: "bsd"
896 indent-tabs-mode: t
897 tab-width: 8
898 End: