Accept follow-up fragments with a TLS message length
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user