diff options
author | Martin Willi <martin@revosec.ch> | 2010-01-25 10:44:35 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-08-03 15:39:24 +0200 |
commit | 4c0c2283a51bab1d992dc2c7337b5e81906ab9e4 (patch) | |
tree | 349b2feadc189489490480561c15807ad45d2651 /src/charon/plugins/eap_tls/tls/tls_fragmentation.c | |
parent | 4c0124a0a2bf535e741ffde067209450cb91b475 (diff) | |
download | strongswan-4c0c2283a51bab1d992dc2c7337b5e81906ab9e4.tar.bz2 strongswan-4c0c2283a51bab1d992dc2c7337b5e81906ab9e4.tar.xz |
Added stubs for handshake handling, server and peer variants
Diffstat (limited to 'src/charon/plugins/eap_tls/tls/tls_fragmentation.c')
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_fragmentation.c | 134 |
1 files changed, 131 insertions, 3 deletions
diff --git a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c index c1cfa0559..0d38e4890 100644 --- a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c +++ b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c @@ -28,30 +28,157 @@ struct private_tls_fragmentation_t { * Public tls_fragmentation_t interface. */ tls_fragmentation_t public; + + /** + * Upper layer handshake protocol + */ + tls_handshake_t *handshake; + + /** + * Handshake input buffer + */ + chunk_t input; + + /** + * Position in input buffer + */ + size_t inpos; + + /** + * Currently processed handshake message type + */ + tls_handshake_type_t type; }; +/** + * Maximum size of a TLS fragment + */ +#define MAX_TLS_FRAGMENT_LEN 16384 + +/** + * Maximum size of a TLS handshake message we accept + */ +#define MAX_TLS_HANDSHAKE_LEN 65536 + +/** + * TLS handshake message header + */ +typedef union { + u_int8_t type; + /* 24bit length field */ + u_int32_t length; +} tls_handshake_header_t; + +/** + * Process TLS handshake protocol data + */ +static status_t process_handshake(private_tls_fragmentation_t *this, + chunk_t data) +{ + while (data.len) + { + u_int32_t len; + status_t status; + tls_handshake_header_t *hdr; + + if (data.len == 0 || data.len > MAX_TLS_FRAGMENT_LEN) + { + DBG1(DBG_IKE, "TLS fragment has invalid length"); + return FAILED; + } + + if (this->input.len == 0) + { /* new handshake message */ + if (data.len < sizeof(tls_handshake_header_t)) + { + DBG1(DBG_IKE, "initial TLS fragment too short %B", &data); + return FAILED; + } + hdr = (tls_handshake_header_t*)data.ptr; + len = untoh32(&hdr->length) & 0x00FFFFFF; + this->type = hdr->type; + if (len > MAX_TLS_HANDSHAKE_LEN) + { + DBG1(DBG_IKE, "TLS handshake message exceeds maximum length"); + return FAILED; + } + this->input = len ? chunk_alloc(len) : chunk_empty; + this->inpos = 0; + data = chunk_skip(data, sizeof(tls_handshake_header_t)); + } + + len = min(this->input.len - this->inpos, data.len); + memcpy(this->input.ptr + this->inpos, data.ptr, len); + this->inpos += len; + data = chunk_skip(data, len); + + if (this->input.len == this->inpos) + { /* message completely defragmented, process */ + status = this->handshake->process(this->handshake, + this->type, this->input); + chunk_free(&this->input); + if (status != NEED_MORE) + { + return status; + } + } + } + return NEED_MORE; +} + METHOD(tls_fragmentation_t, process, status_t, private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data) { - return NEED_MORE; + switch (type) + { + case TLS_CHANGE_CIPHER_SPEC: + /* TODO: handle ChangeCipherSpec */ + return FAILED; + case TLS_ALERT: + /* TODO: handle Alert */ + return FAILED; + case TLS_HANDSHAKE: + return process_handshake(this, data); + case TLS_APPLICATION_DATA: + /* skip application data */ + return NEED_MORE; + default: + DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type); + return NEED_MORE; + } } METHOD(tls_fragmentation_t, build, status_t, private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data) { - return INVALID_STATE; + tls_handshake_header_t header; + tls_handshake_type_t hs_type; + chunk_t hs_data; + status_t status; + + status = this->handshake->build(this->handshake, &hs_type, &hs_data); + if (status != NEED_MORE) + { + return status; + } + htoun32(&header.length, hs_data.len); + header.type |= hs_type; + *data = chunk_cat("cm", chunk_from_thing(header), hs_data); + *type = TLS_HANDSHAKE; + return NEED_MORE; } METHOD(tls_fragmentation_t, destroy, void, private_tls_fragmentation_t *this) { + free(this->input.ptr); free(this); } /** * See header */ -tls_fragmentation_t *tls_fragmentation_create() +tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake) { private_tls_fragmentation_t *this; @@ -61,6 +188,7 @@ tls_fragmentation_t *tls_fragmentation_create() .build = _build, .destroy = _destroy, }, + .handshake = handshake, ); return &this->public; |