automake build system
[mech_eap.orig] / src / eap_peer / eap_fast.c
index bf94e0f..5d3e69d 100644 (file)
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/tls.h"
+#include "crypto/sha1.h"
+#include "eap_common/eap_tlv_common.h"
 #include "eap_i.h"
 #include "eap_tls_common.h"
 #include "eap_config.h"
-#include "tls.h"
-#include "eap_tlv.h"
-#include "sha1.h"
 #include "eap_fast_pac.h"
 
 #ifdef EAP_FAST_DYNAMIC
@@ -343,10 +343,8 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm,
                sm->peer_challenge = data->key_block_p->client_challenge;
        }
        sm->init_phase2 = 1;
-       sm->mschapv2_full_key = 1;
        data->phase2_priv = data->phase2_method->init(sm);
        sm->init_phase2 = 0;
-       sm->mschapv2_full_key = 0;
        sm->auth_challenge = NULL;
        sm->peer_challenge = NULL;
 
@@ -358,6 +356,9 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
 {
        size_t i;
 
+       /* TODO: TNC with anonymous provisioning; need to require both
+        * completed MSCHAPv2 and TNC */
+
        if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
                wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
                           "during unauthenticated provisioning; reject phase2"
@@ -365,6 +366,18 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
                return -1;
        }
 
+#ifdef EAP_TNC
+       if (type == EAP_TYPE_TNC) {
+               data->phase2_type.vendor = EAP_VENDOR_IETF;
+               data->phase2_type.method = EAP_TYPE_TNC;
+               wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
+                          "vendor %d method %d for TNC",
+                          data->phase2_type.vendor,
+                          data->phase2_type.method);
+               return 0;
+       }
+#endif /* EAP_TNC */
+
        for (i = 0; i < data->num_phase2_types; i++) {
                if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
                    data->phase2_types[i].method != type)
@@ -410,6 +423,17 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
                return 0;
        }
 
+       if (data->phase2_priv && data->phase2_method &&
+           *pos != data->phase2_type.method) {
+               wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
+                          "deinitialize previous method");
+               data->phase2_method->deinit(sm, data->phase2_priv);
+               data->phase2_method = NULL;
+               data->phase2_priv = NULL;
+               data->phase2_type.vendor = EAP_VENDOR_IETF;
+               data->phase2_type.method = EAP_TYPE_NONE;
+       }
+
        if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
            data->phase2_type.method == EAP_TYPE_NONE &&
            eap_fast_select_phase2_method(data, *pos) < 0) {
@@ -480,6 +504,8 @@ static struct wpabuf * eap_fast_tlv_result(int status, int intermediate)
        buf = wpabuf_alloc(sizeof(*result));
        if (buf == NULL)
                return NULL;
+       wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)",
+                  intermediate ? "Intermediate " : "", status);
        result = wpabuf_put(buf, sizeof(*result));
        result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
                                        (intermediate ?
@@ -501,12 +527,7 @@ static struct wpabuf * eap_fast_tlv_pac_ack(void)
        if (buf == NULL)
                return NULL;
 
-       res = wpabuf_put(buf, sizeof(*res));
-       res->tlv_type = host_to_be16(EAP_TLV_RESULT_TLV |
-                                    EAP_TLV_TYPE_MANDATORY);
-       res->length = host_to_be16(sizeof(*res) - sizeof(struct eap_tlv_hdr));
-       res->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
-
+       wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)");
        ack = wpabuf_put(buf, sizeof(*ack));
        ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
                                     EAP_TLV_TYPE_MANDATORY);
@@ -638,7 +659,18 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm,
 
        if (key_len > isk_len)
                key_len = isk_len;
-       os_memcpy(isk, key, key_len);
+       if (key_len == 32 &&
+           data->phase2_method->vendor == EAP_VENDOR_IETF &&
+           data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+               /*
+                * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+                * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+                * ISK for EAP-FAST cryptobinding.
+                */
+               os_memcpy(isk, key + 16, 16);
+               os_memcpy(isk + 16, key, 16);
+       } else
+               os_memcpy(isk, key, key_len);
        os_free(key);
 
        return 0;
@@ -886,10 +918,7 @@ static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
                entry->a_id_info_len = len;
                break;
        case PAC_TYPE_PAC_TYPE:
-               /*
-                * draft-cam-winget-eap-fast-provisioning-04.txt,
-                * Section 4.2.6 - PAC-Type TLV
-                */
+               /* RFC 5422, Section 4.2.6 - PAC-Type TLV */
                if (len != 2) {
                        wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
                                   "length %lu (expected 2)",
@@ -929,7 +958,7 @@ static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
        size_t left, len;
        int type;
 
-       /* draft-cam-winget-eap-fast-provisioning-04.txt, Section 4.2.4 */
+       /* RFC 5422, Section 4.2.4 */
 
        /* PAC-Type defaults to Tunnel PAC (Type 1) */
        entry->pac_type = PAC_TYPE_TUNNEL_PAC;
@@ -1171,7 +1200,9 @@ static int eap_fast_process_decrypted(struct eap_sm *sm,
        }
 
        if (data->current_pac == NULL && data->provisioning &&
-           !data->anon_provisioning) {
+           !data->anon_provisioning && !tlv.pac &&
+           (tlv.iresult == EAP_TLV_RESULT_SUCCESS ||
+            tlv.result == EAP_TLV_RESULT_SUCCESS)) {
                /*
                 * Need to request Tunnel PAC when using authenticated
                 * provisioning.
@@ -1183,10 +1214,10 @@ static int eap_fast_process_decrypted(struct eap_sm *sm,
 
        if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
                tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
-               resp = wpabuf_concat(resp, tmp);
+               resp = wpabuf_concat(tmp, resp);
        } else if (failed) {
                tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
-               resp = wpabuf_concat(resp, tmp);
+               resp = wpabuf_concat(tmp, resp);
        }
 
        if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
@@ -1414,9 +1445,9 @@ static int eap_fast_process_start(struct eap_sm *sm,
 
        /* EAP-FAST Version negotiation (section 3.1) */
        wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)",
-                  flags & EAP_PEAP_VERSION_MASK, data->fast_version);
-       if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version)
-               data->fast_version = flags & EAP_PEAP_VERSION_MASK;
+                  flags & EAP_TLS_VERSION_MASK, data->fast_version);
+       if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version)
+               data->fast_version = flags & EAP_TLS_VERSION_MASK;
        wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
                   data->fast_version);