Send EAP-Nak with supported types if requested type is unsupported
authorTobias Brunner <tobias@strongswan.org>
Tue, 21 Aug 2012 14:54:21 +0000 (16:54 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 31 Aug 2012 09:40:27 +0000 (11:40 +0200)
src/libcharon/encoding/payloads/eap_payload.c
src/libcharon/encoding/payloads/eap_payload.h
src/libcharon/plugins/eap_peap/eap_peap_peer.c
src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
src/libcharon/sa/ikev2/authenticators/eap_authenticator.c

index 1b9a5c8..4420f28 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2012 Tobias Brunner
  * Copyright (C) 2005-2010 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -20,6 +21,7 @@
 
 #include <daemon.h>
 #include <eap/eap.h>
+#include <bio/bio_writer.h>
 
 typedef struct private_eap_payload_t private_eap_payload_t;
 
@@ -313,15 +315,75 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier)
        return eap_payload_create_data(data);
 }
 
+/**
+ * Write the given type either expanded or not
+ */
+static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor,
+                                          bool expanded)
+{
+       if (expanded)
+       {
+               writer->write_uint8(writer, EAP_EXPANDED);
+               writer->write_uint24(writer, vendor);
+               writer->write_uint32(writer, type);
+       }
+       else
+       {
+               writer->write_uint8(writer, type);
+       }
+}
+
 /*
  * Described in header
  */
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier)
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded)
 {
-       chunk_t data;
+       enumerator_t *enumerator;
+       eap_type_t reg_type;
+       u_int32_t reg_vendor;
+       bio_writer_t *writer;
+       chunk_t length, data;
+       bool added_any = FALSE, found_vendor = FALSE;
+       eap_payload_t *payload;
+
+       writer = bio_writer_create(12);
+       writer->write_uint8(writer, EAP_RESPONSE);
+       writer->write_uint8(writer, identifier);
+       length = writer->skip(writer, 2);
+
+       write_type(writer, EAP_NAK, 0, expanded);
+
+       enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER);
+       while (enumerator->enumerate(enumerator, &reg_type, &reg_vendor))
+       {
+               if (!reg_vendor || expanded)
+               {
+                       write_type(writer, reg_type, reg_vendor, expanded);
+                       added_any = TRUE;
+               }
+               else if (reg_vendor)
+               {       /* found vendor specifc method, but this is not an expanded Nak */
+                       found_vendor = TRUE;
+               }
+       }
+       enumerator->destroy(enumerator);
 
-       data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK);
-       htoun16(data.ptr + 2, data.len);
-       return eap_payload_create_data(data);
+       if (found_vendor)
+       {       /* request an expanded authentication type */
+               write_type(writer, EAP_EXPANDED, 0, expanded);
+               added_any = TRUE;
+       }
+       if (!added_any)
+       {       /* no methods added */
+               write_type(writer, 0, 0, expanded);
+       }
+
+       /* set length */
+       data = writer->get_buf(writer);
+       htoun16(length.ptr, data.len);
+
+       payload = eap_payload_create_data(data);
+       writer->destroy(writer);
+       return payload;
 }
 
index 52bc7ac..ad8c57d 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2012 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -126,8 +127,10 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier);
  * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
  *
  * @param identifier   EAP identifier to use in payload
+ * @param expanded             TRUE to send an expanded Nak (as response to an expanded
+ *                                             request, i.e. one with vendor specific type)
  * @return                             eap_payload_t object
  */
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier);
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded);
 
 #endif /** EAP_PAYLOAD_H_ @}*/
index 72e201f..96d4d0f 100644 (file)
@@ -85,7 +85,7 @@ METHOD(tls_application_t, process, status_t,
                default:
                        return FAILED;
        }
-               
+
        in = eap_payload_create_data(data);
        DBG3(DBG_IKE, "%B", &data);
        chunk_free(&data);
@@ -151,7 +151,8 @@ METHOD(tls_application_t, process, status_t,
                if (!this->ph2_method)
                {
                        DBG1(DBG_IKE, "EAP method not supported");
-                       this->out = eap_payload_create_nak(in->get_identifier(in));
+                       this->out = eap_payload_create_nak(in->get_identifier(in),
+                                                                                          received_vendor != 0);
                        in->destroy(in);
                        return NEED_MORE;
                }
index 767111b..59366b4 100644 (file)
@@ -138,7 +138,7 @@ METHOD(tls_application_t, process, status_t,
                chunk_free(&avp_data);
        }
        while (eap_pos < eap_data.len);
-               
+
        in = eap_payload_create_data(eap_data);
        chunk_free(&eap_data);
        payload = (payload_t*)in;
@@ -192,7 +192,8 @@ METHOD(tls_application_t, process, status_t,
                if (!this->method)
                {
                        DBG1(DBG_IKE, "EAP method not supported");
-                       this->out = eap_payload_create_nak(in->get_identifier(in));
+                       this->out = eap_payload_create_nak(in->get_identifier(in),
+                                                                                          received_vendor != 0);
                        in->destroy(in);
                        return NEED_MORE;
                }
index 2c282dc..46913a7 100644 (file)
@@ -357,9 +357,11 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
                        this->method->destroy(this->method);
                        this->method = NULL;
                }
+               /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
+                * EAP method (types 3-253, 255) */
                DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
                         eap_type_names, type);
-               return eap_payload_create_nak(in->get_identifier(in));
+               return eap_payload_create_nak(in->get_identifier(in), FALSE);
        }
        if (this->method == NULL)
        {
@@ -377,7 +379,7 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
                if (!this->method)
                {
                        DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
-                       return eap_payload_create_nak(in->get_identifier(in));
+                       return eap_payload_create_nak(in->get_identifier(in), vendor != 0);
                }
        }