]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libtls/tls.c
Implemented TLS session resumption both as client and as server
[thirdparty/strongswan.git] / src / libtls / tls.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.h"
17
18 #include <debug.h>
19
20 #include "tls_protection.h"
21 #include "tls_compression.h"
22 #include "tls_fragmentation.h"
23 #include "tls_crypto.h"
24 #include "tls_server.h"
25 #include "tls_peer.h"
26
27 ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
28 "SSLv2");
29 ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
30 "SSLv3",
31 "TLS 1.0",
32 "TLS 1.1",
33 "TLS 1.2");
34 ENUM_END(tls_version_names, TLS_1_2);
35
36 ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
37 "ChangeCipherSpec",
38 "Alert",
39 "Handshake",
40 "ApplicationData",
41 );
42
43 ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
44 "HelloRequest",
45 "ClientHello",
46 "ServerHello");
47 ENUM_NEXT(tls_handshake_type_names,
48 TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
49 "Certificate",
50 "ServerKeyExchange",
51 "CertificateRequest",
52 "ServerHelloDone",
53 "CertificateVerify",
54 "ClientKeyExchange");
55 ENUM_NEXT(tls_handshake_type_names,
56 TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
57 "Finished");
58 ENUM_END(tls_handshake_type_names, TLS_FINISHED);
59
60 ENUM_BEGIN(tls_extension_names, TLS_EXT_SERVER_NAME, TLS_EXT_STATUS_REQUEST,
61 "server name",
62 "max fragment length",
63 "client certificate url",
64 "trusted ca keys",
65 "truncated hmac",
66 "status request");
67 ENUM_NEXT(tls_extension_names,
68 TLS_EXT_ELLIPTIC_CURVES, TLS_EXT_EC_POINT_FORMATS,
69 TLS_EXT_STATUS_REQUEST,
70 "elliptic curves",
71 "ec point formats");
72 ENUM_NEXT(tls_extension_names,
73 TLS_EXT_SIGNATURE_ALGORITHMS, TLS_EXT_SIGNATURE_ALGORITHMS,
74 TLS_EXT_EC_POINT_FORMATS,
75 "signature algorithms");
76 ENUM_NEXT(tls_extension_names,
77 TLS_EXT_RENEGOTIATION_INFO, TLS_EXT_RENEGOTIATION_INFO,
78 TLS_EXT_SIGNATURE_ALGORITHMS,
79 "renegotiation info");
80 ENUM_END(tls_extension_names, TLS_EXT_RENEGOTIATION_INFO);
81
82 /**
83 * TLS record
84 */
85 typedef struct __attribute__((packed)) {
86 u_int8_t type;
87 u_int16_t version;
88 u_int16_t length;
89 char data[];
90 } tls_record_t;
91
92 typedef struct private_tls_t private_tls_t;
93
94 /**
95 * Private data of an tls_protection_t object.
96 */
97 struct private_tls_t {
98
99 /**
100 * Public tls_t interface.
101 */
102 tls_t public;
103
104 /**
105 * Role this TLS stack acts as.
106 */
107 bool is_server;
108
109 /**
110 * Server identity
111 */
112 identification_t *server;
113
114 /**
115 * Peer identity
116 */
117 identification_t *peer;
118
119 /**
120 * Negotiated TLS version
121 */
122 tls_version_t version;
123
124 /**
125 * TLS stack purpose, as given to constructor
126 */
127 tls_purpose_t purpose;
128
129 /**
130 * TLS record protection layer
131 */
132 tls_protection_t *protection;
133
134 /**
135 * TLS record compression layer
136 */
137 tls_compression_t *compression;
138
139 /**
140 * TLS record fragmentation layer
141 */
142 tls_fragmentation_t *fragmentation;
143
144 /**
145 * TLS alert handler
146 */
147 tls_alert_t *alert;
148
149 /**
150 * TLS crypto helper context
151 */
152 tls_crypto_t *crypto;
153
154 /**
155 * TLS handshake protocol handler
156 */
157 tls_handshake_t *handshake;
158
159 /**
160 * TLS application data handler
161 */
162 tls_application_t *application;
163
164 /**
165 * Allocated input buffer
166 */
167 chunk_t input;
168
169 /**
170 * Number of bytes read in input buffer
171 */
172 size_t inpos;
173
174 /**
175 * Allocated output buffer
176 */
177 chunk_t output;
178
179 /**
180 * Number of bytes processed from output buffer
181 */
182 size_t outpos;
183
184 /**
185 * Partial TLS record header received
186 */
187 tls_record_t head;
188
189 /**
190 * Position in partially received record header
191 */
192 size_t headpos;
193 };
194
195 /**
196 * Described in header.
197 */
198 void libtls_init(void)
199 {
200 /* empty */
201 }
202
203 METHOD(tls_t, process, status_t,
204 private_tls_t *this, void *buf, size_t buflen)
205 {
206 tls_record_t *record;
207 status_t status;
208 u_int len;
209
210 if (this->headpos)
211 { /* have a partial TLS record header, try to complete it */
212 len = min(buflen, sizeof(this->head) - this->headpos);
213 memcpy(((char*)&this->head) + this->headpos, buf, len);
214 this->headpos += len;
215 buflen -= len;
216 buf += len;
217 if (this->headpos == sizeof(this->head))
218 { /* header complete, allocate space with new header */
219 len = untoh16(&this->head.length);
220 this->input = chunk_alloc(len + sizeof(tls_record_t));
221 memcpy(this->input.ptr, &this->head, sizeof(this->head));
222 this->inpos = sizeof(this->head);
223 this->headpos = 0;
224 }
225 }
226
227 while (buflen)
228 {
229 if (this->input.len == 0)
230 {
231 if (buflen < sizeof(tls_record_t))
232 {
233 DBG2(DBG_TLS, "received incomplete TLS record header");
234 memcpy(&this->head, buf, buflen);
235 this->headpos = buflen;
236 break;
237 }
238 while (TRUE)
239 {
240 /* try to process records inline */
241 record = buf;
242 len = untoh16(&record->length);
243
244 if (len + sizeof(tls_record_t) > buflen)
245 { /* not a full record, read to buffer */
246 this->input = chunk_alloc(len + sizeof(tls_record_t));
247 this->inpos = 0;
248 break;
249 }
250 DBG2(DBG_TLS, "processing TLS %N record (%d bytes)",
251 tls_content_type_names, record->type, len);
252 status = this->protection->process(this->protection,
253 record->type, chunk_create(record->data, len));
254 if (status != NEED_MORE)
255 {
256 return status;
257 }
258 buf += len + sizeof(tls_record_t);
259 buflen -= len + sizeof(tls_record_t);
260 if (buflen == 0)
261 {
262 return NEED_MORE;
263 }
264 }
265 }
266 len = min(buflen, this->input.len - this->inpos);
267 memcpy(this->input.ptr + this->inpos, buf, len);
268 buf += len;
269 buflen -= len;
270 this->inpos += len;
271 DBG2(DBG_TLS, "buffering %d bytes, %d bytes of %d byte TLS record received",
272 len, this->inpos, this->input.len);
273 if (this->input.len == this->inpos)
274 {
275 record = (tls_record_t*)this->input.ptr;
276 len = untoh16(&record->length);
277
278 DBG2(DBG_TLS, "processing buffered TLS %N record (%d bytes)",
279 tls_content_type_names, record->type, len);
280 status = this->protection->process(this->protection,
281 record->type, chunk_create(record->data, len));
282 chunk_free(&this->input);
283 this->inpos = 0;
284 if (status != NEED_MORE)
285 {
286 return status;
287 }
288 }
289 }
290 return NEED_MORE;
291 }
292
293 METHOD(tls_t, build, status_t,
294 private_tls_t *this, void *buf, size_t *buflen, size_t *msglen)
295 {
296 tls_content_type_t type;
297 tls_record_t record;
298 status_t status;
299 chunk_t data;
300 size_t len;
301
302 len = *buflen;
303 if (this->output.len == 0)
304 {
305 /* query upper layers for new records, as many as we can get */
306 while (TRUE)
307 {
308 status = this->protection->build(this->protection, &type, &data);
309 switch (status)
310 {
311 case NEED_MORE:
312 record.type = type;
313 htoun16(&record.version, this->version);
314 htoun16(&record.length, data.len);
315 this->output = chunk_cat("mcm", this->output,
316 chunk_from_thing(record), data);
317 DBG2(DBG_TLS, "sending TLS %N record (%d bytes)",
318 tls_content_type_names, type, data.len);
319 continue;
320 case INVALID_STATE:
321 if (this->output.len == 0)
322 {
323 return INVALID_STATE;
324 }
325 break;
326 default:
327 return status;
328 }
329 break;
330 }
331 if (msglen)
332 {
333 *msglen = this->output.len;
334 }
335 }
336 else
337 {
338 if (msglen)
339 {
340 *msglen = 0;
341 }
342 }
343 len = min(len, this->output.len - this->outpos);
344 memcpy(buf, this->output.ptr + this->outpos, len);
345 this->outpos += len;
346 *buflen = len;
347 if (this->outpos == this->output.len)
348 {
349 chunk_free(&this->output);
350 this->outpos = 0;
351 return ALREADY_DONE;
352 }
353 return NEED_MORE;
354 }
355
356 METHOD(tls_t, is_server, bool,
357 private_tls_t *this)
358 {
359 return this->is_server;
360 }
361
362 METHOD(tls_t, get_version, tls_version_t,
363 private_tls_t *this)
364 {
365 return this->version;
366 }
367
368 METHOD(tls_t, set_version, bool,
369 private_tls_t *this, tls_version_t version)
370 {
371 if (version > this->version)
372 {
373 return FALSE;
374 }
375 switch (version)
376 {
377 case TLS_1_0:
378 case TLS_1_1:
379 case TLS_1_2:
380 this->version = version;
381 this->protection->set_version(this->protection, version);
382 return TRUE;
383 case SSL_2_0:
384 case SSL_3_0:
385 default:
386 return FALSE;
387 }
388 }
389
390 METHOD(tls_t, get_purpose, tls_purpose_t,
391 private_tls_t *this)
392 {
393 return this->purpose;
394 }
395
396 METHOD(tls_t, is_complete, bool,
397 private_tls_t *this)
398 {
399 if (this->handshake->finished(this->handshake))
400 {
401 if (!this->application)
402 {
403 return TRUE;
404 }
405 return this->fragmentation->application_finished(this->fragmentation);
406 }
407 return FALSE;
408 }
409
410 METHOD(tls_t, get_eap_msk, chunk_t,
411 private_tls_t *this)
412 {
413 return this->crypto->get_eap_msk(this->crypto);
414 }
415
416 METHOD(tls_t, destroy, void,
417 private_tls_t *this)
418 {
419 this->protection->destroy(this->protection);
420 this->compression->destroy(this->compression);
421 this->fragmentation->destroy(this->fragmentation);
422 this->crypto->destroy(this->crypto);
423 this->handshake->destroy(this->handshake);
424 DESTROY_IF(this->peer);
425 this->server->destroy(this->server);
426 DESTROY_IF(this->application);
427 this->alert->destroy(this->alert);
428
429 free(this->input.ptr);
430 free(this->output.ptr);
431
432 free(this);
433 }
434
435 /**
436 * See header
437 */
438 tls_t *tls_create(bool is_server, identification_t *server,
439 identification_t *peer, tls_purpose_t purpose,
440 tls_application_t *application, tls_cache_t *cache)
441 {
442 private_tls_t *this;
443
444 switch (purpose)
445 {
446 case TLS_PURPOSE_EAP_TLS:
447 case TLS_PURPOSE_EAP_TTLS:
448 case TLS_PURPOSE_EAP_PEAP:
449 case TLS_PURPOSE_GENERIC:
450 break;
451 default:
452 return NULL;
453 }
454
455 INIT(this,
456 .public = {
457 .process = _process,
458 .build = _build,
459 .is_server = _is_server,
460 .get_version = _get_version,
461 .set_version = _set_version,
462 .get_purpose = _get_purpose,
463 .is_complete = _is_complete,
464 .get_eap_msk = _get_eap_msk,
465 .destroy = _destroy,
466 },
467 .is_server = is_server,
468 .version = TLS_1_2,
469 .server = server->clone(server),
470 .peer = peer ? peer->clone(peer) : NULL,
471 .application = application,
472 .purpose = purpose,
473 );
474
475 this->crypto = tls_crypto_create(&this->public, cache);
476 this->alert = tls_alert_create();
477 if (is_server)
478 {
479 this->handshake = &tls_server_create(&this->public, this->crypto,
480 this->alert, this->server, this->peer)->handshake;
481 }
482 else
483 {
484 this->handshake = &tls_peer_create(&this->public, this->crypto,
485 this->alert, this->peer, this->server)->handshake;
486 }
487 this->fragmentation = tls_fragmentation_create(this->handshake, this->alert,
488 this->application);
489 this->compression = tls_compression_create(this->fragmentation, this->alert);
490 this->protection = tls_protection_create(this->compression, this->alert);
491 this->crypto->set_protection(this->crypto, this->protection);
492
493 return &this->public;
494 }