clarified debug output
[strongswan.git] / src / libtls / tls.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.h"
17
18 #include <debug.h>
19
20 #include "tls_protection.h"
21 #include "tls_compression.h"
22 #include "tls_fragmentation.h"
23 #include "tls_crypto.h"
24 #include "tls_server.h"
25 #include "tls_peer.h"
26
27 ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
28 "SSLv2");
29 ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
30 "SSLv3",
31 "TLS 1.0",
32 "TLS 1.1",
33 "TLS 1.2");
34 ENUM_END(tls_version_names, TLS_1_2);
35
36 ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
37 "ChangeCipherSpec",
38 "Alert",
39 "Handshake",
40 "ApplicationData",
41 );
42
43 ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
44 "HelloRequest",
45 "ClientHello",
46 "ServerHello");
47 ENUM_NEXT(tls_handshake_type_names, TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
48 "Certificate",
49 "ServerKeyExchange",
50 "CertificateRequest",
51 "ServerHelloDone",
52 "CertificateVerify",
53 "ClientKeyExchange");
54 ENUM_NEXT(tls_handshake_type_names, TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
55 "Finished");
56 ENUM_END(tls_handshake_type_names, TLS_FINISHED);
57
58 /**
59 * TLS record
60 */
61 typedef struct __attribute__((packed)) {
62 u_int8_t type;
63 u_int16_t version;
64 u_int16_t length;
65 char data[];
66 } tls_record_t;
67
68 typedef struct private_tls_t private_tls_t;
69
70 /**
71 * Private data of an tls_protection_t object.
72 */
73 struct private_tls_t {
74
75 /**
76 * Public tls_t interface.
77 */
78 tls_t public;
79
80 /**
81 * Role this TLS stack acts as.
82 */
83 bool is_server;
84
85 /**
86 * Server identity
87 */
88 identification_t *server;
89
90 /**
91 * Peer identity
92 */
93 identification_t *peer;
94
95 /**
96 * Negotiated TLS version
97 */
98 tls_version_t version;
99
100 /**
101 * TLS stack purpose, as given to constructor
102 */
103 tls_purpose_t purpose;
104
105 /**
106 * TLS record protection layer
107 */
108 tls_protection_t *protection;
109
110 /**
111 * TLS record compression layer
112 */
113 tls_compression_t *compression;
114
115 /**
116 * TLS record fragmentation layer
117 */
118 tls_fragmentation_t *fragmentation;
119
120 /**
121 * TLS alert handler
122 */
123 tls_alert_t *alert;
124
125 /**
126 * TLS crypto helper context
127 */
128 tls_crypto_t *crypto;
129
130 /**
131 * TLS handshake protocol handler
132 */
133 tls_handshake_t *handshake;
134
135 /**
136 * TLS application data handler
137 */
138 tls_application_t *application;
139
140 /**
141 * Allocated input buffer
142 */
143 chunk_t input;
144
145 /**
146 * Number of bytes read in input buffer
147 */
148 size_t inpos;
149
150 /**
151 * Allocated output buffer
152 */
153 chunk_t output;
154
155 /**
156 * Number of bytes processed from output buffer
157 */
158 size_t outpos;
159
160 /**
161 * Partial TLS record header received
162 */
163 tls_record_t head;
164
165 /**
166 * Position in partially received record header
167 */
168 size_t headpos;
169 };
170
171 METHOD(tls_t, process, status_t,
172 private_tls_t *this, void *buf, size_t buflen)
173 {
174 tls_record_t *record;
175 status_t status;
176 u_int len;
177
178 if (this->headpos)
179 { /* have a partial TLS record header, try to complete it */
180 len = min(buflen, sizeof(this->head) - this->headpos);
181 memcpy(((char*)&this->head) + this->headpos, buf, len);
182 this->headpos += len;
183 buflen -= len;
184 buf += len;
185 if (this->headpos == sizeof(this->head))
186 { /* header complete, allocate space with new header */
187 len = untoh16(&this->head.length);
188 this->input = chunk_alloc(len + sizeof(tls_record_t));
189 memcpy(this->input.ptr, &this->head, sizeof(this->head));
190 this->inpos = sizeof(this->head);
191 this->headpos = 0;
192 }
193 }
194
195 while (buflen)
196 {
197 if (this->input.len == 0)
198 {
199 if (buflen < sizeof(tls_record_t))
200 {
201 DBG2(DBG_TLS, "received incomplete TLS record header");
202 memcpy(&this->head, buf, buflen);
203 this->headpos = buflen;
204 break;
205 }
206 while (TRUE)
207 {
208 /* try to process records inline */
209 record = buf;
210 len = untoh16(&record->length);
211
212 if (len + sizeof(tls_record_t) > buflen)
213 { /* not a full record, read to buffer */
214 this->input = chunk_alloc(len + sizeof(tls_record_t));
215 this->inpos = 0;
216 break;
217 }
218 DBG2(DBG_TLS, "processing TLS %N record (%d bytes)",
219 tls_content_type_names, record->type, len);
220 status = this->protection->process(this->protection,
221 record->type, chunk_create(record->data, len));
222 if (status != NEED_MORE)
223 {
224 return status;
225 }
226 buf += len + sizeof(tls_record_t);
227 buflen -= len + sizeof(tls_record_t);
228 if (buflen == 0)
229 {
230 return NEED_MORE;
231 }
232 }
233 }
234 len = min(buflen, this->input.len - this->inpos);
235 memcpy(this->input.ptr + this->inpos, buf, len);
236 buf += len;
237 buflen -= len;
238 this->inpos += len;
239 DBG2(DBG_TLS, "buffering %d bytes, %d bytes of %d byte TLS record received",
240 len, this->inpos, this->input.len);
241 if (this->input.len == this->inpos)
242 {
243 record = (tls_record_t*)this->input.ptr;
244 len = untoh16(&record->length);
245
246 DBG2(DBG_TLS, "processing buffered TLS %N record (%d bytes)",
247 tls_content_type_names, record->type, len);
248 status = this->protection->process(this->protection,
249 record->type, chunk_create(record->data, len));
250 chunk_free(&this->input);
251 this->inpos = 0;
252 if (status != NEED_MORE)
253 {
254 return status;
255 }
256 }
257 }
258 return NEED_MORE;
259 }
260
261 METHOD(tls_t, build, status_t,
262 private_tls_t *this, void *buf, size_t *buflen, size_t *msglen)
263 {
264 tls_content_type_t type;
265 tls_record_t record;
266 status_t status;
267 chunk_t data;
268 size_t len;
269
270 len = *buflen;
271 if (this->output.len == 0)
272 {
273 /* query upper layers for new records, as many as we can get */
274 while (TRUE)
275 {
276 status = this->protection->build(this->protection, &type, &data);
277 switch (status)
278 {
279 case NEED_MORE:
280 record.type = type;
281 htoun16(&record.version, this->version);
282 htoun16(&record.length, data.len);
283 this->output = chunk_cat("mcm", this->output,
284 chunk_from_thing(record), data);
285 DBG2(DBG_TLS, "sending TLS %N record (%d bytes)",
286 tls_content_type_names, type, data.len);
287 continue;
288 case INVALID_STATE:
289 if (this->output.len == 0)
290 {
291 return INVALID_STATE;
292 }
293 break;
294 default:
295 return status;
296 }
297 break;
298 }
299 if (msglen)
300 {
301 *msglen = this->output.len;
302 }
303 }
304 else
305 {
306 DBG2(DBG_TLS, "sending %d bytes buffered fragment",
307 min(*buflen, this->output.len - this->outpos));
308 if (msglen)
309 {
310 *msglen = 0;
311 }
312 }
313 len = min(len, this->output.len - this->outpos);
314 memcpy(buf, this->output.ptr + this->outpos, len);
315 this->outpos += len;
316 *buflen = len;
317 if (this->outpos == this->output.len)
318 {
319 chunk_free(&this->output);
320 this->outpos = 0;
321 return ALREADY_DONE;
322 }
323 return NEED_MORE;
324 }
325
326 METHOD(tls_t, is_server, bool,
327 private_tls_t *this)
328 {
329 return this->is_server;
330 }
331
332 METHOD(tls_t, get_version, tls_version_t,
333 private_tls_t *this)
334 {
335 return this->version;
336 }
337
338 METHOD(tls_t, set_version, bool,
339 private_tls_t *this, tls_version_t version)
340 {
341 if (version > this->version)
342 {
343 return FALSE;
344 }
345 switch (version)
346 {
347 case TLS_1_0:
348 case TLS_1_1:
349 case TLS_1_2:
350 this->version = version;
351 this->protection->set_version(this->protection, version);
352 return TRUE;
353 case SSL_2_0:
354 case SSL_3_0:
355 default:
356 return FALSE;
357 }
358 }
359
360 METHOD(tls_t, get_purpose, tls_purpose_t,
361 private_tls_t *this)
362 {
363 return this->purpose;
364 }
365
366 METHOD(tls_t, is_complete, bool,
367 private_tls_t *this)
368 {
369 if (this->handshake->finished(this->handshake))
370 {
371 if (!this->application)
372 {
373 return TRUE;
374 }
375 return this->fragmentation->application_finished(this->fragmentation);
376 }
377 return FALSE;
378 }
379
380 METHOD(tls_t, get_eap_msk, chunk_t,
381 private_tls_t *this)
382 {
383 return this->crypto->get_eap_msk(this->crypto);
384 }
385
386 METHOD(tls_t, destroy, void,
387 private_tls_t *this)
388 {
389 this->protection->destroy(this->protection);
390 this->compression->destroy(this->compression);
391 this->fragmentation->destroy(this->fragmentation);
392 this->crypto->destroy(this->crypto);
393 this->handshake->destroy(this->handshake);
394 DESTROY_IF(this->peer);
395 this->server->destroy(this->server);
396 DESTROY_IF(this->application);
397 this->alert->destroy(this->alert);
398
399 free(this->input.ptr);
400 free(this->output.ptr);
401
402 free(this);
403 }
404
405 /**
406 * See header
407 */
408 tls_t *tls_create(bool is_server, identification_t *server,
409 identification_t *peer, tls_purpose_t purpose,
410 tls_application_t *application)
411 {
412 private_tls_t *this;
413
414 switch (purpose)
415 {
416 case TLS_PURPOSE_EAP_TLS:
417 case TLS_PURPOSE_EAP_TTLS:
418 case TLS_PURPOSE_GENERIC:
419 break;
420 default:
421 return NULL;
422 }
423
424 INIT(this,
425 .public = {
426 .process = _process,
427 .build = _build,
428 .is_server = _is_server,
429 .get_version = _get_version,
430 .set_version = _set_version,
431 .get_purpose = _get_purpose,
432 .is_complete = _is_complete,
433 .get_eap_msk = _get_eap_msk,
434 .destroy = _destroy,
435 },
436 .is_server = is_server,
437 .version = TLS_1_2,
438 .server = server->clone(server),
439 .peer = peer ? peer->clone(peer) : NULL,
440 .application = application,
441 .purpose = purpose,
442 );
443
444 this->crypto = tls_crypto_create(&this->public);
445 this->alert = tls_alert_create();
446 if (is_server)
447 {
448 this->handshake = &tls_server_create(&this->public, this->crypto,
449 this->alert, this->server, this->peer)->handshake;
450 }
451 else
452 {
453 this->handshake = &tls_peer_create(&this->public, this->crypto,
454 this->alert, this->peer, this->server)->handshake;
455 }
456 this->fragmentation = tls_fragmentation_create(this->handshake, this->alert,
457 this->application);
458 this->compression = tls_compression_create(this->fragmentation, this->alert);
459 this->protection = tls_protection_create(this->compression, this->alert);
460 this->crypto->set_protection(this->crypto, this->protection);
461
462 return &this->public;
463 }