kernel-netlink: Check return value of both halfs when installing default route in...
[strongswan.git] / src / libtls / tls_fragmentation.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_fragmentation.h"
17
18 #include <bio/bio_reader.h>
19 #include <utils/debug.h>
20
21 /**
22 * Maximum size of a TLS handshake message we accept
23 */
24 #define TLS_MAX_HANDSHAKE_LEN 65536
25
26 typedef struct private_tls_fragmentation_t private_tls_fragmentation_t;
27
28 /**
29 * Alert state
30 */
31 typedef enum {
32 /* no alert received/sent */
33 ALERT_NONE,
34 /* currently sending an alert */
35 ALERT_SENDING,
36 /* alert sent and out */
37 ALERT_SENT,
38 } alert_state_t;
39
40 /**
41 * Private data of an tls_fragmentation_t object.
42 */
43 struct private_tls_fragmentation_t {
44
45 /**
46 * Public tls_fragmentation_t interface.
47 */
48 tls_fragmentation_t public;
49
50 /**
51 * Upper layer handshake protocol
52 */
53 tls_handshake_t *handshake;
54
55 /**
56 * TLS alert handler
57 */
58 tls_alert_t *alert;
59
60 /**
61 * State of alert handling
62 */
63 alert_state_t state;
64
65 /**
66 * Did the application layer complete successfully?
67 */
68 bool application_finished;
69
70 /**
71 * Handshake input buffer
72 */
73 chunk_t input;
74
75 /**
76 * Position in input buffer
77 */
78 size_t inpos;
79
80 /**
81 * Currently processed handshake message type
82 */
83 tls_handshake_type_t type;
84
85 /**
86 * Handshake output buffer
87 */
88 chunk_t output;
89
90 /**
91 * Type of data in output buffer
92 */
93 tls_content_type_t output_type;
94
95 /**
96 * Upper layer application data protocol
97 */
98 tls_application_t *application;
99
100 /**
101 * Type of context this TLS instance runs in
102 */
103 tls_purpose_t purpose;
104 };
105
106 /**
107 * Check if we should send a close notify once the application finishes
108 */
109 static bool send_close_notify(private_tls_fragmentation_t *this)
110 {
111 switch (this->purpose)
112 {
113 case TLS_PURPOSE_EAP_TLS:
114 case TLS_PURPOSE_EAP_TTLS:
115 case TLS_PURPOSE_EAP_PEAP:
116 /* not for TLS-in-EAP, as we indicate completion with EAP-SUCCCESS.
117 * Windows does not like close notifies, and hangs/disconnects. */
118 return FALSE;
119 default:
120 return TRUE;
121 }
122 }
123
124 /**
125 * Process a TLS alert
126 */
127 static status_t process_alert(private_tls_fragmentation_t *this,
128 bio_reader_t *reader)
129 {
130 uint8_t level, description;
131
132 if (!reader->read_uint8(reader, &level) ||
133 !reader->read_uint8(reader, &description))
134 {
135 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
136 return NEED_MORE;
137 }
138 return this->alert->process(this->alert, level, description);
139 }
140
141 /**
142 * Process TLS handshake protocol data
143 */
144 static status_t process_handshake(private_tls_fragmentation_t *this,
145 bio_reader_t *reader)
146 {
147 while (reader->remaining(reader))
148 {
149 bio_reader_t *msg;
150 uint8_t type;
151 uint32_t len;
152 status_t status;
153 chunk_t data;
154
155 if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN)
156 {
157 DBG1(DBG_TLS, "TLS fragment has invalid length");
158 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
159 return NEED_MORE;
160 }
161
162 if (this->input.len == 0)
163 { /* new handshake message */
164 if (!reader->read_uint8(reader, &type) ||
165 !reader->read_uint24(reader, &len))
166 {
167 DBG1(DBG_TLS, "TLS handshake header invalid");
168 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
169 return NEED_MORE;
170 }
171 this->type = type;
172 if (len > TLS_MAX_HANDSHAKE_LEN)
173 {
174 DBG1(DBG_TLS, "TLS handshake exceeds maximum length");
175 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
176 return NEED_MORE;
177 }
178 chunk_free(&this->input);
179 this->inpos = 0;
180 if (len)
181 {
182 this->input = chunk_alloc(len);
183 }
184 }
185
186 len = min(this->input.len - this->inpos, reader->remaining(reader));
187 if (!reader->read_data(reader, len, &data))
188 {
189 DBG1(DBG_TLS, "TLS fragment has invalid length");
190 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
191 return NEED_MORE;
192 }
193 memcpy(this->input.ptr + this->inpos, data.ptr, len);
194 this->inpos += len;
195
196 if (this->input.len == this->inpos)
197 { /* message completely defragmented, process */
198 msg = bio_reader_create(this->input);
199 DBG2(DBG_TLS, "received TLS %N handshake (%u bytes)",
200 tls_handshake_type_names, this->type, this->input.len);
201 status = this->handshake->process(this->handshake, this->type, msg);
202 msg->destroy(msg);
203 chunk_free(&this->input);
204 if (status != NEED_MORE)
205 {
206 return status;
207 }
208 }
209 if (this->alert->fatal(this->alert))
210 {
211 break;
212 }
213 }
214 return NEED_MORE;
215 }
216
217 /**
218 * Process TLS application data
219 */
220 static status_t process_application(private_tls_fragmentation_t *this,
221 bio_reader_t *reader)
222 {
223 if (!this->handshake->finished(this->handshake))
224 {
225 DBG1(DBG_TLS, "received TLS application data, "
226 "but handshake not finished");
227 return FAILED;
228 }
229 while (reader->remaining(reader))
230 {
231 status_t status;
232 chunk_t data;
233
234 if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN)
235 {
236 DBG1(DBG_TLS, "TLS fragment has invalid length");
237 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
238 return NEED_MORE;
239 }
240 data = reader->peek(reader);
241 DBG3(DBG_TLS, "%B", &data);
242 status = this->application->process(this->application, reader);
243 switch (status)
244 {
245 case NEED_MORE:
246 continue;
247 case SUCCESS:
248 this->application_finished = TRUE;
249 if (!send_close_notify(this))
250 {
251 return SUCCESS;
252 }
253 /* FALL */
254 case FAILED:
255 default:
256 this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
257 return NEED_MORE;
258 }
259 }
260 return NEED_MORE;
261 }
262
263 METHOD(tls_fragmentation_t, process, status_t,
264 private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
265 {
266 bio_reader_t *reader;
267 status_t status;
268
269 switch (this->state)
270 {
271 case ALERT_SENDING:
272 case ALERT_SENT:
273 /* don't accept more input, fatal error occurred */
274 return NEED_MORE;
275 case ALERT_NONE:
276 break;
277 }
278 reader = bio_reader_create(data);
279 switch (type)
280 {
281 case TLS_CHANGE_CIPHER_SPEC:
282 if (this->handshake->cipherspec_changed(this->handshake, TRUE))
283 {
284 this->handshake->change_cipherspec(this->handshake, TRUE);
285 status = NEED_MORE;
286 break;
287 }
288 status = FAILED;
289 break;
290 case TLS_ALERT:
291 status = process_alert(this, reader);
292 break;
293 case TLS_HANDSHAKE:
294 status = process_handshake(this, reader);
295 break;
296 case TLS_APPLICATION_DATA:
297 status = process_application(this, reader);
298 break;
299 default:
300 DBG1(DBG_TLS, "received unknown TLS content type %d, ignored", type);
301 status = NEED_MORE;
302 break;
303 }
304 reader->destroy(reader);
305 return status;
306 }
307
308 /**
309 * Check if alerts are pending
310 */
311 static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
312 {
313 tls_alert_level_t level;
314 tls_alert_desc_t desc;
315 bio_writer_t *writer;
316
317 if (this->alert->get(this->alert, &level, &desc))
318 {
319 writer = bio_writer_create(2);
320
321 writer->write_uint8(writer, level);
322 writer->write_uint8(writer, desc);
323
324 *data = chunk_clone(writer->get_buf(writer));
325 writer->destroy(writer);
326 return TRUE;
327 }
328 return FALSE;
329 }
330
331 /**
332 * Build handshake message
333 */
334 static status_t build_handshake(private_tls_fragmentation_t *this)
335 {
336 bio_writer_t *hs, *msg;
337 tls_handshake_type_t type;
338 status_t status;
339
340 msg = bio_writer_create(64);
341 while (TRUE)
342 {
343 hs = bio_writer_create(64);
344 status = this->handshake->build(this->handshake, &type, hs);
345 switch (status)
346 {
347 case NEED_MORE:
348 if (this->alert->fatal(this->alert))
349 {
350 break;
351 }
352 msg->write_uint8(msg, type);
353 msg->write_data24(msg, hs->get_buf(hs));
354 DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
355 tls_handshake_type_names, type, hs->get_buf(hs).len);
356 if (!this->handshake->cipherspec_changed(this->handshake, FALSE))
357 {
358 hs->destroy(hs);
359 continue;
360 }
361 /* FALL */
362 case INVALID_STATE:
363 this->output_type = TLS_HANDSHAKE;
364 this->output = chunk_clone(msg->get_buf(msg));
365 break;
366 default:
367 break;
368 }
369 hs->destroy(hs);
370 break;
371 }
372 msg->destroy(msg);
373 return status;
374 }
375
376 /**
377 * Build TLS application data
378 */
379 static status_t build_application(private_tls_fragmentation_t *this)
380 {
381 bio_writer_t *msg;
382 status_t status;
383
384 msg = bio_writer_create(64);
385 while (TRUE)
386 {
387 status = this->application->build(this->application, msg);
388 switch (status)
389 {
390 case NEED_MORE:
391 continue;
392 case INVALID_STATE:
393 this->output_type = TLS_APPLICATION_DATA;
394 this->output = chunk_clone(msg->get_buf(msg));
395 break;
396 case SUCCESS:
397 this->application_finished = TRUE;
398 if (!send_close_notify(this))
399 {
400 break;
401 }
402 /* FALL */
403 case FAILED:
404 default:
405 this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
406 break;
407 }
408 break;
409 }
410 msg->destroy(msg);
411 return status;
412 }
413
414 METHOD(tls_fragmentation_t, build, status_t,
415 private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
416 {
417 status_t status = INVALID_STATE;
418
419 switch (this->state)
420 {
421 case ALERT_SENDING:
422 this->state = ALERT_SENT;
423 return INVALID_STATE;
424 case ALERT_SENT:
425 if (this->application_finished)
426 {
427 return SUCCESS;
428 }
429 return FAILED;
430 case ALERT_NONE:
431 break;
432 }
433 if (check_alerts(this, data))
434 {
435 this->state = ALERT_SENDING;
436 *type = TLS_ALERT;
437 return NEED_MORE;
438 }
439 if (!this->output.len)
440 {
441 if (this->handshake->cipherspec_changed(this->handshake, FALSE))
442 {
443 this->handshake->change_cipherspec(this->handshake, FALSE);
444 *type = TLS_CHANGE_CIPHER_SPEC;
445 *data = chunk_clone(chunk_from_chars(0x01));
446 return NEED_MORE;
447 }
448 if (!this->handshake->finished(this->handshake))
449 {
450 status = build_handshake(this);
451 }
452 else if (this->application)
453 {
454 status = build_application(this);
455 }
456 if (check_alerts(this, data))
457 {
458 this->state = ALERT_SENDING;
459 *type = TLS_ALERT;
460 return NEED_MORE;
461 }
462 }
463 if (this->output.len)
464 {
465 *type = this->output_type;
466 if (this->output.len <= TLS_MAX_FRAGMENT_LEN)
467 {
468 *data = this->output;
469 this->output = chunk_empty;
470 return NEED_MORE;
471 }
472 *data = chunk_create(this->output.ptr, TLS_MAX_FRAGMENT_LEN);
473 this->output = chunk_clone(chunk_skip(this->output, TLS_MAX_FRAGMENT_LEN));
474 return NEED_MORE;
475 }
476 return status;
477 }
478
479 METHOD(tls_fragmentation_t, application_finished, bool,
480 private_tls_fragmentation_t *this)
481 {
482 return this->application_finished;
483 }
484
485 METHOD(tls_fragmentation_t, destroy, void,
486 private_tls_fragmentation_t *this)
487 {
488 free(this->input.ptr);
489 free(this->output.ptr);
490 free(this);
491 }
492
493 /**
494 * See header
495 */
496 tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
497 tls_alert_t *alert, tls_application_t *application,
498 tls_purpose_t purpose)
499 {
500 private_tls_fragmentation_t *this;
501
502 INIT(this,
503 .public = {
504 .process = _process,
505 .build = _build,
506 .application_finished = _application_finished,
507 .destroy = _destroy,
508 },
509 .handshake = handshake,
510 .alert = alert,
511 .state = ALERT_NONE,
512 .application = application,
513 .purpose = purpose,
514 );
515
516 return &this->public;
517 }