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