};
/** 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 */
#define EAP_TLS_FRAGMENT_LEN 1014
{
u_int32_t msg_len;
u_int16_t pkt_len;
+ chunk_t data;
- chunk_free(&this->input);
pkt_len = untoh16(&pkt->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");
return FALSE;
}
msg_len = untoh32(pkt + 1);
- this->inpos = pkt_len - sizeof(eap_tls_packet_t) - 4;
- if (msg_len < this->inpos || msg_len > MAX_TLS_MESSAGE_LEN)
+ if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) ||
+ msg_len > MAX_TLS_MESSAGE_LEN)
{
DBG1(DBG_IKE, "invalid EAP-TLS packet length");
return FALSE;
}
- this->input = chunk_alloc(msg_len);
- memcpy(this->input.ptr, ((char*)(pkt + 1)) + 4, this->inpos);
- }
- else
- { /* non-first fragment */
- if (pkt_len > this->input.len - this->inpos)
+ if (this->input.ptr)
{
- DBG1(DBG_IKE, "EAP-TLS fragment exceeds TLS message length");
- return FALSE;
+ if (msg_len != this->input.len)
+ {
+ DBG1(DBG_IKE, "received unexpected 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);
+ 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
+ {
+ data = chunk_create((char*)(pkt + 1),
+ 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;
}
/**
+ * 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
*/
static eap_payload_t *read_buf(private_eap_tls_t *this, u_int8_t identifier)
status = this->tls->build(this->tls, &type, &data);
switch (status)
{
+ case NEED_MORE:
+ break;
case INVALID_STATE:
/* invalid state means we need more input from peer first */
return NEED_MORE;
- case NEED_MORE:
case SUCCESS:
- break;
+ return SUCCESS;
case FAILED:
default:
return FAILED;
htoun16(&out.version, TLS_1_2);
htoun16(&out.length, data.len);
this->output = chunk_cat("mcm", this->output, header, data);
- if (status == SUCCESS)
- {
- return SUCCESS;
- }
}
}
}
if (pkt->flags & EAP_TLS_MORE_FRAGS)
{ /* more fragments follow */
- *out = read_buf(this, pkt->identifier);
+ *out = create_ack(this, pkt->identifier);
return NEED_MORE;
}
else if (this->input.len != this->inpos)