Annotation of embedaddon/strongswan/src/libtls/tls.c, revision 1.1.1.1
1.1 misho 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 <utils/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: uint8_t type;
87: uint16_t version;
88: uint16_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: * Negotiated TLS version
111: */
112: tls_version_t version;
113:
114: /**
115: * TLS stack purpose, as given to constructor
116: */
117: tls_purpose_t purpose;
118:
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;
133:
134: /**
135: * TLS alert handler
136: */
137: tls_alert_t *alert;
138:
139: /**
140: * TLS crypto helper context
141: */
142: tls_crypto_t *crypto;
143:
144: /**
145: * TLS handshake protocol handler
146: */
147: tls_handshake_t *handshake;
148:
149: /**
150: * TLS application data handler
151: */
152: tls_application_t *application;
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;
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;
173:
174: /**
175: * Position in partially received record header
176: */
177: size_t headpos;
178:
179: /**
180: * Partial TLS record header received
181: */
182: tls_record_t head;
183: };
184:
185: /**
186: * Described in header.
187: */
188: void libtls_init(void)
189: {
190: /* empty */
191: }
192:
193: METHOD(tls_t, process, status_t,
194: private_tls_t *this, void *buf, size_t buflen)
195: {
196: tls_record_t *record;
197: status_t status;
198: u_int len;
199:
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:
217: while (buflen)
218: {
219: if (this->input.len == 0)
220: {
221: while (buflen >= sizeof(tls_record_t))
222: {
223: /* try to process records inline */
224: record = buf;
225: len = untoh16(&record->length);
226:
227: if (len + sizeof(tls_record_t) > buflen)
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: }
241: buf += len + sizeof(tls_record_t);
242: buflen -= len + sizeof(tls_record_t);
243: if (buflen == 0)
244: {
245: return NEED_MORE;
246: }
247: }
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: }
255: }
256: len = min(buflen, this->input.len - this->inpos);
257: memcpy(this->input.ptr + this->inpos, buf, len);
258: buf += len;
259: buflen -= len;
260: this->inpos += len;
261: DBG2(DBG_TLS, "buffering %d bytes, %d bytes of %d byte TLS record received",
262: len, this->inpos, this->input.len);
263: if (this->input.len == this->inpos)
264: {
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: }
278: }
279: }
280: return NEED_MORE;
281: }
282:
283: METHOD(tls_t, build, status_t,
284: private_tls_t *this, void *buf, size_t *buflen, size_t *msglen)
285: {
286: tls_content_type_t type;
287: tls_record_t record;
288: status_t status;
289: chunk_t data;
290: size_t len;
291:
292: len = *buflen;
293: if (this->output.len == 0)
294: {
295: /* query upper layers for new records, as many as we can get */
296: while (TRUE)
297: {
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;
324: }
325: }
326: else
327: {
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;
344: }
345:
346: METHOD(tls_t, is_server, bool,
347: private_tls_t *this)
348: {
349: return this->is_server;
350: }
351:
352: METHOD(tls_t, get_server_id, identification_t*,
353: private_tls_t *this)
354: {
355: return this->handshake->get_server_id(this->handshake);
356: }
357:
358: METHOD(tls_t, get_peer_id, identification_t*,
359: private_tls_t *this)
360: {
361: return this->handshake->get_peer_id(this->handshake);
362: }
363:
364: METHOD(tls_t, get_version, tls_version_t,
365: private_tls_t *this)
366: {
367: return this->version;
368: }
369:
370: METHOD(tls_t, set_version, bool,
371: private_tls_t *this, tls_version_t version)
372: {
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;
383: this->protection->set_version(this->protection, version);
384: return TRUE;
385: case SSL_2_0:
386: case SSL_3_0:
387: default:
388: return FALSE;
389: }
390: }
391:
392: METHOD(tls_t, get_purpose, tls_purpose_t,
393: private_tls_t *this)
394: {
395: return this->purpose;
396: }
397:
398: METHOD(tls_t, is_complete, bool,
399: private_tls_t *this)
400: {
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;
410: }
411:
412: METHOD(tls_t, get_eap_msk, chunk_t,
413: private_tls_t *this)
414: {
415: return this->crypto->get_eap_msk(this->crypto);
416: }
417:
418: METHOD(tls_t, get_auth, auth_cfg_t*,
419: private_tls_t *this)
420: {
421: return this->handshake->get_auth(this->handshake);
422: }
423:
424: METHOD(tls_t, destroy, void,
425: private_tls_t *this)
426: {
427: this->protection->destroy(this->protection);
428: this->compression->destroy(this->compression);
429: this->fragmentation->destroy(this->fragmentation);
430: this->crypto->destroy(this->crypto);
431: this->handshake->destroy(this->handshake);
432: DESTROY_IF(this->application);
433: this->alert->destroy(this->alert);
434:
435: free(this->input.ptr);
436: free(this->output.ptr);
437:
438: free(this);
439: }
440:
441: /**
442: * See header
443: */
444: tls_t *tls_create(bool is_server, identification_t *server,
445: identification_t *peer, tls_purpose_t purpose,
446: tls_application_t *application, tls_cache_t *cache)
447: {
448: private_tls_t *this;
449:
450: switch (purpose)
451: {
452: case TLS_PURPOSE_EAP_TLS:
453: case TLS_PURPOSE_EAP_TTLS:
454: case TLS_PURPOSE_EAP_PEAP:
455: case TLS_PURPOSE_GENERIC:
456: case TLS_PURPOSE_GENERIC_NULLOK:
457: break;
458: default:
459: return NULL;
460: }
461:
462: INIT(this,
463: .public = {
464: .process = _process,
465: .build = _build,
466: .is_server = _is_server,
467: .get_server_id = _get_server_id,
468: .get_peer_id = _get_peer_id,
469: .get_version = _get_version,
470: .set_version = _set_version,
471: .get_purpose = _get_purpose,
472: .is_complete = _is_complete,
473: .get_eap_msk = _get_eap_msk,
474: .get_auth = _get_auth,
475: .destroy = _destroy,
476: },
477: .is_server = is_server,
478: .version = TLS_1_2,
479: .application = application,
480: .purpose = purpose,
481: );
482: lib->settings->add_fallback(lib->settings, "%s.tls", "libtls", lib->ns);
483:
484: this->crypto = tls_crypto_create(&this->public, cache);
485: this->alert = tls_alert_create();
486: if (is_server)
487: {
488: this->handshake = &tls_server_create(&this->public, this->crypto,
489: this->alert, server, peer)->handshake;
490: }
491: else
492: {
493: this->handshake = &tls_peer_create(&this->public, this->crypto,
494: this->alert, peer, server)->handshake;
495: }
496: this->fragmentation = tls_fragmentation_create(this->handshake, this->alert,
497: this->application, purpose);
498: this->compression = tls_compression_create(this->fragmentation, this->alert);
499: this->protection = tls_protection_create(this->compression, this->alert);
500: this->crypto->set_protection(this->crypto, this->protection);
501:
502: return &this->public;
503: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>