Annotation of embedaddon/strongswan/src/libtls/tls_fragmentation.c, revision 1.1.1.1
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);
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>