Send a ClientHello to start TLS negotiation
[strongswan.git] / src / charon / plugins / eap_tls / tls / tls_peer.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tls_peer.h"
17
18 #include <daemon.h>
19
20 #include <time.h>
21
22 typedef struct private_tls_peer_t private_tls_peer_t;
23
24 typedef enum {
25 STATE_INIT,
26 STATE_HELLO_SENT,
27 } peer_state_t;
28
29 /**
30 * Private data of an tls_peer_t object.
31 */
32 struct private_tls_peer_t {
33
34 /**
35 * Public tls_peer_t interface.
36 */
37 tls_peer_t public;
38
39 /**
40 * TLS crypto context
41 */
42 tls_crypto_t *crypto;
43
44 /**
45 * State we are in
46 */
47 peer_state_t state;
48 };
49
50 METHOD(tls_handshake_t, process, status_t,
51 private_tls_peer_t *this, tls_handshake_type_t type, chunk_t data)
52 {
53 return NEED_MORE;
54 }
55
56 /**
57 * Build the Client Hello using a given set of ciphers
58 */
59 static chunk_t build_hello(int count, tls_cipher_suite_t *suite, rng_t *rng)
60 {
61 int i;
62
63 struct __attribute__((packed)) {
64 u_int16_t version;
65 struct __attribute__((packed)) {
66 u_int32_t gmt;
67 u_int8_t bytes[28];
68 } random;
69 struct __attribute__((packed)) {
70 /* never send a session identifier */
71 u_int8_t len;
72 u_int8_t id[0];
73 } session;
74 struct __attribute__((packed)) {
75 u_int16_t len;
76 u_int16_t suite[count];
77 } cipher;
78 struct __attribute__((packed)) {
79 /* currently NULL compression only */
80 u_int8_t len;
81 u_int8_t method[1];
82 } compression;
83 u_int8_t extensions[0];
84 } hello;
85
86 htoun16(&hello.session.len, 0);
87 htoun16(&hello.version, TLS_1_2);
88 htoun32(&hello.random.gmt, time(NULL));
89 rng->get_bytes(rng, sizeof(hello.random.bytes), (char*)&hello.random.bytes);
90 htoun16(&hello.cipher.len, count * 2);
91 for (i = 0; i < count; i++)
92 {
93 htoun16(&hello.cipher.suite[i], suite[i]);
94 }
95 hello.compression.len = 1;
96 hello.compression.method[0] = 0;
97 return chunk_clone(chunk_create((char*)&hello, sizeof(hello)));
98 }
99
100 /**
101 * Send a client hello
102 */
103 static status_t send_hello(private_tls_peer_t *this,
104 tls_handshake_type_t *type, chunk_t *data)
105 {
106 tls_cipher_suite_t *suite;
107 int count;
108 rng_t *rng;
109
110 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
111 if (!rng)
112 {
113 return FAILED;
114 }
115 count = this->crypto->get_cipher_suites(this->crypto, &suite);
116 *data = build_hello(count, suite, rng);
117 *type = TLS_CLIENT_HELLO;
118 free(suite);
119 rng->destroy(rng);
120 return NEED_MORE;
121 }
122
123 METHOD(tls_handshake_t, build, status_t,
124 private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data)
125 {
126 switch (this->state)
127 {
128 case STATE_INIT:
129 this->state = STATE_HELLO_SENT;
130 return send_hello(this, type, data);
131 default:
132 return INVALID_STATE;
133 }
134 }
135
136 METHOD(tls_handshake_t, destroy, void,
137 private_tls_peer_t *this)
138 {
139 free(this);
140 }
141
142 /**
143 * See header
144 */
145 tls_peer_t *tls_peer_create(tls_crypto_t *crypto)
146 {
147 private_tls_peer_t *this;
148
149 INIT(this,
150 .public.handshake = {
151 .process = _process,
152 .build = _build,
153 .destroy = _destroy,
154 },
155 .state = STATE_INIT,
156 .crypto = crypto,
157 );
158
159 return &this->public;
160 }