From 79a5e391f80efbd279c08ddfba9dc7c5e1a036e1 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 24 Aug 2010 09:02:40 +0200 Subject: support fragmentation in AVPs --- src/libcharon/plugins/eap_ttls/eap_ttls_avp.c | 112 ++++++++++++++++++++--- src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 14 ++- src/libcharon/plugins/eap_ttls/eap_ttls_server.c | 13 ++- 3 files changed, 118 insertions(+), 21 deletions(-) diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c index 2c840dd72..a621ffc3e 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c @@ -18,6 +18,7 @@ #include #define AVP_EAP_MESSAGE 79 +#define AVP_HEADER_LEN 8 typedef struct private_eap_ttls_avp_t private_eap_ttls_avp_t; @@ -30,6 +31,26 @@ struct private_eap_ttls_avp_t { * Public eap_ttls_avp_t interface. */ eap_ttls_avp_t public; + + /** + * AVP input buffer + */ + chunk_t input; + + /** + * Position in input buffer + */ + size_t inpos; + + /** + * process header (TRUE) or body (FALSE) + */ + bool process_header; + + /** + * Size of AVP data + */ + size_t data_len; }; METHOD(eap_ttls_avp_t, build, void, @@ -54,35 +75,92 @@ METHOD(eap_ttls_avp_t, build, void, METHOD(eap_ttls_avp_t, process, status_t, private_eap_ttls_avp_t* this, tls_reader_t *reader, chunk_t *data) { - u_int32_t avp_code; - u_int8_t avp_flags; - u_int32_t avp_len, data_len; + size_t len; + chunk_t buf; - if (!reader->read_uint32(reader, &avp_code) || - !reader->read_uint8(reader, &avp_flags) || - !reader->read_uint24(reader, &avp_len)) + if (this->process_header) { - DBG1(DBG_IKE, "received invalid AVP"); - return FAILED; + tls_reader_t *header; + u_int32_t avp_code; + u_int8_t avp_flags; + u_int32_t avp_len; + bool success; + + len = min(reader->remaining(reader), AVP_HEADER_LEN - this->inpos); + if (!reader->read_data(reader, len, &buf)) + { + return FAILED; + } + if (this->input.len == 0) + { + /* start of a new AVP header */ + this->input = chunk_alloc(AVP_HEADER_LEN); + memcpy(this->input.ptr, buf.ptr, len); + this->inpos = len; + } + else + { + memcpy(this->input.ptr + this->inpos, buf.ptr, len); + this->inpos += len; + } + + if (this->inpos < AVP_HEADER_LEN) + { + return NEED_MORE; + } + + /* parse AVP header */ + header = tls_reader_create(this->input); + success = header->read_uint32(header, &avp_code) && + header->read_uint8(header, &avp_flags) && + header->read_uint24(header, &avp_len); + header->destroy(header); + chunk_free(&this->input); + this->inpos = 0; + + if (!success) + { + DBG1(DBG_IKE, "received invalid AVP header"); + return FAILED; + } + if (avp_code != AVP_EAP_MESSAGE) + { + DBG1(DBG_IKE, "expected AVP_EAP_MESSAGE but received %u", avp_code); + return FAILED; + } + this->process_header = FALSE; + this->data_len = avp_len - 8; + this->input = chunk_alloc(this->data_len + (4 - avp_len) % 4); } - if (avp_code != AVP_EAP_MESSAGE) + + /* process AVP data */ + len = min(reader->remaining(reader), this->input.len - this->inpos); + if (!reader->read_data(reader, len, &buf)) { - DBG1(DBG_IKE, "expected AVP_EAP_MESSAGE but received %u", avp_code); return FAILED; } - data_len = avp_len - 8; - if (!reader->read_data(reader, data_len + (4 - avp_len) % 4, data)) + memcpy(this->input.ptr + this->inpos, buf.ptr, len); + this->inpos += len; + if (this->inpos < this->input.len) { - DBG1(DBG_IKE, "received insufficient AVP data"); - return FAILED; + return NEED_MORE; } - data->len = data_len; + + *data = this->input; + data->len = this->data_len; + + /* preparing for next AVP */ + this->input = chunk_empty; + this->inpos = 0; + this->process_header = TRUE; + return SUCCESS; } METHOD(eap_ttls_avp_t, destroy, void, private_eap_ttls_avp_t *this) { + chunk_free(&this->input); free(this); } @@ -99,6 +177,10 @@ eap_ttls_avp_t *eap_ttls_avp_create(void) .build = _build, .destroy = _destroy, }, + .input = chunk_empty, + .inpos = 0, + .process_header = TRUE, + .data_len = 0, ); return &this->public; diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index cbed4d12d..ace412de7 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -67,7 +67,7 @@ struct private_eap_ttls_peer_t { METHOD(tls_application_t, process, status_t, private_eap_ttls_peer_t *this, tls_reader_t *reader) { - chunk_t data; + chunk_t data = chunk_empty; status_t status; payload_t *payload; eap_payload_t *in; @@ -76,11 +76,19 @@ METHOD(tls_application_t, process, status_t, u_int32_t vendor, received_vendor; status = this->avp->process(this->avp, reader, &data); - if (status == FAILED) + switch (status) { - return FAILED; + case SUCCESS: + break; + case NEED_MORE: + DBG1(DBG_IKE, "need more AVP data"); + return NEED_MORE; + case FAILED: + default: + return FAILED; } in = eap_payload_create_data(data); + chunk_free(&data); payload = (payload_t*)in; if (payload->verify(payload) != SUCCESS) diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index c4a18a434..17a520d99 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -67,7 +67,7 @@ struct private_eap_ttls_server_t { METHOD(tls_application_t, process, status_t, private_eap_ttls_server_t *this, tls_reader_t *reader) { - chunk_t data; + chunk_t data = chunk_empty; status_t status; payload_t *payload; eap_payload_t *in; @@ -76,11 +76,18 @@ METHOD(tls_application_t, process, status_t, u_int32_t vendor, received_vendor; status = this->avp->process(this->avp, reader, &data); - if (status == FAILED) + switch (status) { - return FAILED; + case SUCCESS: + break; + case NEED_MORE: + return NEED_MORE; + case FAILED: + default: + return FAILED; } in = eap_payload_create_data(data); + chunk_free(&data); payload = (payload_t*)in; if (payload->verify(payload) != SUCCESS) -- cgit v1.2.3