tls: refactor tls_server_hello()
[siplcs.git] / src / core / sipe-tls.c
blob246924f410e4ef6bf02d31ad75e9aa4e6e94f73f
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-crypt.h"
46 #include "sipe-svc.h"
47 #include "sipe-tls.h"
50 * Private part of TLS state tracking
52 enum tls_handshake_state {
53 TLS_HANDSHAKE_STATE_START,
54 TLS_HANDSHAKE_STATE_SERVER_HELLO,
55 TLS_HANDSHAKE_STATE_FINISHED,
56 TLS_HANDSHAKE_STATE_COMPLETED,
57 TLS_HANDSHAKE_STATE_FAILED
60 struct tls_internal_state {
61 struct sipe_tls_state common;
62 gpointer certificate;
63 enum tls_handshake_state state;
64 guchar *msg_current;
65 gsize msg_remainder;
66 GHashTable *data;
67 GString *debug;
68 gpointer server_certificate;
69 struct sipe_svc_random client_random;
70 struct sipe_svc_random server_random;
71 struct sipe_svc_random premaster_secret;
75 * TLS messages & layout descriptors
78 /* constants */
79 #define TLS_VECTOR_MAX8 255 /* 2^8 - 1 */
80 #define TLS_VECTOR_MAX16 65535 /* 2^16 - 1 */
81 #define TLS_VECTOR_MAX24 16777215 /* 2^24 - 1 */
83 #define TLS_DATATYPE_RANDOM_LENGTH 32
84 #define TLS_DATATYPE_PREMASTER_SECRET_LENGTH 48
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_TYPE_CLIENT_KEY_EXCHANGE 16
111 #define TLS_HANDSHAKE_OFFSET_LENGTH 1
113 struct layout_descriptor;
114 typedef gboolean parse_func(struct tls_internal_state *state,
115 const struct layout_descriptor *desc);
117 /* Defines the strictest alignment requirement */
118 struct tls_compile_integer;
119 typedef void compile_func(struct tls_internal_state *state,
120 const struct layout_descriptor *desc,
121 const struct tls_compile_integer *data);
123 struct layout_descriptor {
124 const gchar *label;
125 parse_func *parser;
126 compile_func *compiler;
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 }
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 struct layout_descriptor *desc)
269 guint value;
270 if (!parse_integer_quiet(state, desc->label, desc->max, &value))
271 return(FALSE);
272 debug_printf(state, "%s/INTEGER%" G_GSIZE_FORMAT " = %d\n",
273 desc->label, desc->max, 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) desc->label, save);
279 return(TRUE);
282 static gboolean parse_array(struct tls_internal_state *state,
283 const struct layout_descriptor *desc)
285 if (!msg_remainder_check(state, desc->label, desc->max))
286 return(FALSE);
287 debug_printf(state, "%s/ARRAY[%" G_GSIZE_FORMAT "]\n",
288 desc->label, desc->max);
289 if (state->data) {
290 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
291 desc->max);
292 save->length = desc->max;
293 memcpy((guchar *)save->data, state->msg_current, desc->max);
294 g_hash_table_insert(state->data, (gpointer) desc->label, save);
297 state->msg_current += desc->max;
298 state->msg_remainder -= desc->max;
299 return(TRUE);
302 static gboolean parse_vector(struct tls_internal_state *state,
303 const struct layout_descriptor *desc)
305 guint length;
306 if (!parse_integer_quiet(state, desc->label,
307 (desc->max > TLS_VECTOR_MAX16) ? 3 :
308 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1,
309 &length))
310 return(FALSE);
311 if (length < desc->min) {
312 SIPE_DEBUG_ERROR("parse_vector: '%s' too short %d, expected %" G_GSIZE_FORMAT,
313 desc->label, length, desc->min);
314 return(FALSE);
316 debug_printf(state, "%s/VECTOR<%d>\n", desc->label, length);
317 if (state->data) {
318 struct tls_parsed_array *save = g_malloc0(sizeof(struct tls_parsed_array) +
319 length);
320 save->length = length;
321 memcpy((guchar *)save->data, state->msg_current, length);
322 g_hash_table_insert(state->data, (gpointer) desc->label, save);
324 state->msg_current += length;
325 state->msg_remainder -= length;
326 return(TRUE);
330 * Specific data type parser routines
333 /* TBD... */
336 * TLS data compilers
338 * Low-level data conversion routines
340 * - host alignment agnostic, i.e. can fetch a word from uneven address
341 * - host -> TLS host endianess conversion
342 * - don't modify state
344 static void lowlevel_integer_to_tls(guchar *bytes,
345 gsize length,
346 guint value)
348 while (length--) {
349 bytes[length] = value & 0xFF;
350 value >>= 8;
355 * Generic data type compiler routines
357 static void compile_integer(struct tls_internal_state *state,
358 const struct layout_descriptor *desc,
359 const struct tls_compile_integer *data)
361 lowlevel_integer_to_tls(state->msg_current, desc->max, data->value);
362 state->msg_current += desc->max;
363 state->msg_remainder += desc->max;
366 static void compile_array(struct tls_internal_state *state,
367 const struct layout_descriptor *desc,
368 const struct tls_compile_integer *data)
370 const struct tls_compile_array *array = (struct tls_compile_array *) data;
371 memcpy(state->msg_current, array->placeholder, desc->max);
372 state->msg_current += desc->max;
373 state->msg_remainder += desc->max;
376 static void compile_vector(struct tls_internal_state *state,
377 const struct layout_descriptor *desc,
378 const struct tls_compile_integer *data)
380 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
381 gsize length = vector->elements;
382 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
383 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
385 lowlevel_integer_to_tls(state->msg_current, length_field, length);
386 state->msg_current += length_field;
387 state->msg_remainder += length_field;
388 memcpy(state->msg_current, vector->placeholder, length);
389 state->msg_current += length;
390 state->msg_remainder += length;
393 static void compile_vector_int2(struct tls_internal_state *state,
394 const struct layout_descriptor *desc,
395 const struct tls_compile_integer *data)
397 const struct tls_compile_vector *vector = (struct tls_compile_vector *) data;
398 gsize elements = vector->elements;
399 gsize length = elements * sizeof(guint16);
400 gsize length_field = (desc->max > TLS_VECTOR_MAX16) ? 3 :
401 (desc->max > TLS_VECTOR_MAX8) ? 2 : 1;
402 const guint *p = vector->placeholder;
404 lowlevel_integer_to_tls(state->msg_current, length_field, length);
405 state->msg_current += length_field;
406 state->msg_remainder += length_field;
407 while (elements--) {
408 lowlevel_integer_to_tls(state->msg_current, sizeof(guint16), *p++);
409 state->msg_current += sizeof(guint16);
410 state->msg_remainder += sizeof(guint16);
415 * Specific data type compiler routines
418 /* TBD... */
421 * TLS handshake message layout descriptors
423 struct ClientHello_host {
424 const struct tls_compile_integer protocol_version;
425 const struct tls_compile_random random;
426 const struct tls_compile_sessionid sessionid;
427 const struct tls_compile_cipher cipher;
428 const struct tls_compile_compression compression;
430 #define CLIENTHELLO_OFFSET(a) offsetof(struct ClientHello_host, a)
432 static const struct layout_descriptor const ClientHello_l[] = {
433 { "Client Protocol Version", parse_integer, compile_integer, 0, 2, CLIENTHELLO_OFFSET(protocol_version) },
434 { "Random", parse_array, compile_array, 0, TLS_DATATYPE_RANDOM_LENGTH, CLIENTHELLO_OFFSET(random) },
435 { "SessionID", parse_vector, compile_vector, 0, 32, CLIENTHELLO_OFFSET(sessionid) },
436 { "CipherSuite", parse_vector, compile_vector_int2, 2, TLS_VECTOR_MAX16, CLIENTHELLO_OFFSET(cipher)},
437 { "CompressionMethod", parse_vector, compile_vector, 1, TLS_VECTOR_MAX8, CLIENTHELLO_OFFSET(compression) },
438 TLS_LAYOUT_DESCRIPTOR_END
440 static const struct msg_descriptor const ClientHello_m = {
441 NULL, "Client Hello", ClientHello_l, TLS_HANDSHAKE_TYPE_CLIENT_HELLO
444 static const struct layout_descriptor const ServerHello_l[] = {
445 { "Server Protocol Version", parse_integer, NULL, 0, 2, 0 },
446 { "Random", parse_array, NULL, 0, TLS_DATATYPE_RANDOM_LENGTH, 0 },
447 { "SessionID", parse_vector, NULL, 0, 32, 0 },
448 { "CipherSuite", parse_integer, NULL, 0, 2, 0 },
449 { "CompressionMethod", parse_integer, NULL, 0, 1, 0 },
450 TLS_LAYOUT_DESCRIPTOR_END
452 static const struct msg_descriptor const ServerHello_m = {
453 &ClientHello_m, "Server Hello", ServerHello_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO
456 struct Certificate_host {
457 struct tls_compile_vector certificate;
459 #define CERTIFICATE_OFFSET(a) offsetof(struct Certificate_host, a)
461 static const struct layout_descriptor const Certificate_l[] = {
462 { "Certificate", parse_vector, compile_vector, 0, TLS_VECTOR_MAX24, CERTIFICATE_OFFSET(certificate) },
463 TLS_LAYOUT_DESCRIPTOR_END
465 static const struct msg_descriptor const Certificate_m = {
466 &ServerHello_m, "Certificate", Certificate_l, TLS_HANDSHAKE_TYPE_CERTIFICATE
469 static const struct layout_descriptor const CertificateRequest_l[] = {
470 { "CertificateType", parse_vector, NULL, 1, TLS_VECTOR_MAX8, 0 },
471 { "DistinguishedName", parse_vector, NULL, 0, TLS_VECTOR_MAX16, 0 },
472 TLS_LAYOUT_DESCRIPTOR_END
474 static const struct msg_descriptor const CertificateRequest_m = {
475 &Certificate_m, "Certificate Request", CertificateRequest_l, TLS_HANDSHAKE_TYPE_CERTIFICATE_REQ
478 static const struct layout_descriptor const ServerHelloDone_l[] = {
479 TLS_LAYOUT_DESCRIPTOR_END
481 static const struct msg_descriptor const ServerHelloDone_m = {
482 &CertificateRequest_m, "Server Hello Done", ServerHelloDone_l, TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE
485 struct ClientKeyExchange_host {
486 struct tls_compile_vector secret;
488 #define CLIENTKEYEXCHANGE_OFFSET(a) offsetof(struct ClientKeyExchange_host, a)
490 static const struct layout_descriptor const ClientKeyExchange_l[] = {
491 { "Exchange Keys", parse_vector, compile_vector, 0, TLS_VECTOR_MAX16, CLIENTKEYEXCHANGE_OFFSET(secret) },
492 TLS_LAYOUT_DESCRIPTOR_END
494 static const struct msg_descriptor const ClientKeyExchange_m = {
495 &ServerHelloDone_m, "Client Key Exchange", ClientKeyExchange_l, TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE
498 #define HANDSHAKE_MSG_DESCRIPTORS &ClientKeyExchange_m
501 * TLS message parsers
503 static gboolean handshake_parse(struct tls_internal_state *state)
505 const guchar *bytes = state->msg_current;
506 gsize length = state->msg_remainder;
507 gboolean success = FALSE;
509 while (length > 0) {
510 const struct msg_descriptor *desc;
511 gsize msg_length;
512 guint msg_type;
514 /* header check */
515 if (length < TLS_HANDSHAKE_HEADER_LENGTH) {
516 debug_print(state, "CORRUPTED HANDSHAKE HEADER");
517 break;
520 /* msg length check */
521 msg_length = lowlevel_integer_to_host(bytes + TLS_HANDSHAKE_OFFSET_LENGTH,
523 if (msg_length > length) {
524 debug_print(state, "HANDSHAKE MESSAGE TOO LONG");
525 break;
528 /* msg type */
529 msg_type = bytes[TLS_HANDSHAKE_OFFSET_TYPE];
530 for (desc = HANDSHAKE_MSG_DESCRIPTORS;
531 desc;
532 desc = desc->next)
533 if (msg_type == desc->type)
534 break;
536 debug_printf(state, "TLS handshake (%" G_GSIZE_FORMAT " bytes) (%d)",
537 msg_length, msg_type);
539 state->msg_current = (guchar *) bytes + TLS_HANDSHAKE_HEADER_LENGTH;
540 state->msg_remainder = msg_length;
542 if (desc->layouts) {
543 const struct layout_descriptor *ldesc = desc->layouts;
545 debug_printf(state, "%s\n", desc->description);
546 while (TLS_LAYOUT_IS_VALID(ldesc)) {
547 success = ldesc->parser(state, ldesc);
548 if (!success)
549 break;
550 ldesc++;
552 if (!success)
553 break;
554 } else {
555 debug_print(state, "ignored\n");
556 debug_hex(state, 0);
559 /* next message */
560 bytes += TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
561 length -= TLS_HANDSHAKE_HEADER_LENGTH + msg_length;
562 if (length > 0) {
563 debug_print(state, "------\n");
564 } else {
565 success = TRUE;
569 return(success);
572 static void free_parse_data(struct tls_internal_state *state)
574 if (state->data) {
575 g_hash_table_destroy(state->data);
576 state->data = NULL;
580 /* NOTE: we don't support record fragmentation */
581 static gboolean tls_record_parse(struct tls_internal_state *state,
582 gboolean incoming)
584 const guchar *bytes = incoming ? state->common.in_buffer : state->common.out_buffer;
585 gsize length = incoming ? state->common.in_length : state->common.out_length;
586 guint version;
587 const gchar *version_str;
588 gsize record_length;
589 gboolean success = FALSE;
591 debug_printf(state, "TLS MESSAGE %s\n", incoming ? "INCOMING" : "OUTGOING");
593 /* truncated header check */
594 if (length < TLS_RECORD_HEADER_LENGTH) {
595 SIPE_DEBUG_ERROR("tls_record_parse: too short TLS record header (%" G_GSIZE_FORMAT " bytes)",
596 length);
597 return(FALSE);
600 /* protocol version check */
601 version = lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_VERSION, 2);
602 if (version < TLS_PROTOCOL_VERSION_1_0) {
603 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: SSL1/2/3 not supported");
604 return(FALSE);
606 switch (version) {
607 case TLS_PROTOCOL_VERSION_1_0:
608 version_str = "1.0 (RFC2246)";
609 break;
610 case TLS_PROTOCOL_VERSION_1_1:
611 version_str = "1.1 (RFC4346)";
612 break;
613 default:
614 version_str = "<future protocol version>";
615 break;
618 /* record length check */
619 record_length = TLS_RECORD_HEADER_LENGTH +
620 lowlevel_integer_to_host(bytes + TLS_RECORD_OFFSET_LENGTH, 2);
621 if (record_length > length) {
622 SIPE_DEBUG_ERROR_NOFORMAT("tls_record_parse: record too long");
623 return(FALSE);
626 /* TLS record header OK */
627 debug_printf(state, "TLS %s record (%" G_GSIZE_FORMAT " bytes)\n",
628 version_str, length);
629 state->msg_current = (guchar *) bytes + TLS_RECORD_HEADER_LENGTH;
630 state->msg_remainder = length - TLS_RECORD_HEADER_LENGTH;
632 /* Collect parser data for incoming messages */
633 if (incoming)
634 state->data = g_hash_table_new_full(g_str_hash, g_str_equal,
635 NULL, g_free);
637 switch (bytes[TLS_RECORD_OFFSET_TYPE]) {
638 case TLS_RECORD_TYPE_HANDSHAKE:
639 success = handshake_parse(state);
640 break;
642 default:
643 debug_print(state, "Unsupported TLS message\n");
644 debug_hex(state, 0);
645 break;
648 if (!success)
649 free_parse_data(state);
651 if (state->debug) {
652 SIPE_DEBUG_INFO_NOFORMAT(state->debug->str);
653 g_string_truncate(state->debug, 0);
656 return(success);
660 * TLS message compiler
662 static void compile_msg(struct tls_internal_state *state,
663 gsize size,
664 gsize messages,
665 ...)
668 * Estimate the size of the compiled message
670 * The data structures in the host format have zero or more padding
671 * bytes added by the compiler to ensure correct element alignments.
672 * So the sizeof() of the data structure is always equal or greater
673 * than the space needed for the compiled data. By adding the space
674 * required for the headers we arrive at a safe estimate
676 * Therefore we don't need space checks in the compiler functions
678 gsize total_size = size +
679 TLS_RECORD_HEADER_LENGTH +
680 TLS_HANDSHAKE_HEADER_LENGTH * messages;
681 guchar *buffer = g_malloc0(total_size);
682 va_list ap;
684 SIPE_DEBUG_INFO("compile_msg: buffer size %" G_GSIZE_FORMAT,
685 total_size);
687 state->msg_current = buffer + TLS_RECORD_HEADER_LENGTH;
688 state->msg_remainder = 0;
690 va_start(ap, messages);
691 while (messages--) {
692 const struct msg_descriptor *desc = va_arg(ap, struct msg_descriptor *);
693 const guchar *data = va_arg(ap, gpointer);
694 const struct layout_descriptor *ldesc = desc->layouts;
695 guchar *handshake = state->msg_current;
696 gsize length;
698 /* add TLS handshake header */
699 handshake[TLS_HANDSHAKE_OFFSET_TYPE] = desc->type;
700 state->msg_current += TLS_HANDSHAKE_HEADER_LENGTH;
701 state->msg_remainder += TLS_HANDSHAKE_HEADER_LENGTH;
703 while (TLS_LAYOUT_IS_VALID(ldesc)) {
705 * Avoid "cast increases required alignment" errors
707 * (void *) tells the compiler that we know what we're
708 * doing, i.e. we know that the calculated address
709 * points to correctly aligned data.
711 ldesc->compiler(state, ldesc,
712 (void *) (data + ldesc->offset));
713 ldesc++;
716 length = state->msg_current - handshake - TLS_HANDSHAKE_HEADER_LENGTH;
717 lowlevel_integer_to_tls(handshake + TLS_HANDSHAKE_OFFSET_LENGTH,
718 3, length);
719 SIPE_DEBUG_INFO("compile_msg: (%d)%s, size %" G_GSIZE_FORMAT,
720 desc->type, desc->description, length);
724 va_end(ap);
726 /* add TLS record header */
727 buffer[TLS_RECORD_OFFSET_TYPE] = TLS_RECORD_TYPE_HANDSHAKE;
728 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_VERSION, 2,
729 TLS_PROTOCOL_VERSION_1_0);
730 lowlevel_integer_to_tls(buffer + TLS_RECORD_OFFSET_LENGTH, 2,
731 state->msg_remainder);
733 state->common.out_buffer = buffer;
734 state->common.out_length = state->msg_remainder + TLS_RECORD_HEADER_LENGTH;
736 SIPE_DEBUG_INFO("compile_msg: compiled size %" G_GSIZE_FORMAT,
737 state->common.out_length);
740 static struct Certificate_host *tls_client_certificate(struct tls_internal_state *state,
741 gsize *cumulative_length)
743 struct Certificate_host *certificate;
744 gsize certificate_length = sipe_cert_crypto_raw_length(state->certificate);
746 /* setup our response */
747 /* Client Certificate is VECTOR_MAX24 of VECTOR_MAX24s */
748 certificate = g_malloc0(sizeof(struct Certificate_host) + 3 +
749 certificate_length);
750 certificate->certificate.elements = certificate_length + 3;
751 lowlevel_integer_to_tls((guchar *) certificate->certificate.placeholder, 3,
752 certificate_length);
753 memcpy((guchar *) certificate->certificate.placeholder + 3,
754 sipe_cert_crypto_raw(state->certificate),
755 certificate_length);
757 *cumulative_length += sizeof(struct Certificate_host) + certificate_length;
758 return(certificate);
761 static struct ClientKeyExchange_host *tls_client_key_exchange(struct tls_internal_state *state,
762 gsize *cumulative_length)
764 struct tls_parsed_array *server_random;
765 struct tls_parsed_array *server_certificate;
766 struct ClientKeyExchange_host *exchange;
767 gsize server_certificate_length;
769 /* check for required data fields */
770 server_random = g_hash_table_lookup(state->data, "Random");
771 if (!server_random) {
772 SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: no server random");
773 return(NULL);
775 server_certificate = g_hash_table_lookup(state->data, "Certificate");
776 /* Server Certificate is VECTOR_MAX24 of VECTOR_MAX24s */
777 if (!server_certificate || (server_certificate->length < 3)) {
778 SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: no server certificate");
779 return(FALSE);
781 SIPE_DEBUG_INFO("tls_client_key_exchange: server certificate list %" G_GSIZE_FORMAT" bytes",
782 server_certificate->length);
783 /* first certificate is the server certificate */
784 server_certificate_length = lowlevel_integer_to_host(server_certificate->data,
786 SIPE_DEBUG_INFO("tls_client_key_exchange: server certificate %" G_GSIZE_FORMAT" bytes",
787 server_certificate_length);
788 if ((server_certificate_length + 3) > server_certificate->length) {
789 SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: truncated server certificate");
791 state->server_certificate = sipe_cert_crypto_import(server_certificate->data + 3,
792 server_certificate_length);
793 if (!state->server_certificate) {
794 SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: corrupted server certificate");
795 return(FALSE);
797 /* server public key modulus length */
798 server_certificate_length = sipe_cert_crypto_modulus_length(state->server_certificate);
799 if (server_certificate_length < TLS_DATATYPE_PREMASTER_SECRET_LENGTH) {
800 SIPE_DEBUG_ERROR("tls_client_key_exchange: server public key strength too low (%" G_GSIZE_FORMAT ")",
801 server_certificate_length);
802 return(FALSE);
804 SIPE_DEBUG_INFO("tls_client_key_exchange: server public key strength = %" G_GSIZE_FORMAT,
805 server_certificate_length);
807 /* found all the required fields */
808 state->server_random.length = server_random->length;
809 state->server_random.buffer = g_memdup(server_random->data,
810 server_random->length);
812 /* ClientKeyExchange */
813 exchange = g_malloc0(sizeof(struct ClientKeyExchange_host) +
814 server_certificate_length);
815 exchange->secret.elements = server_certificate_length;
816 sipe_svc_fill_random(&state->premaster_secret,
817 TLS_DATATYPE_PREMASTER_SECRET_LENGTH * 8); /* bits */
818 lowlevel_integer_to_tls(state->premaster_secret.buffer, 2,
819 TLS_PROTOCOL_VERSION_1_0);
820 if (!sipe_crypt_rsa_encrypt(sipe_cert_crypto_public_key(state->server_certificate),
821 TLS_DATATYPE_PREMASTER_SECRET_LENGTH,
822 state->premaster_secret.buffer,
823 (guchar *) exchange->secret.placeholder)) {
824 SIPE_DEBUG_ERROR_NOFORMAT("tls_client_key_exchange: encryption of pre-master secret failed");
825 g_free(exchange);
826 return(NULL);
829 *cumulative_length += sizeof(struct ClientKeyExchange_host) + server_certificate_length;
830 return(exchange);
834 * TLS state handling
837 static gboolean tls_client_hello(struct tls_internal_state *state)
839 guint32 now = time(NULL);
840 guint32 now_N = GUINT32_TO_BE(now);
841 struct ClientHello_host msg = {
842 { TLS_PROTOCOL_VERSION_1_0 },
843 { 0, { } },
844 { 0 /* empty SessionID */ },
845 { 3,
847 TLS_RSA_WITH_RC4_128_MD5,
848 TLS_RSA_WITH_RC4_128_SHA,
849 TLS_RSA_EXPORT_WITH_RC4_40_MD5
852 { 1,
854 TLS_COMP_METHOD_NULL
859 /* First 4 bytes of client_random is the current timestamp */
860 sipe_svc_fill_random(&state->client_random,
861 TLS_DATATYPE_RANDOM_LENGTH * 8); /* -> bits */
862 memcpy(state->client_random.buffer, &now_N, sizeof(now_N));
863 memcpy((guchar *) msg.random.random, state->client_random.buffer,
864 TLS_DATATYPE_RANDOM_LENGTH);
866 compile_msg(state,
867 sizeof(msg),
869 &ClientHello_m, &msg);
871 if (sipe_backend_debug_enabled())
872 state->debug = g_string_new("");
874 state->state = TLS_HANDSHAKE_STATE_SERVER_HELLO;
875 return(tls_record_parse(state, FALSE));
878 static gboolean tls_server_hello(struct tls_internal_state *state)
880 struct Certificate_host *certificate = NULL;
881 struct ClientKeyExchange_host *exchange = NULL;
882 gsize length = 0;
883 gboolean success = FALSE;
885 if (!tls_record_parse(state, TRUE))
886 return(FALSE);
888 if (((certificate = tls_client_certificate(state, &length)) != NULL) &&
889 ((exchange = tls_client_key_exchange(state, &length)) != NULL)) {
891 compile_msg(state,
892 length,
894 &Certificate_m, certificate,
895 &ClientKeyExchange_m, exchange);
897 success = tls_record_parse(state, FALSE);
898 if (success)
899 state->state = TLS_HANDSHAKE_STATE_FINISHED;
902 g_free(exchange);
903 g_free(certificate);
904 free_parse_data(state);
906 return(success);
909 static gboolean tls_finished(struct tls_internal_state *state)
911 if (!tls_record_parse(state, TRUE))
912 return(FALSE);
914 /* TBD: data is really not needed? */
915 free_parse_data(state);
917 state->common.out_buffer = NULL;
918 state->common.out_length = 0;
919 state->state = TLS_HANDSHAKE_STATE_COMPLETED;
921 /* temporary */
922 return(TRUE);
926 * TLS public API
929 struct sipe_tls_state *sipe_tls_start(gpointer certificate)
931 struct tls_internal_state *state;
933 if (!certificate)
934 return(NULL);
936 state = g_new0(struct tls_internal_state, 1);
937 state->certificate = certificate;
938 state->state = TLS_HANDSHAKE_STATE_START;
940 return((struct sipe_tls_state *) state);
943 gboolean sipe_tls_next(struct sipe_tls_state *state)
945 struct tls_internal_state *internal = (struct tls_internal_state *) state;
946 gboolean success = FALSE;
948 if (!state)
949 return(FALSE);
951 state->out_buffer = NULL;
953 switch (internal->state) {
954 case TLS_HANDSHAKE_STATE_START:
955 success = tls_client_hello(internal);
956 break;
958 case TLS_HANDSHAKE_STATE_SERVER_HELLO:
959 success = tls_server_hello(internal);
960 break;
962 case TLS_HANDSHAKE_STATE_FINISHED:
963 success = tls_finished(internal);
964 break;
966 case TLS_HANDSHAKE_STATE_COMPLETED:
967 case TLS_HANDSHAKE_STATE_FAILED:
968 /* This should not happen */
969 SIPE_DEBUG_ERROR_NOFORMAT("sipe_tls_next: called in incorrect state!");
970 break;
973 if (!success) {
974 internal->state = TLS_HANDSHAKE_STATE_FAILED;
977 return(success);
980 void sipe_tls_free(struct sipe_tls_state *state)
982 if (state) {
983 struct tls_internal_state *internal = (struct tls_internal_state *) state;
985 free_parse_data(internal);
986 if (internal->debug)
987 g_string_free(internal->debug, TRUE);
988 sipe_svc_free_random(&internal->client_random);
989 sipe_svc_free_random(&internal->server_random);
990 sipe_svc_free_random(&internal->premaster_secret);
991 sipe_cert_crypto_destroy(internal->server_certificate);
992 g_free(state->session_key);
993 g_free(state->out_buffer);
994 g_free(state);
999 Local Variables:
1000 mode: c
1001 c-file-style: "bsd"
1002 indent-tabs-mode: t
1003 tab-width: 8
1004 End: