diff options
author | René Mayrhofer <rene@mayrhofer.eu.org> | 2011-05-19 13:37:29 +0200 |
---|---|---|
committer | René Mayrhofer <rene@mayrhofer.eu.org> | 2011-05-19 13:37:29 +0200 |
commit | 0a9d51a49042a68daa15b0c74a2b7f152f52606b (patch) | |
tree | 451888dcb17d00e52114f734e846821373fbbd44 /src/libtls/tls_eap.c | |
parent | 568905f488e63e28778f87ac0e38d845f45bae79 (diff) | |
download | vyos-strongswan-0a9d51a49042a68daa15b0c74a2b7f152f52606b.tar.gz vyos-strongswan-0a9d51a49042a68daa15b0c74a2b7f152f52606b.zip |
Imported Upstream version 4.5.2
Diffstat (limited to 'src/libtls/tls_eap.c')
-rw-r--r-- | src/libtls/tls_eap.c | 148 |
1 files changed, 113 insertions, 35 deletions
diff --git a/src/libtls/tls_eap.c b/src/libtls/tls_eap.c index 8204a3441..685904fdf 100644 --- a/src/libtls/tls_eap.c +++ b/src/libtls/tls_eap.c @@ -1,3 +1,4 @@ + /* * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -41,6 +42,11 @@ struct private_tls_eap_t { eap_type_t type; /** + * Current value of EAP identifier + */ + u_int8_t identifier; + + /** * TLS stack */ tls_t *tls; @@ -51,6 +57,13 @@ struct private_tls_eap_t { bool is_server; /** + * If FALSE include the total length of an EAP message + * in the first fragment of fragmented messages only. + * If TRUE also include the length in non-fragmented messages. + */ + bool include_length; + + /** * First fragment of a multi-fragment record? */ bool first_fragment; @@ -75,14 +88,15 @@ struct private_tls_eap_t { * Flags of an EAP-TLS/TTLS/TNC message */ typedef enum { - EAP_TLS_LENGTH = (1<<7), /* shared with EAP-TTLS/TNC */ - EAP_TLS_MORE_FRAGS = (1<<6), /* shared with EAP-TTLS/TNC */ - EAP_TLS_START = (1<<5), /* shared with EAP-TTLS/TNC */ - EAP_TTLS_VERSION = (0x07), /* shared with EAP-TNC */ + EAP_TLS_LENGTH = (1<<7), /* shared with EAP-TTLS/TNC/PEAP */ + EAP_TLS_MORE_FRAGS = (1<<6), /* shared with EAP-TTLS/TNC/PEAP */ + EAP_TLS_START = (1<<5), /* shared with EAP-TTLS/TNC/PEAP */ + EAP_TTLS_VERSION = (0x07), /* shared with EAP-TNC/PEAP */ } eap_tls_flags_t; #define EAP_TTLS_SUPPORTED_VERSION 0 #define EAP_TNC_SUPPORTED_VERSION 1 +#define EAP_PEAP_SUPPORTED_VERSION 0 /** * EAP-TLS/TTLS packet format @@ -113,18 +127,19 @@ METHOD(tls_eap_t, initiate, status_t, case EAP_TNC: pkt.flags |= EAP_TNC_SUPPORTED_VERSION; break; + case EAP_PEAP: + pkt.flags |= EAP_PEAP_SUPPORTED_VERSION; + break; default: break; } htoun16(&pkt.length, sizeof(eap_tls_packet_t)); - do - { /* start with non-zero random identifier */ - pkt.identifier = random(); - } - while (!pkt.identifier); + pkt.identifier = this->identifier; - DBG2(DBG_IKE, "sending %N start packet", eap_type_names, this->type); *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)); + DBG3(DBG_TLS, "%B", out); return NEED_MORE; } return FAILED; @@ -163,8 +178,7 @@ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt) /** * Build a packet to send */ -static status_t build_pkt(private_tls_eap_t *this, - u_int8_t identifier, chunk_t *out) +static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) { char buf[this->frag_size]; eap_tls_packet_t *pkt; @@ -172,9 +186,13 @@ static status_t build_pkt(private_tls_eap_t *this, status_t status; char *kind; + if (this->is_server) + { + this->identifier++; + } pkt = (eap_tls_packet_t*)buf; pkt->code = this->is_server ? EAP_REQUEST : EAP_RESPONSE; - pkt->identifier = this->is_server ? identifier + 1 : identifier; + pkt->identifier = this->identifier; pkt->type = this->type; pkt->flags = 0; @@ -186,13 +204,15 @@ static status_t build_pkt(private_tls_eap_t *this, case EAP_TNC: pkt->flags |= EAP_TNC_SUPPORTED_VERSION; break; + case EAP_PEAP: + pkt->flags |= EAP_PEAP_SUPPORTED_VERSION; + break; default: break; } if (this->first_fragment) { - pkt->flags |= EAP_TLS_LENGTH; 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); @@ -210,13 +230,21 @@ static status_t build_pkt(private_tls_eap_t *this, kind = "further fragment"; if (this->first_fragment) { + pkt->flags |= EAP_TLS_LENGTH; this->first_fragment = FALSE; kind = "first fragment"; } break; case ALREADY_DONE: - kind = "packet"; - if (!this->first_fragment) + if (this->first_fragment) + { + if (this->include_length) + { + pkt->flags |= EAP_TLS_LENGTH; + } + kind = "packet"; + } + else { this->first_fragment = TRUE; kind = "final fragment"; @@ -225,39 +253,58 @@ static status_t build_pkt(private_tls_eap_t *this, default: return status; } - DBG2(DBG_TLS, "sending %N %s (%u bytes)", - eap_type_names, this->type, kind, len); if (reclen) { - htoun32(pkt + 1, reclen); - len += sizeof(u_int32_t); - pkt->flags |= EAP_TLS_LENGTH; + if (pkt->flags & EAP_TLS_LENGTH) + { + htoun32(pkt + 1, reclen); + len += sizeof(u_int32_t); + pkt->flags |= EAP_TLS_LENGTH; + } + else + { + /* get rid of the reserved length field */ + memcpy(buf+sizeof(eap_packet_t), + buf+sizeof(eap_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); + DBG3(DBG_TLS, "%B", out); return NEED_MORE; } /** * Send an ack to request next fragment */ -static chunk_t create_ack(private_tls_eap_t *this, u_int8_t identifier) +static chunk_t create_ack(private_tls_eap_t *this) { eap_tls_packet_t pkt = { .code = this->is_server ? EAP_REQUEST : EAP_RESPONSE, - .identifier = this->is_server ? identifier + 1 : identifier, .type = this->type, }; + + if (this->is_server) + { + this->identifier++; + } + pkt.identifier = this->identifier; htoun16(&pkt.length, sizeof(pkt)); + switch (this->type) { case EAP_TTLS: pkt.flags |= EAP_TTLS_SUPPORTED_VERSION; - break; + break; case EAP_TNC: pkt.flags |= EAP_TNC_SUPPORTED_VERSION; break; + case EAP_PEAP: + pkt.flags |= EAP_PEAP_SUPPORTED_VERSION; + break; default: break; } @@ -274,23 +321,30 @@ METHOD(tls_eap_t, process, status_t, if (++this->processed > this->max_msg_count) { - DBG1(DBG_IKE, "%N packet count exceeded (%d > %d)", + DBG1(DBG_TLS, "%N packet count exceeded (%d > %d)", eap_type_names, this->type, this->processed, this->max_msg_count); return FAILED; } pkt = (eap_tls_packet_t*)in.ptr; - if (in.len < sizeof(eap_tls_packet_t) || - untoh16(&pkt->length) != in.len) + if (in.len < sizeof(eap_tls_packet_t) || untoh16(&pkt->length) != in.len) { - DBG1(DBG_IKE, "invalid %N packet length", - eap_type_names, this->type); + DBG1(DBG_TLS, "invalid %N packet length", eap_type_names, this->type); return FAILED; } + + /* update EAP identifier */ + if (!this->is_server) + { + this->identifier = pkt->identifier; + } + DBG3(DBG_TLS, "%N payload %B", eap_type_names, this->type, &in); + if (pkt->flags & EAP_TLS_START) { - if (this->type == EAP_TTLS || this->type == EAP_TNC) + if (this->type == EAP_TTLS || this->type == EAP_TNC || + this->type == EAP_PEAP) { DBG1(DBG_TLS, "%N version is v%u", eap_type_names, this->type, pkt->flags & EAP_TTLS_VERSION); @@ -302,7 +356,7 @@ METHOD(tls_eap_t, process, status_t, { DBG2(DBG_TLS, "received %N acknowledgement packet", eap_type_names, this->type); - status = build_pkt(this, pkt->identifier, out); + status = build_pkt(this, out); if (status == INVALID_STATE && this->tls->is_complete(this->tls)) { return SUCCESS; @@ -320,16 +374,16 @@ METHOD(tls_eap_t, process, status_t, return status; } } - status = build_pkt(this, pkt->identifier, out); + status = build_pkt(this, out); switch (status) { case INVALID_STATE: - *out = create_ack(this, pkt->identifier); + *out = create_ack(this); return NEED_MORE; case FAILED: if (!this->is_server) { - *out = create_ack(this, pkt->identifier); + *out = create_ack(this); return NEED_MORE; } return FAILED; @@ -344,6 +398,18 @@ METHOD(tls_eap_t, get_msk, chunk_t, return this->tls->get_eap_msk(this->tls); } +METHOD(tls_eap_t, get_identifier, u_int8_t, + private_tls_eap_t *this) +{ + return this->identifier; +} + +METHOD(tls_eap_t, set_identifier, void, + private_tls_eap_t *this, u_int8_t identifier) +{ + this->identifier = identifier; +} + METHOD(tls_eap_t, destroy, void, private_tls_eap_t *this) { @@ -355,7 +421,7 @@ METHOD(tls_eap_t, destroy, void, * See header */ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size, - int max_msg_count) + int max_msg_count, bool include_length) { private_tls_eap_t *this; @@ -369,6 +435,8 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size, .initiate = _initiate, .process = _process, .get_msk = _get_msk, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, .destroy = _destroy, }, .type = type, @@ -376,8 +444,18 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size, .first_fragment = TRUE, .frag_size = frag_size, .max_msg_count = max_msg_count, + .include_length = include_length, .tls = tls, ); + if (this->is_server) + { + do + { /* start with non-zero random identifier */ + this->identifier = random(); + } + while (!this->identifier); + } + return &this->public; } |