tls: first crack at generic message compiler
[siplcs.git] / src / core / sipe-tls.c
blob30046af9b1dcdc1cd72249648c3932395534ed96
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_TYPE_FIXED 0x00
77 #define TLS_TYPE_ARRAY 0x01
78 #define TLS_TYPE_VECTOR 0x02
80 #define TLS_VECTOR_MAX8 255 /* 2^8 - 1 */
81 #define TLS_VECTOR_MAX16 65535 /* 2^16 - 1 */
82 #define TLS_VECTOR_MAX24 16777215 /* 2^24 - 1 */
84 #define TLS_DATATYPE_RANDOM_LENGTH 32
86 #define TLS_PROTOCOL_VERSION_1_0 0x0301
87 #define TLS_PROTOCOL_VERSION_1_1 0x0302
89 /* CipherSuites */
90 #define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003
91 #define TLS_RSA_WITH_RC4_128_MD5 0x0004
92 #define TLS_RSA_WITH_RC4_128_SHA 0x0005
94 /* CompressionMethods */
95 #define TLS_COMP_METHOD_NULL 0
97 #define TLS_RECORD_HEADER_LENGTH 5
98 #define TLS_RECORD_OFFSET_TYPE 0
99 #define TLS_RECORD_TYPE_HANDSHAKE 22
100 #define TLS_RECORD_OFFSET_VERSION 1
101 #define TLS_RECORD_OFFSET_LENGTH 3
103 #define TLS_HANDSHAKE_HEADER_LENGTH 4
104 #define TLS_HANDSHAKE_OFFSET_TYPE 0
105 #define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 1
106 #define TLS_HANDSHAKE_TYPE_SERVER_HELLO 2
107 #define TLS_HANDSHAKE_TYPE_CERTIFICATE 11
108 #define TLS_HANDSHAKE_TYPE_CERTIFICATE_REQ 13
109 #define TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE 14
110 #define TLS_HANDSHAKE_OFFSET_LENGTH 1
112 struct layout_descriptor;
113 typedef gboolean parse_func(struct tls_internal_state *state,
114 const struct layout_descriptor *desc);
116 /* Defines the strictest alignment requirement */
117 struct tls_compile_integer;
118 typedef void compile_func(struct tls_internal_state *state,
119 const struct layout_descriptor *desc,
120 const struct tls_compile_integer *data);
122 struct layout_descriptor {
123 const gchar *label;
124 parse_func *parser;
125 compile_func *compiler;
126 guint type;
127 gsize min; /* 0 for fixed/array */
128 gsize max;
129 gsize offset;
132 #define TLS_LAYOUT_DESCRIPTOR_END { NULL, NULL, NULL, 0, 0, 0, 0 }
133 #define TLS_LAYOUT_IS_VALID(desc) (desc->label)
135 struct msg_descriptor {
136 const struct msg_descriptor *next;
137 const gchar *description;
138 const struct layout_descriptor *layouts;
139 guint type;
142 /* parsed data */
143 struct tls_parsed_integer {
144 guint value;
147 struct tls_parsed_array {
148 gsize length; /* bytes */
149 const guchar data[0];
152 /* compile data */
153 struct tls_compile_integer {
154 gsize value;
157 struct tls_compile_array {
158 gsize elements; /* unused */
159 guchar placeholder[];
162 struct tls_compile_random {
163 gsize elements; /* unused */
164 guchar random[TLS_DATATYPE_RANDOM_LENGTH];
167 struct tls_compile_vector {
168 gsize elements; /* VECTOR */
169 guint placeholder[];
172 struct tls_compile_sessionid {
173 gsize elements; /* VECTOR */
176 struct tls_compile_cipher {
177 gsize elements; /* VECTOR */
178 guint suites[3];
181 struct tls_compile_compression {
182 gsize elements; /* VECTOR */
183 guint methods[1];
187 * TLS message debugging
189 static void debug_hex(struct tls_internal_state *state,
190 gsize alternative_length)
192 GString *str = state->debug;
193 const guchar *bytes;
194 gsize length;
195 gint count;
197 if (!str) return;
199 bytes = state->msg_current;
200 length = alternative_length ? alternative_length : state->msg_remainder;
201 count = -1;
203 while (length-- > 0) {
204 if (++count == 0) {
205 /* do nothing */;
206 } else if ((count % 16) == 0) {
207 g_string_append(str, "\n");
208 } else if ((count % 8) == 0) {
209 g_string_append(str, " ");
211 g_string_append_printf(str, " %02X", *bytes++);
213 g_string_append(str, "\n");
216 #define debug_print(state, string) \
217 if (state->debug) g_string_append(state->debug, string)
218 #define debug_printf(state, format, ...) \
219 if (state->debug) g_string_append_printf(state->debug, format, __VA_ARGS__)
222 * TLS data parsers
224 * Low-level data conversion routines
226 * - host alignment agnostic, i.e. can fetch a word from uneven address
227 * - TLS -> host endianess conversion
228 * - no length check, caller has to do it
229 * - don't modify state
231 static guint lowlevel_integer_to_host(const guchar *bytes,
232 gsize length)
234 guint sum = 0;
235 while (length--) sum = (sum << 8) + *bytes++;
236 return(sum);
240 * Generic data type parser routines
242 static gboolean msg_remainder_check(struct tls_internal_state *state,
243 const gchar *label,
244 gsize length)
246 if (length > state->msg_remainder) {
247 SIPE_DEBUG_ERROR("msg_remainder_check: '%s' expected %" G_GSIZE_FORMAT " bytes, remaining %" G_GSIZE_FORMAT,
248 label, length, state->msg_remainder);
249 return(FALSE);
251 return(TRUE);
254 static gboolean parse_integer_quiet(struct tls_internal_state *state,
255 const gchar *label,
256 gsize length,
257 guint *result)
259 if (!msg_remainder_check(state, label, length)) return(FALSE);
260 *result = lowlevel_integer_to_host(state->msg_current, length);
261 state->msg_current += length;
262 state->msg_remainder -= length;
263 return(TRUE);
266 static gboolean parse_integer(struct tls_internal_state *state,
267 const gchar *label,
268 gsize length)
270 guint value;
271 if (!parse_integer_quiet(state, label, length, &value)) return(FALSE);
272 debug_printf(state, "%s/INTEGER%" G_GSIZE_FORMAT " = %d\n",
273 label, length, value);
274 if (state->data) {
275 struct tls_parsed_integer *save = g_new0(struct tls_parsed_integer, 1);
276 save->value = value;
277 g_hash_table_insert(state->data, (gpointer) label, save);
279 return(TRUE);
282 static gboolean parse_array(struct tls_internal_state *state,
283 const gchar *label,
284 gsize length)
286 if (!msg_remainder_check(state, label, length)) return(FALSE);
287 debug_printf(state, "%s/ARRAY[%" G_GSIZE_FORMAT "]\n",
288 label, length);
289 if (state->data) {
290 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
291 length);
292 save->length = length;
293 memcpy((guchar *)save->data, state->msg_current, length);
294 g_hash_table_insert(state->data, (gpointer) label, save);
297 state->msg_current += length;
298 state->msg_remainder -= length;
299 return(TRUE);
302 static gboolean parse_vector(struct tls_internal_state *state,
303 const gchar *label,
304 gsize min,
305 gsize max)
307 guint length;
308 if (!parse_integer_quiet(state, label,
309 (max > TLS_VECTOR_MAX16) ? 3 :
310 (max > TLS_VECTOR_MAX8) ? 2 : 1,
311 &length))
312 return(FALSE);
313 if (length < min) {
314 SIPE_DEBUG_ERROR("parse_vector: '%s' too short %d, expected %" G_GSIZE_FORMAT,
315 label, length, min);
316 return(FALSE);
318 debug_printf(state, "%s/VECTOR<%d>\n", label, length);
319 if (state->data) {
320 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
321 length);
322 save->length = length;
323 memcpy((guchar *)save->data, state->msg_current, length);
324 g_hash_table_insert(state->data, (gpointer) label, save);
326 state->msg_current += length;
327 state->msg_remainder -= length;
328 return(TRUE);
332 * Specific data type parser routines
335 /* TBD... */
338 * TLS data compilers
340 * Low-level data conversion routines
342 * - host alignment agnostic, i.e. can fetch a word from uneven address
343 * - host -> TLS host endianess conversion
344 * - don't modify state
346 static void lowlevel_integer_to_tls(guchar *bytes,
347 gsize length,
348 guint value)
350 while (length--) {
351 bytes[length] = value & 0xFF;
352 value >>= 8;
357 * Generic data type compiler routines
359 static void compile_integer(struct tls_internal_state *state,
360 const struct layout_descriptor *desc,
361 const struct tls_compile_integer *data)
363 lowlevel_integer_to_tls(state->msg_current, desc->max, data->value);
364 state->msg_current += desc->max;
365 state->msg_remainder += desc->max;
368 static void compile_array(struct tls_internal_state *state,
369 const struct layout_descriptor *desc,
370 const struct tls_compile_integer *data)
372 const struct tls_compile_array *array = (struct tls_compile_array *) data;
373 memcpy(state->msg_current, array->placeholder, desc->max);
374 state->msg_current += desc->max;
375 state->msg_remainder += desc->max;
378 static void compile_vector(struct tls_internal_state *state,
379 const struct layout_descriptor *desc,
380 const struct tls_compile_integer *data)
382 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
383 gsize length = vector->elements;
384 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
385 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
387 lowlevel_integer_to_tls(state->msg_current, length_field, length);
388 state->msg_current += length_field;
389 state->msg_remainder += length_field;
390 memcpy(state->msg_current, vector->placeholder, length);
391 state->msg_current += length;
392 state->msg_remainder += length;
395 static void compile_vector_int2(struct tls_internal_state *state,
396 const struct layout_descriptor *desc,
397 const struct tls_compile_integer *data)
399 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
400 gsize elements = vector->elements;
401 gsize length = elements * sizeof(guint16);
402 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
403 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
404 const guint *p = vector->placeholder;
406 lowlevel_integer_to_tls(state->msg_current, length_field, length);
407 state->msg_current += length_field;
408 state->msg_remainder += length_field;
409 while (elements--) {
410 lowlevel_integer_to_tls(state->msg_current, sizeof(guint16), *p++);
411 state->msg_current += sizeof(guint16);
412 state->msg_remainder += sizeof(guint16);
417 * Specific data type compiler routines
420 /* TBD... */
423 * TLS handshake message layout descriptors
425 struct ClientHello_host {
426 const struct tls_compile_integer protocol_version;
427 const struct tls_compile_random random;
428 const struct tls_compile_sessionid sessionid;
429 const struct tls_compile_cipher cipher;
430 const struct tls_compile_compression compression;
432 #define CLIENTHELLO_OFFSET(a) offsetof(struct ClientHello_host, a)
434 static const struct layout_descriptor const ClientHello_l[] = {
435 { "Client Protocol Version", NULL, compile_integer, TLS_TYPE_FIXED, 0, 2, CLIENTHELLO_OFFSET(protocol_version) },
436 { "Random", NULL, compile_array, TLS_TYPE_ARRAY, 0, TLS_DATATYPE_RANDOM_LENGTH, CLIENTHELLO_OFFSET(random) },
437 { "SessionID", NULL, compile_vector, TLS_TYPE_VECTOR, 0, 32, CLIENTHELLO_OFFSET(sessionid) },
438 { "CipherSuite", NULL, compile_vector_int2, TLS_TYPE_VECTOR, 2, TLS_VECTOR_MAX16, CLIENTHELLO_OFFSET(cipher)},
439 { "CompressionMethod", NULL, compile_vector, TLS_TYPE_VECTOR, 1, TLS_VECTOR_MAX8, CLIENTHELLO_OFFSET(compression) },
440 TLS_LAYOUT_DESCRIPTOR_END
442 static const struct msg_descriptor const ClientHello_m = {
443 NULL, "Client Hello", ClientHello_l, TLS_HANDSHAKE_TYPE_CLIENT_HELLO
446 static const struct layout_descriptor const ServerHello_l[] = {
447 { "Server Protocol Version", NULL, NULL, TLS_TYPE_FIXED, 0, 2, 0 },
448 { "Random", NULL, NULL, TLS_TYPE_ARRAY, 0, TLS_DATATYPE_RANDOM_LENGTH, 0 },
449 { "SessionID", NULL, NULL, TLS_TYPE_VECTOR, 0, 32, 0 },
450 { "CipherSuite", NULL, NULL, TLS_TYPE_FIXED, 0, 2, 0 },
451 { "CompressionMethod", NULL, NULL, TLS_TYPE_FIXED, 0, 1, 0 },
452 TLS_LAYOUT_DESCRIPTOR_END
454 static const struct msg_descriptor const ServerHello_m = {
455 &ClientHello_m, "Server Hello", ServerHello_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO
458 static const struct layout_descriptor const Certificate_l[] = {
459 { "Certificate", NULL, NULL, TLS_TYPE_VECTOR, 0, TLS_VECTOR_MAX24, 0 },
460 TLS_LAYOUT_DESCRIPTOR_END
462 static const struct msg_descriptor const Certificate_m = {
463 &ServerHello_m, "Certificate", Certificate_l, TLS_HANDSHAKE_TYPE_CERTIFICATE
466 static const struct layout_descriptor const CertificateRequest_l[] = {
467 { "CertificateType", NULL, NULL, TLS_TYPE_VECTOR, 1, TLS_VECTOR_MAX8, 0 },
468 { "DistinguishedName", NULL, NULL, TLS_TYPE_VECTOR, 0, TLS_VECTOR_MAX16, 0 },
469 TLS_LAYOUT_DESCRIPTOR_END
471 static const struct msg_descriptor const CertificateRequest_m = {
472 &Certificate_m, "Certificate Request", CertificateRequest_l, TLS_HANDSHAKE_TYPE_CERTIFICATE_REQ
475 static const struct layout_descriptor const ServerHelloDone_l[] = {
476 TLS_LAYOUT_DESCRIPTOR_END
478 static const struct msg_descriptor const ServerHelloDone_m = {
479 &CertificateRequest_m, "Server Hello Done", ServerHelloDone_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE
482 #define HANDSHAKE_MSG_DESCRIPTORS &ServerHelloDone_m
485 * TLS message parsers
487 static gboolean generic_parser(struct tls_internal_state *state,
488 const struct layout_descriptor *desc)
490 while (TLS_LAYOUT_IS_VALID(desc)) {
492 /* Special parser */
493 if (desc->parser) {
494 /* TBD... */
496 /* Generic parser */
497 } else {
498 gboolean success;
500 switch (desc->type) {
501 case TLS_TYPE_FIXED:
502 success = parse_integer(state, desc->label, desc->max);
503 break;
505 case TLS_TYPE_ARRAY:
506 success = parse_array(state, desc->label, desc->max);
507 break;
509 case TLS_TYPE_VECTOR:
510 success = parse_vector(state, desc->label, desc->min, desc->max);
511 break;
513 default:
514 SIPE_DEBUG_ERROR("generic_parser: unknown descriptor type %d",
515 desc->type);
516 success = FALSE;
517 break;
520 if (!success)
521 return(FALSE);
524 /* next field */
525 desc++;
528 return(TRUE);
531 static gboolean handshake_parse(struct tls_internal_state *state)
533 const guchar *bytes = state->msg_current;
534 gsize length = state->msg_remainder;
535 gboolean success = FALSE;
537 while (length > 0) {
538 const struct msg_descriptor *desc;
539 gsize msg_length;
540 guint msg_type;
542 /* header check */
543 if (length < TLS_HANDSHAKE_HEADER_LENGTH) {
544 debug_print(state, "CORRUPTED HANDSHAKE HEADER");
545 break;
548 /* msg length check */
549 msg_length = lowlevel_integer_to_host(bytes + TLS_HANDSHAKE_OFFSET_LENGTH,
551 if (msg_length > length) {
552 debug_print(state, "HANDSHAKE MESSAGE TOO LONG");
553 break;
556 /* msg type */
557 msg_type = bytes[TLS_HANDSHAKE_OFFSET_TYPE];
558 for (desc = HANDSHAKE_MSG_DESCRIPTORS;
559 desc;
560 desc = desc->next)
561 if (msg_type == desc->type)
562 break;
564 debug_printf(state, "TLS handshake (%" G_GSIZE_FORMAT " bytes) (%d)",
565 msg_length, msg_type);
567 state->msg_current = (guchar *) bytes + TLS_HANDSHAKE_HEADER_LENGTH;
568 state->msg_remainder = msg_length;
570 if (desc->layouts) {
571 debug_printf(state, "%s\n", desc->description);
572 success = generic_parser(state, desc->layouts);
573 if (!success)
574 break;
575 } else {
576 debug_print(state, "ignored\n");
577 debug_hex(state, 0);
580 /* next message */
581 bytes += TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
582 length -= TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
583 if (length > 0) {
584 debug_print(state, "------\n");
585 } else {
586 success = TRUE;
590 return(success);
593 static void free_parse_data(struct tls_internal_state *state)
595 if (state->data) {
596 g_hash_table_destroy(state->data);
597 state->data = NULL;
601 /* NOTE: we don't support record fragmentation */
602 static gboolean tls_record_parse(struct tls_internal_state *state,
603 gboolean incoming)
605 const guchar *bytes = incoming ? state->common.in_buffer : state->common.out_buffer;
606 gsize length = incoming ? state->common.in_length : state->common.out_length;
607 guint version;
608 const gchar *version_str;
609 gsize record_length;
610 gboolean success = FALSE;
612 debug_printf(state, "TLS MESSAGE %s\n", incoming ? "INCOMING" : "OUTGOING");
614 /* truncated header check */
615 if (length < TLS_RECORD_HEADER_LENGTH) {
616 SIPE_DEBUG_ERROR("tls_record_parse: too short TLS record header (%" G_GSIZE_FORMAT " bytes)",
617 length);
618 return(FALSE);
621 /* protocol version check */
622 version = lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_VERSION, 2);
623 if (version < TLS_PROTOCOL_VERSION_1_0) {
624 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: SSL1/2/3 not supported");
625 return(FALSE);
627 switch (version) {
628 case TLS_PROTOCOL_VERSION_1_0:
629 version_str = "1.0 (RFC2246)";
630 break;
631 case TLS_PROTOCOL_VERSION_1_1:
632 version_str = "1.1 (RFC4346)";
633 break;
634 default:
635 version_str = "<future protocol version>";
636 break;
639 /* record length check */
640 record_length = TLS_RECORD_HEADER_LENGTH +
641 lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_LENGTH, 2);
642 if (record_length > length) {
643 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: record too long");
644 return(FALSE);
647 /* TLS record header OK */
648 debug_printf(state, "TLS %s record (%" G_GSIZE_FORMAT " bytes)\n",
649 version_str, length);
650 state->msg_current = (guchar *) bytes + TLS_RECORD_HEADER_LENGTH;
651 state->msg_remainder = length - TLS_RECORD_HEADER_LENGTH;
653 /* Collect parser data for incoming messages */
654 if (incoming)
655 state->data = g_hash_table_new_full(g_str_hash, g_str_equal,
656 NULL, g_free);
658 switch (bytes[TLS_RECORD_OFFSET_TYPE]) {
659 case TLS_RECORD_TYPE_HANDSHAKE:
660 success = handshake_parse(state);
661 break;
663 default:
664 debug_print(state, "Unsupported TLS message\n");
665 debug_hex(state, 0);
666 break;
669 if (!success)
670 free_parse_data(state);
672 if (state->debug) {
673 SIPE_DEBUG_INFO_NOFORMAT(state->debug->str);
674 g_string_truncate(state->debug, 0);
677 return(success);
681 * TLS message compiler
683 static void compile_msg(struct tls_internal_state *state,
684 gsize size,
685 gsize messages,
686 ...)
688 /* host data structures have padding so they are longer
689 * than the compiled message. So buffer is large enough. */
690 gsize total_size = size +
691 TLS_RECORD_HEADER_LENGTH +
692 TLS_HANDSHAKE_HEADER_LENGTH * messages;
693 guchar *buffer = g_malloc0(total_size);
694 va_list ap;
696 SIPE_DEBUG_INFO("compile_msg: buffer size %" G_GSIZE_FORMAT,
697 total_size);
699 state->msg_current = buffer + TLS_RECORD_HEADER_LENGTH;
700 state->msg_remainder = 0;
702 va_start(ap, messages);
703 while (messages--) {
704 const struct msg_descriptor *desc = va_arg(ap, struct msg_descriptor *);
705 const guchar *data = va_arg(ap, gpointer);
706 const struct layout_descriptor *ldesc = desc->layouts;
707 guchar *handshake = state->msg_current;
708 gsize length;
710 /* add TLS handshake header */
711 handshake[TLS_HANDSHAKE_OFFSET_TYPE] = desc->type;
712 state->msg_current += TLS_HANDSHAKE_HEADER_LENGTH;
713 state->msg_remainder += TLS_HANDSHAKE_HEADER_LENGTH;
715 while (TLS_LAYOUT_IS_VALID(ldesc)) {
716 ldesc->compiler(state, ldesc,
717 /* Need to use (void *) here so that
718 * the compiler doesn't check for
719 * aligment restrictions. The data
720 * structures *ARE* correctly aligned!
722 (void *) (data + ldesc->offset));
723 ldesc++;
726 length = state->msg_current - handshake - TLS_HANDSHAKE_HEADER_LENGTH;
727 lowlevel_integer_to_tls(handshake + TLS_HANDSHAKE_OFFSET_LENGTH,
728 3, length);
729 SIPE_DEBUG_INFO("compile_msg: (%d)%s, size %" G_GSIZE_FORMAT,
730 desc->type, desc->description, length);
734 va_end(ap);
736 /* add TLS record header */
737 buffer[TLS_RECORD_OFFSET_TYPE] = TLS_RECORD_TYPE_HANDSHAKE;
738 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_VERSION, 2,
739 TLS_PROTOCOL_VERSION_1_0);
740 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_LENGTH, 2,
741 state->msg_remainder);
743 state->common.out_buffer = buffer;
744 state->common.out_length = state->msg_remainder + TLS_RECORD_HEADER_LENGTH;
746 SIPE_DEBUG_INFO("compile_msg: compiled size %" G_GSIZE_FORMAT,
747 state->common.out_length);
750 static gboolean tls_client_hello(struct tls_internal_state *state)
752 guint32 now = time(NULL);
753 guint32 now_N = GUINT32_TO_BE(now);
754 struct ClientHello_host msg = {
755 { TLS_PROTOCOL_VERSION_1_0 },
756 { 0, { } },
757 { 0 /* empty SessionID */ },
758 { 3,
760 TLS_RSA_WITH_RC4_128_MD5,
761 TLS_RSA_WITH_RC4_128_SHA,
762 TLS_RSA_EXPORT_WITH_RC4_40_MD5
765 { 1,
767 TLS_COMP_METHOD_NULL
772 /* First 4 bytes of client_random is the current timestamp */
773 sipe_svc_fill_random(&state->client_random,
774 TLS_DATATYPE_RANDOM_LENGTH * 8); /* -> bits */
775 memcpy(state->client_random.buffer, &now_N, sizeof(now_N));
776 memcpy((guchar *) msg.random.random, state->client_random.buffer,
777 TLS_DATATYPE_RANDOM_LENGTH);
779 compile_msg(state,
780 sizeof(msg),
782 &ClientHello_m, &msg);
784 if (sipe_backend_debug_enabled())
785 state->debug = g_string_new("");
787 state->state = TLS_HANDSHAKE_STATE_SERVER_HELLO;
788 return(tls_record_parse(state, FALSE));
791 static gboolean tls_server_hello(struct tls_internal_state *state)
793 if (!tls_record_parse(state, TRUE))
794 return(FALSE);
796 /* temporary */
797 free_parse_data(state);
798 state->common.out_buffer = NULL;
799 state->common.out_length = 0;
801 state->state = TLS_HANDSHAKE_STATE_FINISHED;
802 return(tls_record_parse(state, FALSE));
805 static gboolean tls_finished(struct tls_internal_state *state)
807 if (!tls_record_parse(state, TRUE))
808 return(FALSE);
810 /* TBD: data is really not needed? */
811 free_parse_data(state);
813 state->common.out_buffer = NULL;
814 state->common.out_length = 0;
815 state->state = TLS_HANDSHAKE_STATE_COMPLETED;
817 /* temporary */
818 return(TRUE);
821 /* Public API */
823 struct sipe_tls_state *sipe_tls_start(gpointer certificate)
825 struct tls_internal_state *state;
827 if (!certificate)
828 return(NULL);
830 state = g_new0(struct tls_internal_state, 1);
831 state->certificate = certificate;
832 state->state = TLS_HANDSHAKE_STATE_START;
834 return((struct sipe_tls_state *) state);
837 gboolean sipe_tls_next(struct sipe_tls_state *state)
839 struct tls_internal_state *internal = (struct tls_internal_state *) state;
840 gboolean success = FALSE;
842 if (!state)
843 return(FALSE);
845 state->out_buffer = NULL;
847 switch (internal->state) {
848 case TLS_HANDSHAKE_STATE_START:
849 success = tls_client_hello(internal);
850 break;
852 case TLS_HANDSHAKE_STATE_SERVER_HELLO:
853 success = tls_server_hello(internal);
854 break;
856 case TLS_HANDSHAKE_STATE_FINISHED:
857 success = tls_finished(internal);
858 break;
860 case TLS_HANDSHAKE_STATE_COMPLETED:
861 case TLS_HANDSHAKE_STATE_FAILED:
862 /* This should not happen */
863 SIPE_DEBUG_ERROR_NOFORMAT("sipe_tls_next: called in incorrect state!");
864 break;
867 if (!success) {
868 internal->state = TLS_HANDSHAKE_STATE_FAILED;
871 return(success);
874 void sipe_tls_free(struct sipe_tls_state *state)
876 if (state) {
877 struct tls_internal_state *internal = (struct tls_internal_state *) state;
879 free_parse_data(internal);
880 if (internal->debug)
881 g_string_free(internal->debug, TRUE);
882 sipe_svc_free_random(&internal->client_random);
883 g_free(internal->server_random.buffer);
884 g_free(state->session_key);
885 g_free(state->out_buffer);
886 g_free(state);
891 Local Variables:
892 mode: c
893 c-file-style: "bsd"
894 indent-tabs-mode: t
895 tab-width: 8
896 End: