Accept follow-up fragments with a TLS message length

This commit is contained in:
Martin Willi
2010-08-03 15:39:24 +02:00
parent 40e384ea01
commit 4c0124a0a2
+50 -24
View File
@@ -74,7 +74,7 @@ struct private_eap_tls_t {
}; };
/** Size limit for a single TLS message */ /** Size limit for a single TLS message */
#define MAX_TLS_MESSAGE_LEN 16192 #define MAX_TLS_MESSAGE_LEN 16384
/** Size of a EAP-TLS fragment */ /** Size of a EAP-TLS fragment */
#define EAP_TLS_FRAGMENT_LEN 1014 #define EAP_TLS_FRAGMENT_LEN 1014
@@ -137,41 +137,70 @@ static bool write_buf(private_eap_tls_t *this, eap_tls_packet_t *pkt)
{ {
u_int32_t msg_len; u_int32_t msg_len;
u_int16_t pkt_len; u_int16_t pkt_len;
chunk_t data;
chunk_free(&this->input);
pkt_len = untoh16(&pkt->length); pkt_len = untoh16(&pkt->length);
if (pkt->flags & EAP_TLS_LENGTH) if (pkt->flags & EAP_TLS_LENGTH)
{ /* first fragment */ {
if (pkt_len < sizeof(eap_tls_packet_t) + 4) if (pkt_len < sizeof(eap_tls_packet_t) + sizeof(msg_len))
{ {
DBG1(DBG_IKE, "EAP-TLS packet too short"); DBG1(DBG_IKE, "EAP-TLS packet too short");
return FALSE; return FALSE;
} }
msg_len = untoh32(pkt + 1); msg_len = untoh32(pkt + 1);
this->inpos = pkt_len - sizeof(eap_tls_packet_t) - 4; if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) ||
if (msg_len < this->inpos || msg_len > MAX_TLS_MESSAGE_LEN) msg_len > MAX_TLS_MESSAGE_LEN)
{ {
DBG1(DBG_IKE, "invalid EAP-TLS packet length"); DBG1(DBG_IKE, "invalid EAP-TLS packet length");
return FALSE; return FALSE;
} }
this->input = chunk_alloc(msg_len); if (this->input.ptr)
memcpy(this->input.ptr, ((char*)(pkt + 1)) + 4, this->inpos); {
if (msg_len != this->input.len)
{
DBG1(DBG_IKE, "received unexpected TLS message length");
return FALSE;
}
}
else
{
this->input = chunk_alloc(msg_len);
this->inpos = 0;
}
data = chunk_create((char*)(pkt + 1) + sizeof(msg_len),
pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len));
} }
else else
{ /* non-first fragment */ {
if (pkt_len > this->input.len - this->inpos) data = chunk_create((char*)(pkt + 1),
{ pkt_len - sizeof(eap_tls_packet_t));
DBG1(DBG_IKE, "EAP-TLS fragment exceeds TLS message length");
return FALSE;
}
memcpy(this->input.ptr + this->inpos, (char*)(pkt + 1),
pkt_len - sizeof(eap_tls_packet_t));
this->inpos += pkt_len - sizeof(eap_tls_packet_t);
} }
if (data.len > this->input.len - this->inpos)
{
DBG1(DBG_IKE, "EAP-TLS fragment exceeds TLS message length");
return FALSE;
}
memcpy(this->input.ptr + this->inpos, data.ptr, data.len);
this->inpos += data.len;
return TRUE; return TRUE;
} }
/**
* Send an ack to request next fragment
*/
static eap_payload_t *create_ack(private_eap_tls_t *this, u_int8_t identifier)
{
eap_tls_packet_t pkt = {
.code = this->is_server ? EAP_REQUEST : EAP_RESPONSE,
.identifier = this->is_server ? identifier + 1 : identifier,
.type = EAP_TLS,
};
htoun16(&pkt.length, sizeof(pkt));
return eap_payload_create_data(chunk_from_thing(pkt));
}
/** /**
* Create a eap response from data in the TLS output buffer * Create a eap response from data in the TLS output buffer
*/ */
@@ -256,12 +285,13 @@ static status_t process_buf(private_eap_tls_t *this)
status = this->tls->build(this->tls, &type, &data); status = this->tls->build(this->tls, &type, &data);
switch (status) switch (status)
{ {
case NEED_MORE:
break;
case INVALID_STATE: case INVALID_STATE:
/* invalid state means we need more input from peer first */ /* invalid state means we need more input from peer first */
return NEED_MORE; return NEED_MORE;
case NEED_MORE:
case SUCCESS: case SUCCESS:
break; return SUCCESS;
case FAILED: case FAILED:
default: default:
return FAILED; return FAILED;
@@ -270,10 +300,6 @@ static status_t process_buf(private_eap_tls_t *this)
htoun16(&out.version, TLS_1_2); htoun16(&out.version, TLS_1_2);
htoun16(&out.length, data.len); htoun16(&out.length, data.len);
this->output = chunk_cat("mcm", this->output, header, data); this->output = chunk_cat("mcm", this->output, header, data);
if (status == SUCCESS)
{
return SUCCESS;
}
} }
} }
@@ -305,7 +331,7 @@ METHOD(eap_method_t, process, status_t,
} }
if (pkt->flags & EAP_TLS_MORE_FRAGS) if (pkt->flags & EAP_TLS_MORE_FRAGS)
{ /* more fragments follow */ { /* more fragments follow */
*out = read_buf(this, pkt->identifier); *out = create_ack(this, pkt->identifier);
return NEED_MORE; return NEED_MORE;
} }
else if (this->input.len != this->inpos) else if (this->input.len != this->inpos)