Implemented TLS Alert handling
[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 * Handshake input buffer
63 */
64 chunk_t input;
65
66 /**
67 * Position in input buffer
68 */
69 size_t inpos;
70
71 /**
72 * Currently processed handshake message type
73 */
74 tls_handshake_type_t type;
75
76 /**
77 * Handshake output buffer
78 */
79 chunk_t output;
80
81 /**
82 * Upper layer application data protocol
83 */
84 tls_application_t *application;
85 };
86
87 /**
88 * Maximum size of a TLS fragment
89 */
90 #define MAX_TLS_FRAGMENT_LEN 16384
91
92 /**
93 * Maximum size of a TLS handshake message we accept
94 */
95 #define MAX_TLS_HANDSHAKE_LEN 65536
96
97 /**
98 * Process a TLS alert
99 */
100 static status_t process_alert(private_tls_fragmentation_t *this,
101 tls_reader_t *reader)
102 {
103 u_int8_t level, description;
104
105 if (!reader->read_uint8(reader, &level) ||
106 !reader->read_uint8(reader, &description))
107 {
108 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
109 return NEED_MORE;
110 }
111 return this->alert->process(this->alert, level, description);
112 }
113
114 /**
115 * Process TLS handshake protocol data
116 */
117 static status_t process_handshake(private_tls_fragmentation_t *this,
118 tls_reader_t *reader)
119 {
120 while (reader->remaining(reader))
121 {
122 tls_reader_t *msg;
123 u_int8_t type;
124 u_int32_t len;
125 status_t status;
126 chunk_t data;
127
128 if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
129 {
130 DBG1(DBG_TLS, "TLS fragment has invalid length");
131 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
132 return NEED_MORE;
133 }
134
135 if (this->input.len == 0)
136 { /* new handshake message */
137 if (!reader->read_uint8(reader, &type) ||
138 !reader->read_uint24(reader, &len))
139 {
140 DBG1(DBG_TLS, "TLS handshake header invalid");
141 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
142 return NEED_MORE;
143 }
144 this->type = type;
145 if (len > MAX_TLS_HANDSHAKE_LEN)
146 {
147 DBG1(DBG_TLS, "TLS handshake message exceeds maximum length");
148 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
149 return NEED_MORE;
150 }
151 chunk_free(&this->input);
152 this->inpos = 0;
153 if (len)
154 {
155 this->input = chunk_alloc(len);
156 }
157 }
158
159 len = min(this->input.len - this->inpos, reader->remaining(reader));
160 if (!reader->read_data(reader, len, &data))
161 {
162 DBG1(DBG_TLS, "TLS fragment has invalid length");
163 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
164 return NEED_MORE;
165 }
166 memcpy(this->input.ptr + this->inpos, data.ptr, len);
167 this->inpos += len;
168
169 if (this->input.len == this->inpos)
170 { /* message completely defragmented, process */
171 msg = tls_reader_create(this->input);
172 DBG2(DBG_TLS, "received TLS %N message (%u bytes)",
173 tls_handshake_type_names, this->type, 4 + this->input.len);
174 status = this->handshake->process(this->handshake, this->type, msg);
175 msg->destroy(msg);
176 chunk_free(&this->input);
177 if (status != NEED_MORE)
178 {
179 return status;
180 }
181 }
182 }
183 return NEED_MORE;
184 }
185
186 /**
187 * Process TLS application data
188 */
189 static status_t process_application(private_tls_fragmentation_t *this,
190 tls_reader_t *reader)
191 {
192 while (reader->remaining(reader))
193 {
194 status_t status;
195
196 if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
197 {
198 DBG1(DBG_TLS, "TLS fragment has invalid length");
199 this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
200 return NEED_MORE;
201 }
202 status = this->application->process(this->application, reader);
203 if (status != NEED_MORE)
204 {
205 this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
206 return NEED_MORE;
207 }
208 }
209 return NEED_MORE;
210 }
211
212 METHOD(tls_fragmentation_t, process, status_t,
213 private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
214 {
215 tls_reader_t *reader;
216 status_t status;
217
218 switch (this->state)
219 {
220 case ALERT_SENDING:
221 case ALERT_SENT:
222 /* don't accept more input, fatal error ocurred */
223 return NEED_MORE;
224 case ALERT_NONE:
225 break;
226 }
227 reader = tls_reader_create(data);
228 switch (type)
229 {
230 case TLS_CHANGE_CIPHER_SPEC:
231 if (this->handshake->change_cipherspec(this->handshake))
232 {
233 status = NEED_MORE;
234 break;
235 }
236 status = FAILED;
237 break;
238 case TLS_ALERT:
239 status = process_alert(this, reader);
240 break;
241 case TLS_HANDSHAKE:
242 status = process_handshake(this, reader);
243 break;
244 case TLS_APPLICATION_DATA:
245 status = process_application(this, reader);
246 break;
247 default:
248 DBG1(DBG_TLS, "received unknown TLS content type %d, ignored", type);
249 status = NEED_MORE;
250 break;
251 }
252 reader->destroy(reader);
253 return status;
254 }
255
256 /**
257 * Check if alerts are pending
258 */
259 static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
260 {
261 tls_alert_level_t level;
262 tls_alert_desc_t desc;
263 tls_writer_t *writer;
264
265 if (this->alert->get(this->alert, &level, &desc))
266 {
267 writer = tls_writer_create(2);
268
269 writer->write_uint8(writer, level);
270 writer->write_uint8(writer, desc);
271
272 *data = chunk_clone(writer->get_buf(writer));
273 writer->destroy(writer);
274 return TRUE;
275 }
276 return FALSE;
277 }
278
279 METHOD(tls_fragmentation_t, build, status_t,
280 private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
281 {
282 chunk_t hs_data;
283 tls_handshake_type_t hs_type;
284 tls_writer_t *writer, *msg;
285 status_t status = INVALID_STATE;
286
287 switch (this->state)
288 {
289 case ALERT_SENDING:
290 this->state = ALERT_SENT;
291 return INVALID_STATE;
292 case ALERT_SENT:
293 return FAILED;
294 case ALERT_NONE:
295 break;
296 }
297 if (check_alerts(this, data))
298 {
299 this->state = ALERT_SENDING;
300 *type = TLS_ALERT;
301 return NEED_MORE;
302 }
303 if (this->handshake->cipherspec_changed(this->handshake))
304 {
305 *type = TLS_CHANGE_CIPHER_SPEC;
306 *data = chunk_clone(chunk_from_chars(0x01));
307 return NEED_MORE;
308 }
309
310 if (!this->output.len)
311 {
312 msg = tls_writer_create(64);
313
314 if (this->handshake->finished(this->handshake))
315 {
316 if (this->application)
317 {
318 status = this->application->build(this->application, msg);
319 if (status == INVALID_STATE)
320 {
321 *type = TLS_APPLICATION_DATA;
322 this->output = chunk_clone(msg->get_buf(msg));
323 }
324 else if (status != NEED_MORE)
325 {
326 this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
327 if (check_alerts(this, data))
328 {
329 this->state = ALERT_SENDING;
330 *type = TLS_ALERT;
331 return NEED_MORE;
332 }
333 }
334 }
335 }
336 else
337 {
338 do
339 {
340 writer = tls_writer_create(64);
341 status = this->handshake->build(this->handshake, &hs_type, writer);
342 switch (status)
343 {
344 case NEED_MORE:
345 hs_data = writer->get_buf(writer);
346 msg->write_uint8(msg, hs_type);
347 msg->write_data24(msg, hs_data);
348 DBG2(DBG_TLS, "sending TLS %N message (%u bytes)",
349 tls_handshake_type_names, hs_type, 4 + hs_data.len);
350 break;
351 case INVALID_STATE:
352 *type = TLS_HANDSHAKE;
353 this->output = chunk_clone(msg->get_buf(msg));
354 break;
355 default:
356 break;
357 }
358 writer->destroy(writer);
359 }
360 while (status == NEED_MORE);
361 }
362
363 msg->destroy(msg);
364 if (status != INVALID_STATE)
365 {
366 return status;
367 }
368 }
369
370 if (this->output.len)
371 {
372 if (this->output.len <= MAX_TLS_FRAGMENT_LEN)
373 {
374 *data = this->output;
375 this->output = chunk_empty;
376 return NEED_MORE;
377 }
378 *data = chunk_create(this->output.ptr, MAX_TLS_FRAGMENT_LEN);
379 this->output = chunk_clone(chunk_skip(this->output, MAX_TLS_FRAGMENT_LEN));
380 return NEED_MORE;
381 }
382 return status;
383 }
384
385 METHOD(tls_fragmentation_t, destroy, void,
386 private_tls_fragmentation_t *this)
387 {
388 free(this->input.ptr);
389 free(this->output.ptr);
390 free(this);
391 }
392
393 /**
394 * See header
395 */
396 tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
397 tls_alert_t *alert, tls_application_t *application)
398 {
399 private_tls_fragmentation_t *this;
400
401 INIT(this,
402 .public = {
403 .process = _process,
404 .build = _build,
405 .destroy = _destroy,
406 },
407 .handshake = handshake,
408 .alert = alert,
409 .state = ALERT_NONE,
410 .application = application,
411 );
412
413 return &this->public;
414 }