Merged the hostap_2.6 updates, and the Leap of Faith work, from the hostap_update...
[mech_eap.git] / libeap / src / eap_server / eap_server_fast.c
index 39beb33..2049172 100644 (file)
@@ -2,14 +2,8 @@
  * EAP-FAST server (RFC 4851)
  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -18,6 +12,7 @@
 #include "crypto/aes_wrap.h"
 #include "crypto/sha1.h"
 #include "crypto/tls.h"
+#include "crypto/random.h"
 #include "eap_common/eap_tlv_common.h"
 #include "eap_common/eap_fast_common.h"
 #include "eap_i.h"
@@ -166,8 +161,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
                return 0;
        }
 
-       if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
-                      pac_opaque, buf) < 0) {
+       if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+                      (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
                           "PAC-Opaque");
                os_free(buf);
@@ -185,44 +180,49 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
                        buf, end - buf);
 
        pos = buf;
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
+       while (end - pos > 1) {
+               u8 id, elen;
+
+               id = *pos++;
+               elen = *pos++;
+               if (elen > end - pos)
                        break;
 
-               switch (*pos) {
+               switch (id) {
                case PAC_OPAQUE_TYPE_PAD:
-                       pos = end;
-                       break;
+                       goto done;
                case PAC_OPAQUE_TYPE_KEY:
-                       if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
-                               wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
-                                          "PAC-Key length %d", pos[1]);
+                       if (elen != EAP_FAST_PAC_KEY_LEN) {
+                               wpa_printf(MSG_DEBUG,
+                                          "EAP-FAST: Invalid PAC-Key length %d",
+                                          elen);
                                os_free(buf);
                                return -1;
                        }
-                       pac_key = pos + 2;
+                       pac_key = pos;
                        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
                                        "decrypted PAC-Opaque",
                                        pac_key, EAP_FAST_PAC_KEY_LEN);
                        break;
                case PAC_OPAQUE_TYPE_LIFETIME:
-                       if (pos[1] != 4) {
+                       if (elen != 4) {
                                wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
                                           "PAC-Key lifetime length %d",
-                                          pos[1]);
+                                          elen);
                                os_free(buf);
                                return -1;
                        }
-                       lifetime = WPA_GET_BE32(pos + 2);
+                       lifetime = WPA_GET_BE32(pos);
                        break;
                case PAC_OPAQUE_TYPE_IDENTITY:
-                       identity = pos + 2;
-                       identity_len = pos[1];
+                       identity = pos;
+                       identity_len = elen;
                        break;
                }
 
-               pos += 2 + pos[1];
+               pos += elen;
        }
+done:
 
        if (pac_key == NULL) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
@@ -278,7 +278,7 @@ static void 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 "
@@ -305,7 +305,6 @@ static void 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");
@@ -412,11 +411,13 @@ static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
 static void * eap_fast_init(struct eap_sm *sm)
 {
        struct eap_fast_data *data;
-       u8 ciphers[5] = {
+       u8 ciphers[7] = {
                TLS_CIPHER_ANON_DH_AES128_SHA,
                TLS_CIPHER_AES128_SHA,
                TLS_CIPHER_RSA_DHE_AES128_SHA,
                TLS_CIPHER_RC4_SHA,
+               TLS_CIPHER_RSA_DHE_AES256_SHA,
+               TLS_CIPHER_AES256_SHA,
                TLS_CIPHER_NONE
        };
 
@@ -433,7 +434,7 @@ static void * eap_fast_init(struct eap_sm *sm)
        }
        data->state = START;
 
-       if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+       if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_FAST)) {
                wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
                eap_fast_reset(sm, data);
                return NULL;
@@ -516,7 +517,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv)
        os_free(data->key_block_p);
        wpabuf_free(data->pending_phase2_resp);
        os_free(data->identity);
-       os_free(data);
+       bin_clear_free(data, sizeof(*data));
 }
 
 
@@ -642,7 +643,7 @@ static struct wpabuf * eap_fast_build_crypto_binding(
        binding->version = EAP_FAST_VERSION;
        binding->received_version = data->peer_version;
        binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
-       if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) {
+       if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) {
                wpabuf_free(buf);
                return NULL;
        }
@@ -692,7 +693,7 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
        struct eap_tlv_result_tlv *result;
        struct os_time now;
 
-       if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+       if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
            os_get_time(&now) < 0)
                return NULL;
        wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
@@ -735,8 +736,8 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
                os_free(pac_buf);
                return NULL;
        }
-       if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
-                    pac_opaque) < 0) {
+       if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+                    pac_len / 8, pac_buf, pac_opaque) < 0) {
                os_free(pac_buf);
                os_free(pac_opaque);
                return NULL;
@@ -824,6 +825,9 @@ static int eap_fast_encrypt_phase2(struct eap_sm *sm,
        encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
        wpabuf_free(plain);
 
+       if (!encr)
+               return -1;
+
        if (data->ssl.tls_out && piggyback) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
                           "(len=%d) with last Phase 1 Message (len=%d "
@@ -1021,7 +1025,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm,
        if (m->check(sm, priv, &buf)) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
                           "ignore the packet");
-               next_type = eap_fast_req_failure(sm, data);
+               eap_fast_req_failure(sm, data);
                return;
        }
 
@@ -1128,26 +1132,28 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm,
 static int eap_fast_parse_tlvs(struct wpabuf *data,
                               struct eap_fast_tlv_parse *tlv)
 {
-       int mandatory, tlv_type, len, res;
+       int mandatory, tlv_type, res;
+       size_t len;
        u8 *pos, *end;
 
        os_memset(tlv, 0, sizeof(*tlv));
 
        pos = wpabuf_mhead(data);
        end = pos + wpabuf_len(data);
-       while (pos + 4 < end) {
+       while (end - pos > 4) {
                mandatory = pos[0] & 0x80;
                tlv_type = WPA_GET_BE16(pos) & 0x3fff;
                pos += 2;
                len = WPA_GET_BE16(pos);
                pos += 2;
-               if (pos + len > end) {
+               if (len > (size_t) (end - pos)) {
                        wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
                        return -1;
                }
                wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
-                          "TLV type %d length %d%s",
-                          tlv_type, len, mandatory ? " (mandatory)" : "");
+                          "TLV type %d length %u%s",
+                          tlv_type, (unsigned int) len,
+                          mandatory ? " (mandatory)" : "");
 
                res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
                if (res == -2)
@@ -1201,7 +1207,7 @@ static int eap_fast_validate_crypto_binding(
                return -1;
        }
 
-       if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+       if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
            (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
                wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
                           "Crypto-Binding");
@@ -1215,7 +1221,7 @@ static int eap_fast_validate_crypto_binding(
                    (u8 *) b, bind_len);
        hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
                  b->compound_mac);
-       if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+       if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) {
                wpa_hexdump(MSG_MSGDUMP,
                            "EAP-FAST: Calculated Compound MAC",
                            b->compound_mac, sizeof(cmac));
@@ -1559,7 +1565,10 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
        if (eapKeyData == NULL)
                return NULL;
 
-       eap_fast_derive_eap_msk(data->simck, eapKeyData);
+       if (eap_fast_derive_eap_msk(data->simck, eapKeyData) < 0) {
+               os_free(eapKeyData);
+               return NULL;
+       }
        *len = EAP_FAST_KEY_LEN;
 
        return eapKeyData;
@@ -1578,7 +1587,10 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
        if (eapKeyData == NULL)
                return NULL;
 
-       eap_fast_derive_eap_emsk(data->simck, eapKeyData);
+       if (eap_fast_derive_eap_emsk(data->simck, eapKeyData) < 0) {
+               os_free(eapKeyData);
+               return NULL;
+       }
        *len = EAP_EMSK_LEN;
 
        return eapKeyData;
@@ -1592,10 +1604,21 @@ static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
 }
 
 
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_fast_data *data = priv;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST,
+                                               len);
+}
+
+
 int eap_server_fast_register(void)
 {
        struct eap_method *eap;
-       int ret;
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
                                      EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
@@ -1611,9 +1634,7 @@ int eap_server_fast_register(void)
        eap->getKey = eap_fast_getKey;
        eap->get_emsk = eap_fast_get_emsk;
        eap->isSuccess = eap_fast_isSuccess;
+       eap->getSessionId = eap_fast_get_session_id;
 
-       ret = eap_server_method_register(eap);
-       if (ret)
-               eap_server_method_free(eap);
-       return ret;
+       return eap_server_method_register(eap);
 }