Eap channel binding support code
[freeradius.git] / src / modules / rlm_eap / libeap / eapcommon.c
index 5d072ab..0ad65cc 100644 (file)
@@ -60,8 +60,6 @@
 #include <freeradius-devel/ident.h>
 RCSID("$Id$")
 
-#include <freeradius-devel/autoconf.h>
-#include <freeradius-devel/missing.h>
 #include <freeradius-devel/libradius.h>
 #include "eap_types.h"
 
@@ -115,7 +113,10 @@ static const char *eap_types[] = {
   "pax",
   "psk",
   "sake",
-  "ikev2"
+  "ikev2",
+  "50",
+  "51",
+  "pwd"
 };                             /* MUST have PW_EAP_MAX_TYPES */
 
 /*
@@ -146,7 +147,7 @@ const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen)
                 *      Prefer the dictionary name over a number,
                 *      if it exists.
                 */
-               dval = dict_valbyattr(PW_EAP_TYPE, type);
+               dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
                if (dval) {
                        snprintf(buffer, buflen, "%s", dval->name);
                }
@@ -157,7 +158,7 @@ const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen)
                /*
                 *      Prefer the dictionary name, if it exists.
                 */
-               dval = dict_valbyattr(PW_EAP_TYPE, type);
+               dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
                if (dval) {
                        snprintf(buffer, buflen, "%s", dval->name);
                        return buffer;
@@ -258,7 +259,7 @@ int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply)
        }
        eap_packet = (eap_packet_t *)reply->packet;
 
-       pairdelete(&(packet->vps), PW_EAP_MESSAGE);
+       pairdelete(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY);
 
        vp = eap_packet2vp(eap_packet);
        if (!vp) return RLM_MODULE_INVALID;
@@ -271,9 +272,9 @@ int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply)
         *      Don't add a Message-Authenticator if it's already
         *      there.
         */
-       vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR);
+       vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
        if (!vp) {
-               vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
+               vp = paircreate(PW_MESSAGE_AUTHENTICATOR, 0);
                memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
                vp->length = AUTH_VECTOR_LEN;
                pairadd(&(packet->vps), vp);
@@ -322,7 +323,7 @@ VALUE_PAIR *eap_packet2vp(const eap_packet_t *packet)
                size = total;
                if (size > 253) size = 253;
 
-               vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
+               vp = paircreate(PW_EAP_MESSAGE, 0);
                if (!vp) {
                        pairfree(&head);
                        return NULL;
@@ -359,9 +360,9 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
        /*
         *      Get only EAP-Message attribute list
         */
-       first = pairfind(vps, PW_EAP_MESSAGE);
+       first = pairfind(vps, PW_EAP_MESSAGE, 0, TAG_ANY);
        if (first == NULL) {
-               radlog(L_ERR, "rlm_eap: EAP-Message not found");
+               DEBUG("rlm_eap: EAP-Message not found");
                return NULL;
        }
 
@@ -369,7 +370,7 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
         *      Sanity check the length before doing anything.
         */
        if (first->length < 4) {
-               radlog(L_ERR, "rlm_eap: EAP packet is too short.");
+               DEBUG("rlm_eap: EAP packet is too short.");
                return NULL;
        }
 
@@ -384,7 +385,7 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
         *      Take out even more weird things.
         */
        if (len < 4) {
-               radlog(L_ERR, "rlm_eap: EAP packet has invalid length.");
+               DEBUG("rlm_eap: EAP packet has invalid length.");
                return NULL;
        }
 
@@ -392,11 +393,11 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
         *      Sanity check the length, BEFORE malloc'ing memory.
         */
        total_len = 0;
-       for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) {
+       for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
                total_len += vp->length;
 
                if (total_len > len) {
-                       radlog(L_ERR, "rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
+                       DEBUG("rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
                        return NULL;
                }
        }
@@ -405,7 +406,7 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
         *      If the length is SMALLER, die, too.
         */
        if (total_len < len) {
-               radlog(L_ERR, "rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
+               DEBUG("rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
                return NULL;
        }
 
@@ -424,10 +425,109 @@ eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
        ptr = (unsigned char *)eap_packet;
 
        /* RADIUS ensures order of attrs, so just concatenate all */
-       for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) {
+       for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
                memcpy(ptr, vp->vp_strvalue, vp->length);
                ptr += vp->length;
        }
 
        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;
+}