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