Updated to hostap_2_6
[mech_eap.git] / libeap / src / eap_peer / eap_peap.c
index 98a48a6..45ba381 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * 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.
@@ -59,6 +59,7 @@ struct eap_peap_data {
        size_t id_len;
 
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
        enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
        int crypto_binding_used;
        u8 binding_nonce[32];
@@ -69,8 +70,8 @@ struct eap_peap_data {
 };
 
 
-static int eap_peap_parse_phase1(struct eap_peap_data *data,
-                                const char *phase1)
+static void eap_peap_parse_phase1(struct eap_peap_data *data,
+                                 const char *phase1)
 {
        const char *pos;
 
@@ -125,8 +126,6 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data,
                wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
        }
 #endif /* EAP_TNC */
-
-       return 0;
 }
 
 
@@ -144,11 +143,8 @@ static void * eap_peap_init(struct eap_sm *sm)
        data->peap_outer_success = 2;
        data->crypto_binding = OPTIONAL_BINDING;
 
-       if (config && config->phase1 &&
-           eap_peap_parse_phase1(data, config->phase1) < 0) {
-               eap_peap_deinit(sm, data);
-               return NULL;
-       }
+       if (config && config->phase1)
+               eap_peap_parse_phase1(data, config->phase1);
 
        if (eap_peer_select_phase2_methods(config, "auth=",
                                           &data->phase2_types,
@@ -191,6 +187,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        eap_peap_free_key(data);
        os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
 }
 
@@ -256,6 +253,7 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
 {
        u8 *tk;
        u8 isk[32], imck[60];
+       int resumed;
 
        /*
         * Tunnel key (TK) is the first 60 octets of the key generated by
@@ -266,8 +264,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
                return -1;
        wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
 
-       if (data->reauth &&
-           tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+       resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
+       wpa_printf(MSG_DEBUG,
+                  "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
+                  data->reauth, resumed, data->phase2_eap_started,
+                  data->phase2_success);
+       if (data->reauth && !data->phase2_eap_started && resumed) {
                /* Fast-connect: IPMK|CMK = TK */
                os_memcpy(data->ipmk, tk, 40);
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -337,7 +339,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
                    addr[0], len[0]);
        wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
                    addr[1], len[1]);
-       hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+       if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
+               return -1;
        wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
        data->crypto_binding_used = 1;
 
@@ -648,6 +651,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
                                        if (*resp == NULL) {
                                                ret->methodState = METHOD_DONE;
                                                ret->decision = DECISION_FAIL;
+                                               wpabuf_free(buf);
                                                return -1;
                                        }
                                        wpabuf_put_buf(*resp, buf);
@@ -1006,6 +1010,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
            !data->resuming) {
                res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
        } 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-PEAP: 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-PEAP: 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-PEAP: Continuing to wait external server certificate validation");
+                       return NULL;
+               }
+
                res = eap_peer_tls_process_helper(sm, &data->ssl,
                                                  EAP_TYPE_PEAP,
                                                  data->peap_version, id, &msg,
@@ -1018,6 +1050,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                        ret->decision = DECISION_FAIL;
                        return resp;
                }
+
+
+               if (sm->waiting_ext_cert_check) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-PEAP: 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 *label;
                        wpa_printf(MSG_DEBUG,
@@ -1123,6 +1165,8 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_peap_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
        data->crypto_binding_used = 0;
 }
 
@@ -1237,7 +1281,6 @@ static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
 int eap_peer_peap_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
@@ -1255,8 +1298,5 @@ int eap_peer_peap_register(void)
        eap->init_for_reauth = eap_peap_init_for_reauth;
        eap->getSessionId = eap_peap_get_session_id;
 
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
 }