diff options
Diffstat (limited to 'src/libtls/tls_eap.c')
-rw-r--r-- | src/libtls/tls_eap.c | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/src/libtls/tls_eap.c b/src/libtls/tls_eap.c index 685904fdf..928aadcb3 100644 --- a/src/libtls/tls_eap.c +++ b/src/libtls/tls_eap.c @@ -21,8 +21,11 @@ #include <debug.h> #include <library.h> -/** Size limit for a single TLS message */ -#define MAX_TLS_MESSAGE_LEN 65536 +/** + * Size limit for a TLS message allowing for worst-case protection overhead + * according to section 6.2.3. "Payload Protection" of RFC 5246 TLS 1.2 + */ +#define TLS_MAX_MESSAGE_LEN 4 * (TLS_MAX_FRAGMENT_LEN + 2048) typedef struct private_tls_eap_t private_tls_eap_t; @@ -79,7 +82,7 @@ struct private_tls_eap_t { int processed; /** - * Maximum number of processed EAP messages/fragments + * Maximum number of processed EAP messages/fragments */ int max_msg_count; }; @@ -138,7 +141,7 @@ METHOD(tls_eap_t, initiate, status_t, *out = chunk_clone(chunk_from_thing(pkt)); DBG2(DBG_TLS, "sending %N start packet (%u bytes)", - eap_type_names, this->type, sizeof(eap_tls_packet_t)); + eap_type_names, this->type, sizeof(eap_tls_packet_t)); DBG3(DBG_TLS, "%B", out); return NEED_MORE; } @@ -150,10 +153,12 @@ METHOD(tls_eap_t, initiate, status_t, */ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt) { - u_int32_t msg_len; u_int16_t pkt_len; + u_int32_t msg_len; + size_t msg_len_offset = 0; pkt_len = untoh16(&pkt->length); + if (pkt->flags & EAP_TLS_LENGTH) { if (pkt_len < sizeof(eap_tls_packet_t) + sizeof(msg_len)) @@ -163,16 +168,17 @@ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt) } msg_len = untoh32(pkt + 1); if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) || - msg_len > MAX_TLS_MESSAGE_LEN) + msg_len > TLS_MAX_MESSAGE_LEN) { - DBG1(DBG_TLS, "invalid %N packet length", eap_type_names, this->type); + DBG1(DBG_TLS, "invalid %N packet length (%u bytes)", eap_type_names, + this->type, msg_len); return FAILED; } - return this->tls->process(this->tls, (char*)(pkt + 1) + sizeof(msg_len), - pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len)); + msg_len_offset = sizeof(msg_len); } - return this->tls->process(this->tls, (char*)(pkt + 1), - pkt_len - sizeof(eap_tls_packet_t)); + + return this->tls->process(this->tls, (char*)(pkt + 1) + msg_len_offset, + pkt_len - sizeof(eap_tls_packet_t) - msg_len_offset); } /** @@ -182,7 +188,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) { char buf[this->frag_size]; eap_tls_packet_t *pkt; - size_t len, reclen; + size_t len, reclen, msg_len_offset; status_t status; char *kind; @@ -214,15 +220,16 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) if (this->first_fragment) { len = sizeof(buf) - sizeof(eap_tls_packet_t) - sizeof(u_int32_t); - status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) + - sizeof(u_int32_t), &len, &reclen); + msg_len_offset = sizeof(u_int32_t); } else { len = sizeof(buf) - sizeof(eap_tls_packet_t); - status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t), - &len, &reclen); + msg_len_offset = 0; } + status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) + + msg_len_offset, &len, &reclen); + switch (status) { case NEED_MORE: @@ -230,7 +237,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) kind = "further fragment"; if (this->first_fragment) { - pkt->flags |= EAP_TLS_LENGTH; + pkt->flags |= EAP_TLS_LENGTH; this->first_fragment = FALSE; kind = "first fragment"; } @@ -244,11 +251,15 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) } kind = "packet"; } - else + else if (this->type != EAP_TNC) { this->first_fragment = TRUE; kind = "final fragment"; } + else + { + kind = "packet"; + } break; default: return status; @@ -256,7 +267,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) if (reclen) { if (pkt->flags & EAP_TLS_LENGTH) - { + { htoun32(pkt + 1, reclen); len += sizeof(u_int32_t); pkt->flags |= EAP_TLS_LENGTH; @@ -264,15 +275,15 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) else { /* get rid of the reserved length field */ - memcpy(buf+sizeof(eap_packet_t), - buf+sizeof(eap_packet_t)+sizeof(u_int32_t), len); + memmove(buf + sizeof(eap_tls_packet_t), + buf + sizeof(eap_tls_packet_t) + sizeof(u_int32_t), len); } } len += sizeof(eap_tls_packet_t); htoun16(&pkt->length, len); *out = chunk_clone(chunk_create(buf, len)); DBG2(DBG_TLS, "sending %N %s (%u bytes)", - eap_type_names, this->type, kind, len); + eap_type_names, this->type, kind, len); DBG3(DBG_TLS, "%B", out); return NEED_MORE; } @@ -319,7 +330,7 @@ METHOD(tls_eap_t, process, status_t, eap_tls_packet_t *pkt; status_t status; - if (++this->processed > this->max_msg_count) + if (this->max_msg_count && ++this->processed > this->max_msg_count) { DBG1(DBG_TLS, "%N packet count exceeded (%d > %d)", eap_type_names, this->type, @@ -441,7 +452,7 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size, }, .type = type, .is_server = tls->is_server(tls), - .first_fragment = TRUE, + .first_fragment = (type != EAP_TNC), .frag_size = frag_size, .max_msg_count = max_msg_count, .include_length = include_length, |