Updated to hostap_2_6
[mech_eap.git] / libeap / src / eap_peer / eap_fast.c
index 4cbe3ba..964ebe7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -67,6 +67,7 @@ struct eap_fast_data {
        int simck_idx;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
 };
 
 
@@ -112,8 +113,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
 }
 
 
-static int eap_fast_parse_phase1(struct eap_fast_data *data,
-                                const char *phase1)
+static void eap_fast_parse_phase1(struct eap_fast_data *data,
+                                 const char *phase1)
 {
        const char *pos;
 
@@ -139,8 +140,6 @@ static int eap_fast_parse_phase1(struct eap_fast_data *data,
                wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
                           "list");
        }
-
-       return 0;
 }
 
 
@@ -158,10 +157,8 @@ static void * eap_fast_init(struct eap_sm *sm)
        data->fast_version = EAP_FAST_VERSION;
        data->max_pac_list_len = 10;
 
-       if (config->phase1 && eap_fast_parse_phase1(data, config->phase1) < 0) {
-               eap_fast_deinit(sm, data);
-               return NULL;
-       }
+       if (config->phase1)
+               eap_fast_parse_phase1(data, config->phase1);
 
        if (eap_peer_select_phase2_methods(config, "auth=",
                                           &data->phase2_types,
@@ -254,14 +251,16 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
        os_memset(data->emsk, 0, EAP_EMSK_LEN);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
 
 static int eap_fast_derive_msk(struct eap_fast_data *data)
 {
-       eap_fast_derive_eap_msk(data->simck, data->key_data);
-       eap_fast_derive_eap_emsk(data->simck, data->emsk);
+       if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
+           eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
+               return -1;
        data->success = 1;
        return 0;
 }
@@ -276,7 +275,7 @@ static int eap_fast_derive_key_auth(struct eap_sm *sm,
         * Extra key material after TLS key_block: session_key_seed[40]
         */
 
-       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+       sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
                                  EAP_FAST_SKS_LEN);
        if (sks == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +303,6 @@ static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
        os_free(data->key_block_p);
        data->key_block_p = (struct eap_fast_key_block_provisioning *)
                eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
-                                   "key expansion",
                                    sizeof(*data->key_block_p));
        if (data->key_block_p == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -711,9 +709,10 @@ static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
        if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
                return -1;
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
-       sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-                  "Inner Methods Compound Keys",
-                  isk, sizeof(isk), imck, sizeof(imck));
+       if (sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+                      "Inner Methods Compound Keys",
+                      isk, sizeof(isk), imck, sizeof(imck)) < 0)
+               return -1;
        data->simck_idx++;
        os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
@@ -1096,7 +1095,7 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
        /* Parse TLVs from the decrypted Phase 2 data */
        pos = wpabuf_mhead(decrypted);
        end = pos + wpabuf_len(decrypted);
-       while (pos + 4 < end) {
+       while (end - pos > 4) {
                mandatory = pos[0] & 0x80;
                tlv_type = WPA_GET_BE16(pos) & 0x3fff;
                pos += 2;
@@ -1443,7 +1442,7 @@ static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
 static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
                                             struct eap_fast_data *data)
 {
-       u8 ciphers[5];
+       u8 ciphers[7];
        int count = 0;
 
        if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
@@ -1455,7 +1454,9 @@ static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
        if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated "
                           "provisioning TLS cipher suites");
+               ciphers[count++] = TLS_CIPHER_RSA_DHE_AES256_SHA;
                ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA;
+               ciphers[count++] = TLS_CIPHER_AES256_SHA;
                ciphers[count++] = TLS_CIPHER_AES128_SHA;
                ciphers[count++] = TLS_CIPHER_RC4_SHA;
        }
@@ -1567,6 +1568,34 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        res = 1;
                }
        } else {
+               if (sm->waiting_ext_cert_check && data->pending_resp) {
+                       struct eap_peer_config *config = eap_get_config(sm);
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_GOOD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check succeeded - continue handshake");
+                               resp = data->pending_resp;
+                               data->pending_resp = NULL;
+                               sm->waiting_ext_cert_check = 0;
+                               return resp;
+                       }
+
+                       if (config->pending_ext_cert_check ==
+                           EXT_CERT_CHECK_BAD) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: External certificate check failed - force authentication failure");
+                               ret->methodState = METHOD_DONE;
+                               ret->decision = DECISION_FAIL;
+                               sm->waiting_ext_cert_check = 0;
+                               return NULL;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                /* Continue processing TLS handshake (phase 1). */
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_FAST,
@@ -1580,6 +1609,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
                        return resp;
                }
 
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-FAST: Waiting external server certificate validation");
+                       wpabuf_free(data->pending_resp);
+                       data->pending_resp = resp;
+                       return NULL;
+               }
+
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                        char cipher[80];
                        wpa_printf(MSG_DEBUG,
@@ -1644,6 +1681,8 @@ static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
        data->key_block_p = NULL;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
 }
 
 
@@ -1721,7 +1760,7 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
        struct eap_fast_data *data = priv;
        u8 *id;
 
-       if (!data->success)
+       if (!data->success || !data->session_id)
                return NULL;
 
        id = os_malloc(data->id_len);
@@ -1757,7 +1796,6 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_fast_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1778,8 +1816,5 @@ int eap_peer_fast_register(void)
 #endif
        eap->get_emsk = eap_fast_get_emsk;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }