From: Kevin Date: Fri, 3 Feb 2012 13:15:10 +0000 (-0500) Subject: Eap channel binding support code X-Git-Url: http://www.project-moonshot.org/gitweb/?p=freeradius.git;a=commitdiff_plain;h=212c79e4b0f292f82d7b674f26ce0d705014251d Eap channel binding support code --- diff --git a/src/include/radius.h b/src/include/radius.h index 9160ada..2107056 100644 --- a/src/include/radius.h +++ b/src/include/radius.h @@ -318,6 +318,7 @@ #define VENDORPEC_FREERADIUS 11344 #define VENDORPEC_WIMAX 24757 #define VENDORPEC_EXTENDED (1 << 25) +#define VENDORPEC_UKERNA 25622 /* * Vendor specific attributes @@ -361,3 +362,9 @@ #define PW_VQP_MAC 0x2c06 #define PW_VQP_UNKNOWN 0x2c07 #define PW_VQP_COOKIE 0x2c08 + +/* + * JANET's code for transporting eap channel binding data over ttls + */ + +#define PW_UKERNA_CHBIND 134 diff --git a/src/modules/rlm_eap/libeap/eap_types.h b/src/modules/rlm_eap/libeap/eap_types.h index aac473a..c494d50 100644 --- a/src/modules/rlm_eap/libeap/eap_types.h +++ b/src/modules/rlm_eap/libeap/eap_types.h @@ -110,6 +110,14 @@ typedef struct eap_packet_t { uint8_t data[1]; } eap_packet_t; +/* + * Structure to represent eap channel binding packet format *on wire* + */ +typedef struct eap_chbind_packet_t { + uint8_t code; + uint8_t data[1]; +} eap_chbind_packet_t; + /* * interfaces in eapcommon.c @@ -120,5 +128,7 @@ extern int eap_wireformat(EAP_PACKET *reply); extern int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply); extern VALUE_PAIR *eap_packet2vp(const eap_packet_t *reply); extern eap_packet_t *eap_vp2packet(VALUE_PAIR *vps); +extern VALUE_PAIR *eap_chbind_packet2vp(const eap_chbind_packet_t *packet, size_t len); +extern size_t eap_chbind_vp2packet(VALUE_PAIR *vps, eap_chbind_packet_t **packet); #endif /* _EAP_TYPES_H */ diff --git a/src/modules/rlm_eap/libeap/eapcommon.c b/src/modules/rlm_eap/libeap/eapcommon.c index 889341b..4a7990b 100644 --- a/src/modules/rlm_eap/libeap/eapcommon.c +++ b/src/modules/rlm_eap/libeap/eapcommon.c @@ -431,3 +431,102 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps) return eap_packet; } + +VALUE_PAIR *eap_chbind_packet2vp(const eap_chbind_packet_t *packet, size_t len) +{ + size_t size; + const uint8_t *ptr; + VALUE_PAIR *head = NULL; + VALUE_PAIR **tail = &head; + VALUE_PAIR *vp; + + ptr = (const uint8_t *) packet; + + do { + size = len; + if (size > 247) size = 247; + + vp = paircreate(PW_VENDOR_SPECIFIC, VENDORPEC_UKERNA, + PW_TYPE_OCTETS); + if (!vp) { + pairfree(&head); + return NULL; + } + vp->vp_octets[0] = PW_UKERNA_CHBIND; + vp->vp_octets[1] = size; + memcpy(&vp->vp_octets[2], ptr, size); + vp->length = size + 2; + + *tail = vp; + tail = &(vp->next); + + ptr += size; + len -= size; + } while (len > 0); + + return head; +} + + +/* + * Find the next EAP-CHANNEL-BINDING message in the + * pair list + */ +static VALUE_PAIR *eap_chbind_find_pair(VALUE_PAIR *vps) +{ + VALUE_PAIR *result = pairfind(vps, PW_VENDOR_SPECIFIC, + VENDORPEC_UKERNA); + while (result && (result->vp_octets[0] != PW_UKERNA_CHBIND)) + result = result->next; + return result; +} + +/* + * Handles multiple EAP-channel-binding Message attrs + * ie concatenates all to get the complete EAP-channel-binding packet. + */ +size_t eap_chbind_vp2packet(VALUE_PAIR *vps, eap_chbind_packet_t **result) +{ + VALUE_PAIR *first, *vp; + eap_chbind_packet_t *eap_chbind_packet; + unsigned char *ptr; + size_t len; + + first = eap_chbind_find_pair(vps); + + /* + * Sanity check the length, BEFORE malloc'ing memory. + */ + len = 0; + for (vp = first; vp; vp = eap_chbind_find_pair(vp)) { + if ((vp->length < 2) || + (vp->length != vp->vp_octets[1]+2)) { + DEBUG("rlm_eap: Malformed EAP channel binding value pair. Length in pair header does not match actual length"); + return 0; + } + len += vp->vp_octets[1]; + } + + /* + * Now that we know the lengths are OK, allocate memory. + */ + eap_chbind_packet = (eap_chbind_packet_t *) malloc(len); + if (eap_chbind_packet == NULL) { + radlog(L_ERR, "rlm_eap: out of memory"); + return 0; + } + + /* + * Copy the data from EAP-Message's over to our EAP packet. + */ + ptr = (unsigned char *)eap_chbind_packet; + + /* RADIUS ensures order of attrs, so just concatenate all */ + for (vp = first; vp; vp = eap_chbind_find_pair(vp->next)) { + memcpy(ptr, vp->vp_octets+2, vp->length-2); + ptr += vp->length-2; + } + + *result = eap_chbind_packet; + return len; +} diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c index 056e415..4fd9a16 100644 --- a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c @@ -954,6 +954,8 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) const uint8_t *data; size_t data_len; REQUEST *request = handler->request; + eap_chbind_packet_t *chbind_packet; + size_t chbind_len; rad_assert(request != NULL); @@ -1195,6 +1197,36 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) } /* + * Process channel binding here. + */ + chbind_len = eap_chbind_vp2packet(fake->packet->vps, &chbind_packet); + if (chbind_len > 0) { + /*CHBIND_REQ *req = chbind_allocate(); + req->chbind_req = chbind_packet; + req->chbind_req_len = chbind_len; + if (fake->username) { + req->username = fake->username->vp_octets; + req->username_len = fake->username->length; + } else { + req->username = NULL; + req->username_len = 0; + } + chbind_process(request, req); + */ + + /* free the chbind packet; we're done with it */ + free(chbind_packet); + + /* encapsulate response here */ + /*pairadd(replyvps, eap_chbind_packet2vp(req->chbind_resp, + req->chbind_resp_len)); + */ + + /* clean up chbind req */ + /*chbind_free(req);*/ + } + + /* * Call authentication recursively, which will * do PAP, CHAP, MS-CHAP, etc. */