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