Annotation of embedaddon/strongswan/src/libtls/tls_fragmentation.c, revision 1.1.1.2
1.1 misho 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);
1.1.1.2 ! misho 295: if (!this->handshake->finished(this->handshake))
! 296: {
! 297: break;
! 298: }
! 299: /* fall-through */
1.1 misho 300: case TLS_APPLICATION_DATA:
301: status = process_application(this, reader);
302: break;
303: default:
304: DBG1(DBG_TLS, "received unknown TLS content type %d, ignored", type);
305: status = NEED_MORE;
306: break;
307: }
308: reader->destroy(reader);
309: return status;
310: }
311:
312: /**
313: * Check if alerts are pending
314: */
315: static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
316: {
317: tls_alert_level_t level;
318: tls_alert_desc_t desc;
319: bio_writer_t *writer;
320:
321: if (this->alert->get(this->alert, &level, &desc))
322: {
323: writer = bio_writer_create(2);
324:
325: writer->write_uint8(writer, level);
326: writer->write_uint8(writer, desc);
327:
328: *data = chunk_clone(writer->get_buf(writer));
329: writer->destroy(writer);
330: return TRUE;
331: }
332: return FALSE;
333: }
334:
335: /**
336: * Build handshake message
337: */
338: static status_t build_handshake(private_tls_fragmentation_t *this)
339: {
340: bio_writer_t *hs, *msg;
341: tls_handshake_type_t type;
342: status_t status;
343:
344: msg = bio_writer_create(64);
345: while (TRUE)
346: {
347: hs = bio_writer_create(64);
348: status = this->handshake->build(this->handshake, &type, hs);
349: switch (status)
350: {
351: case NEED_MORE:
352: if (this->alert->fatal(this->alert))
353: {
354: break;
355: }
356: msg->write_uint8(msg, type);
357: msg->write_data24(msg, hs->get_buf(hs));
358: DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
359: tls_handshake_type_names, type, hs->get_buf(hs).len);
1.1.1.2 ! misho 360: if (type != TLS_FINISHED &&
! 361: type != TLS_KEY_UPDATE &&
! 362: !this->handshake->cipherspec_changed(this->handshake, FALSE))
1.1 misho 363: {
364: hs->destroy(hs);
365: continue;
366: }
367: /* FALL */
368: case INVALID_STATE:
369: this->output_type = TLS_HANDSHAKE;
370: this->output = chunk_clone(msg->get_buf(msg));
371: break;
372: default:
373: break;
374: }
375: hs->destroy(hs);
376: break;
377: }
378: msg->destroy(msg);
379: return status;
380: }
381:
382: /**
383: * Build TLS application data
384: */
385: static status_t build_application(private_tls_fragmentation_t *this)
386: {
387: bio_writer_t *msg;
388: status_t status;
389:
390: msg = bio_writer_create(64);
391: while (TRUE)
392: {
393: status = this->application->build(this->application, msg);
394: switch (status)
395: {
396: case NEED_MORE:
397: continue;
398: case INVALID_STATE:
399: this->output_type = TLS_APPLICATION_DATA;
400: this->output = chunk_clone(msg->get_buf(msg));
401: break;
402: case SUCCESS:
403: this->application_finished = TRUE;
404: if (!send_close_notify(this))
405: {
406: break;
407: }
408: /* FALL */
409: case FAILED:
410: default:
411: this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
412: break;
413: }
414: break;
415: }
416: msg->destroy(msg);
417: return status;
418: }
419:
420: METHOD(tls_fragmentation_t, build, status_t,
421: private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
422: {
423: status_t status = INVALID_STATE;
424:
425: switch (this->state)
426: {
427: case ALERT_SENDING:
428: this->state = ALERT_SENT;
429: return INVALID_STATE;
430: case ALERT_SENT:
431: if (this->application_finished)
432: {
433: return SUCCESS;
434: }
435: return FAILED;
436: case ALERT_NONE:
437: break;
438: }
439: if (check_alerts(this, data))
440: {
441: this->state = ALERT_SENDING;
442: *type = TLS_ALERT;
443: return NEED_MORE;
444: }
445: if (!this->output.len)
446: {
447: if (this->handshake->cipherspec_changed(this->handshake, FALSE))
448: {
449: this->handshake->change_cipherspec(this->handshake, FALSE);
450: *type = TLS_CHANGE_CIPHER_SPEC;
451: *data = chunk_clone(chunk_from_chars(0x01));
452: return NEED_MORE;
453: }
454: if (!this->handshake->finished(this->handshake))
455: {
456: status = build_handshake(this);
457: }
458: else if (this->application)
459: {
460: status = build_application(this);
461: }
462: if (check_alerts(this, data))
463: {
464: this->state = ALERT_SENDING;
465: *type = TLS_ALERT;
466: return NEED_MORE;
467: }
468: }
469: if (this->output.len)
470: {
471: *type = this->output_type;
472: if (this->output.len <= TLS_MAX_FRAGMENT_LEN)
473: {
474: *data = this->output;
475: this->output = chunk_empty;
476: return NEED_MORE;
477: }
478: *data = chunk_create(this->output.ptr, TLS_MAX_FRAGMENT_LEN);
479: this->output = chunk_clone(chunk_skip(this->output, TLS_MAX_FRAGMENT_LEN));
480: return NEED_MORE;
481: }
482: return status;
483: }
484:
485: METHOD(tls_fragmentation_t, application_finished, bool,
486: private_tls_fragmentation_t *this)
487: {
488: return this->application_finished;
489: }
490:
491: METHOD(tls_fragmentation_t, destroy, void,
492: private_tls_fragmentation_t *this)
493: {
494: free(this->input.ptr);
495: free(this->output.ptr);
496: free(this);
497: }
498:
499: /**
500: * See header
501: */
502: tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
503: tls_alert_t *alert, tls_application_t *application,
504: tls_purpose_t purpose)
505: {
506: private_tls_fragmentation_t *this;
507:
508: INIT(this,
509: .public = {
510: .process = _process,
511: .build = _build,
512: .application_finished = _application_finished,
513: .destroy = _destroy,
514: },
515: .handshake = handshake,
516: .alert = alert,
517: .state = ALERT_NONE,
518: .application = application,
519: .purpose = purpose,
520: );
521:
522: return &this->public;
523: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>