2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
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"
27 ENUM_BEGIN(tls_version_names
, SSL_2_0
, SSL_2_0
,
29 ENUM_NEXT(tls_version_names
, SSL_3_0
, TLS_1_2
, SSL_2_0
,
34 ENUM_END(tls_version_names
, TLS_1_2
);
36 ENUM(tls_content_type_names
, TLS_CHANGE_CIPHER_SPEC
, TLS_APPLICATION_DATA
,
43 ENUM_BEGIN(tls_handshake_type_names
, TLS_HELLO_REQUEST
, TLS_SERVER_HELLO
,
47 ENUM_NEXT(tls_handshake_type_names
,
48 TLS_CERTIFICATE
, TLS_CLIENT_KEY_EXCHANGE
, TLS_SERVER_HELLO
,
55 ENUM_NEXT(tls_handshake_type_names
,
56 TLS_FINISHED
, TLS_FINISHED
, TLS_CLIENT_KEY_EXCHANGE
,
58 ENUM_END(tls_handshake_type_names
, TLS_FINISHED
);
60 ENUM_BEGIN(tls_extension_names
, TLS_EXT_SERVER_NAME
, TLS_EXT_STATUS_REQUEST
,
62 "max fragment length",
63 "client certificate url",
67 ENUM_NEXT(tls_extension_names
,
68 TLS_EXT_ELLIPTIC_CURVES
, TLS_EXT_EC_POINT_FORMATS
,
69 TLS_EXT_STATUS_REQUEST
,
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
);
85 typedef struct __attribute__((packed
)) {
92 typedef struct private_tls_t private_tls_t
;
95 * Private data of an tls_protection_t object.
97 struct private_tls_t
{
100 * Public tls_t interface.
105 * Role this TLS stack acts as.
112 identification_t
*server
;
117 identification_t
*peer
;
120 * Negotiated TLS version
122 tls_version_t version
;
125 * TLS stack purpose, as given to constructor
127 tls_purpose_t purpose
;
130 * TLS record protection layer
132 tls_protection_t
*protection
;
135 * TLS record compression layer
137 tls_compression_t
*compression
;
140 * TLS record fragmentation layer
142 tls_fragmentation_t
*fragmentation
;
150 * TLS crypto helper context
152 tls_crypto_t
*crypto
;
155 * TLS handshake protocol handler
157 tls_handshake_t
*handshake
;
160 * TLS application data handler
162 tls_application_t
*application
;
165 * Allocated input buffer
170 * Number of bytes read in input buffer
175 * Allocated output buffer
180 * Number of bytes processed from output buffer
185 * Partial TLS record header received
190 * Position in partially received record header
196 * Described in header.
198 void libtls_init(void)
203 METHOD(tls_t
, process
, status_t
,
204 private_tls_t
*this, void *buf
, size_t buflen
)
206 tls_record_t
*record
;
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
;
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
);
229 if (this->input
.len
== 0)
231 if (buflen
< sizeof(tls_record_t
))
233 DBG2(DBG_TLS
, "received incomplete TLS record header");
234 memcpy(&this->head
, buf
, buflen
);
235 this->headpos
= buflen
;
240 /* try to process records inline */
242 len
= untoh16(&record
->length
);
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
));
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
)
258 buf
+= len
+ sizeof(tls_record_t
);
259 buflen
-= len
+ sizeof(tls_record_t
);
266 len
= min(buflen
, this->input
.len
- this->inpos
);
267 memcpy(this->input
.ptr
+ this->inpos
, buf
, 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
)
275 record
= (tls_record_t
*)this->input
.ptr
;
276 len
= untoh16(&record
->length
);
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
);
284 if (status
!= NEED_MORE
)
293 METHOD(tls_t
, build
, status_t
,
294 private_tls_t
*this, void *buf
, size_t *buflen
, size_t *msglen
)
296 tls_content_type_t type
;
303 if (this->output
.len
== 0)
305 /* query upper layers for new records, as many as we can get */
308 status
= this->protection
->build(this->protection
, &type
, &data
);
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
);
321 if (this->output
.len
== 0)
323 return INVALID_STATE
;
333 *msglen
= this->output
.len
;
343 len
= min(len
, this->output
.len
- this->outpos
);
344 memcpy(buf
, this->output
.ptr
+ this->outpos
, len
);
347 if (this->outpos
== this->output
.len
)
349 chunk_free(&this->output
);
356 METHOD(tls_t
, is_server
, bool,
359 return this->is_server
;
362 METHOD(tls_t
, get_version
, tls_version_t
,
365 return this->version
;
368 METHOD(tls_t
, set_version
, bool,
369 private_tls_t
*this, tls_version_t version
)
371 if (version
> this->version
)
380 this->version
= version
;
381 this->protection
->set_version(this->protection
, version
);
390 METHOD(tls_t
, get_purpose
, tls_purpose_t
,
393 return this->purpose
;
396 METHOD(tls_t
, is_complete
, bool,
399 if (this->handshake
->finished(this->handshake
))
401 if (!this->application
)
405 return this->fragmentation
->application_finished(this->fragmentation
);
410 METHOD(tls_t
, get_eap_msk
, chunk_t
,
413 return this->crypto
->get_eap_msk(this->crypto
);
416 METHOD(tls_t
, destroy
, void,
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
);
429 free(this->input
.ptr
);
430 free(this->output
.ptr
);
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
)
446 case TLS_PURPOSE_EAP_TLS
:
447 case TLS_PURPOSE_EAP_TTLS
:
448 case TLS_PURPOSE_EAP_PEAP
:
449 case TLS_PURPOSE_GENERIC
:
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
,
467 .is_server
= is_server
,
469 .server
= server
->clone(server
),
470 .peer
= peer
? peer
->clone(peer
) : NULL
,
471 .application
= application
,
475 this->crypto
= tls_crypto_create(&this->public, cache
);
476 this->alert
= tls_alert_create();
479 this->handshake
= &tls_server_create(&this->public, this->crypto
,
480 this->alert
, this->server
, this->peer
)->handshake
;
484 this->handshake
= &tls_peer_create(&this->public, this->crypto
,
485 this->alert
, this->peer
, this->server
)->handshake
;
487 this->fragmentation
= tls_fragmentation_create(this->handshake
, this->alert
,
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
);
493 return &this->public;