summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/eap_fast.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/eap_fast.c')
-rw-r--r--contrib/wpa_supplicant/eap_fast.c736
1 files changed, 427 insertions, 309 deletions
diff --git a/contrib/wpa_supplicant/eap_fast.c b/contrib/wpa_supplicant/eap_fast.c
index ff8f76c..d9347a9 100644
--- a/contrib/wpa_supplicant/eap_fast.c
+++ b/contrib/wpa_supplicant/eap_fast.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-FAST (draft-cam-winget-eap-fast-00.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-FAST (draft-cam-winget-eap-fast-03.txt)
+ * Copyright (c) 2004-2006, 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
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
#include "eap_tlv.h"
@@ -35,6 +32,8 @@
#define EAP_FAST_VERSION 1
#define EAP_FAST_KEY_LEN 64
#define EAP_FAST_PAC_KEY_LEN 32
+#define EAP_FAST_SIMCK_LEN 40
+#define EAP_FAST_SKS_LEN 40
#define TLS_EXT_PAC_OPAQUE 35
@@ -61,19 +60,11 @@ struct pac_tlv_hdr {
};
-/* draft-cam-winget-eap-fast-02.txt:
- * 6.2 EAP-FAST Authentication Phase 1: Key Derivations */
-struct eap_fast_key_block_auth {
- /* Extra key material after TLS key_block */
- u8 session_key_seed[40];
-};
-
-
/* draft-cam-winget-eap-fast-provisioning-01.txt:
* 3.4 Key Derivations Used in the EAP-FAST Provisioning Exchange */
struct eap_fast_key_block_provisioning {
/* Extra key material after TLS key_block */
- u8 session_key_seed[40];
+ u8 session_key_seed[EAP_FAST_SKS_LEN];
u8 server_challenge[16];
u8 client_challenge[16];
};
@@ -105,33 +96,36 @@ struct eap_fast_data {
void *phase2_priv;
int phase2_success;
- u8 phase2_type;
- u8 *phase2_types;
+ struct eap_method_type phase2_type;
+ struct eap_method_type *phase2_types;
size_t num_phase2_types;
int resuming; /* starting a resumed session */
- struct eap_fast_key_block_auth *key_block_a;
struct eap_fast_key_block_provisioning *key_block_p;
int provisioning_allowed; /* is PAC provisioning allowed */
int provisioning; /* doing PAC provisioning (not the normal auth) */
u8 key_data[EAP_FAST_KEY_LEN];
+ u8 emsk[EAP_EMSK_LEN];
int success;
struct eap_fast_pac *pac;
struct eap_fast_pac *current_pac;
int tls_master_secret_set;
+
+ u8 simck[EAP_FAST_SIMCK_LEN];
+ int simck_idx;
};
static void eap_fast_free_pac(struct eap_fast_pac *pac)
{
- free(pac->pac_opaque);
- free(pac->pac_info);
- free(pac->a_id);
- free(pac->i_id);
- free(pac->a_id_info);
- free(pac);
+ os_free(pac->pac_opaque);
+ os_free(pac->pac_info);
+ os_free(pac->a_id);
+ os_free(pac->i_id);
+ os_free(pac->a_id_info);
+ os_free(pac);
}
@@ -142,7 +136,7 @@ static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data,
while (pac) {
if (pac->a_id_len == a_id_len &&
- memcmp(pac->a_id, a_id, a_id_len) == 0) {
+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
return pac;
}
pac = pac->next;
@@ -164,7 +158,7 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
prev = NULL;
while (pac) {
if (pac->a_id_len == entry->a_id_len &&
- memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
+ os_memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
if (prev == NULL) {
data->pac = pac->next;
} else {
@@ -180,60 +174,59 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
}
/* Allocate a new entry and add it to the list of PACs. */
- pac = malloc(sizeof(*pac));
+ pac = os_zalloc(sizeof(*pac));
if (pac == NULL)
return -1;
- memset(pac, 0, sizeof(*pac));
- memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
+ os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
if (entry->pac_opaque) {
- pac->pac_opaque = malloc(entry->pac_opaque_len);
+ pac->pac_opaque = os_malloc(entry->pac_opaque_len);
if (pac->pac_opaque == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->pac_opaque, entry->pac_opaque,
- entry->pac_opaque_len);
+ os_memcpy(pac->pac_opaque, entry->pac_opaque,
+ entry->pac_opaque_len);
pac->pac_opaque_len = entry->pac_opaque_len;
}
if (entry->pac_info) {
- pac->pac_info = malloc(entry->pac_info_len);
+ pac->pac_info = os_malloc(entry->pac_info_len);
if (pac->pac_info == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->pac_info, entry->pac_info,
- entry->pac_info_len);
+ os_memcpy(pac->pac_info, entry->pac_info,
+ entry->pac_info_len);
pac->pac_info_len = entry->pac_info_len;
}
if (entry->a_id) {
- pac->a_id = malloc(entry->a_id_len);
+ pac->a_id = os_malloc(entry->a_id_len);
if (pac->a_id == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->a_id, entry->a_id,
- entry->a_id_len);
+ os_memcpy(pac->a_id, entry->a_id,
+ entry->a_id_len);
pac->a_id_len = entry->a_id_len;
}
if (entry->i_id) {
- pac->i_id = malloc(entry->i_id_len);
+ pac->i_id = os_malloc(entry->i_id_len);
if (pac->i_id == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->i_id, entry->i_id,
- entry->i_id_len);
+ os_memcpy(pac->i_id, entry->i_id,
+ entry->i_id_len);
pac->i_id_len = entry->i_id_len;
}
if (entry->a_id_info) {
- pac->a_id_info = malloc(entry->a_id_info_len);
+ pac->a_id_info = os_malloc(entry->a_id_info_len);
if (pac->a_id_info == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->a_id_info, entry->a_id_info,
- entry->a_id_info_len);
+ os_memcpy(pac->a_id_info, entry->a_id_info,
+ entry->a_id_info_len);
pac->a_id_info_len = entry->a_id_info_len;
}
pac->next = data->pac;
@@ -267,7 +260,7 @@ static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
len = l_end - rc->pos;
if (len >= buf_len)
len = buf_len - 1;
- memcpy(buf, rc->pos, len);
+ os_memcpy(buf, rc->pos, len);
buf[len] = '\0';
rc->pos = l_end + 1;
}
@@ -293,15 +286,15 @@ static u8 * eap_fast_parse_hex(const char *value, size_t *len)
if (value == NULL)
return NULL;
- hlen = strlen(value);
+ hlen = os_strlen(value);
if (hlen & 1)
return NULL;
*len = hlen / 2;
- buf = malloc(*len);
+ buf = os_malloc(*len);
if (buf == NULL)
return NULL;
if (hexstr2bin(value, buf, *len)) {
- free(buf);
+ os_free(buf);
return NULL;
}
return buf;
@@ -321,9 +314,9 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
if (pac_file == NULL)
return -1;
- memset(&rc, 0, sizeof(rc));
+ os_memset(&rc, 0, sizeof(rc));
- if (strncmp(pac_file, "blob://", 7) == 0) {
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
const struct wpa_config_blob *blob;
blob = eap_get_config_blob(sm, pac_file + 7);
if (blob == NULL) {
@@ -344,17 +337,17 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
}
}
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL) {
return -1;
}
line++;
if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
- strcmp(pac_file_hdr, buf) != 0) {
+ os_strcmp(pac_file_hdr, buf) != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
"PAC file '%s'", pac_file);
- free(buf);
+ os_free(buf);
if (rc.f)
fclose(rc.f);
return -1;
@@ -362,12 +355,12 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
line++;
- pos = strchr(buf, '=');
+ pos = os_strchr(buf, '=');
if (pos) {
*pos++ = '\0';
}
- if (strcmp(buf, "START") == 0) {
+ if (os_strcmp(buf, "START") == 0) {
if (pac) {
wpa_printf(MSG_INFO, "EAP-FAST: START line "
"without END in '%s:%d'",
@@ -375,15 +368,14 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- pac = malloc(sizeof(*pac));
+ pac = os_zalloc(sizeof(*pac));
if (pac == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No memory for "
"PAC entry");
ret = -1;
break;
}
- memset(pac, 0, sizeof(*pac));
- } else if (strcmp(buf, "END") == 0) {
+ } else if (os_strcmp(buf, "END") == 0) {
if (pac == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: END line "
"without START in '%s:%d'",
@@ -395,7 +387,7 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
data->pac = pac;
pac = NULL;
count++;
- } else if (pac && strcmp(buf, "PAC-Key") == 0) {
+ } else if (pac && os_strcmp(buf, "PAC-Key") == 0) {
u8 *key;
size_t key_len;
key = eap_fast_parse_hex(pos, &key_len);
@@ -403,13 +395,14 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
"PAC-Key '%s:%d'", pac_file, line);
ret = -1;
- free(key);
+ os_free(key);
break;
}
- memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
- free(key);
- } else if (pac && strcmp(buf, "PAC-Opaque") == 0) {
+ os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
+ os_free(key);
+ } else if (pac && os_strcmp(buf, "PAC-Opaque") == 0) {
+ os_free(pac->pac_opaque);
pac->pac_opaque =
eap_fast_parse_hex(pos, &pac->pac_opaque_len);
if (pac->pac_opaque == NULL) {
@@ -419,7 +412,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "A-ID") == 0) {
+ } else if (pac && os_strcmp(buf, "A-ID") == 0) {
+ os_free(pac->a_id);
pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
if (pac->a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
@@ -427,7 +421,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "I-ID") == 0) {
+ } else if (pac && os_strcmp(buf, "I-ID") == 0) {
+ os_free(pac->i_id);
pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
if (pac->i_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
@@ -435,7 +430,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "A-ID-Info") == 0) {
+ } else if (pac && os_strcmp(buf, "A-ID-Info") == 0) {
+ os_free(pac->a_id_info);
pac->a_id_info =
eap_fast_parse_hex(pos, &pac->a_id_info_len);
if (pac->a_id_info == NULL) {
@@ -455,7 +451,7 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
}
- free(buf);
+ os_free(buf);
if (rc.f)
fclose(rc.f);
@@ -472,20 +468,20 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
const char *field, const u8 *data,
size_t len, int txt)
{
- int i;
- size_t need;
+ size_t i, need;
+ int ret;
if (data == NULL || *buf == NULL)
return;
- need = strlen(field) + len * 2 + 30;
+ need = os_strlen(field) + len * 2 + 30;
if (txt)
- need += strlen(field) + len + 20;
+ need += os_strlen(field) + len + 20;
if (*pos - *buf + need > *buf_len) {
- char *nbuf = realloc(*buf, *buf_len + need);
+ char *nbuf = os_realloc(*buf, *buf_len + need);
if (nbuf == NULL) {
- free(*buf);
+ os_free(*buf);
*buf = NULL;
return;
}
@@ -493,21 +489,33 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
*buf_len += need;
}
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
- for (i = 0; i < len; i++) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%02x", data[i]);
- }
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
+ *pos += wpa_snprintf_hex(*pos, *buf + *buf_len - *pos, data, len);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
if (txt) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%s-txt=", field);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+ "%s-txt=", field);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
for (i = 0; i < len; i++) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%c", data[i]);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+ "%c", data[i]);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
}
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
}
}
@@ -517,7 +525,7 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
{
FILE *f;
struct eap_fast_pac *pac;
- int count = 0;
+ int count = 0, ret;
char *buf, *pos;
size_t buf_len;
@@ -525,15 +533,25 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
return -1;
buf_len = 1024;
- pos = buf = malloc(buf_len);
+ pos = buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- pos += snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+ ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
pac = data->pac;
while (pac) {
- pos += snprintf(pos, buf + buf_len - pos, "START\n");
+ ret = os_snprintf(pos, buf + buf_len - pos, "START\n");
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
EAP_FAST_PAC_KEY_LEN, 0);
eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
@@ -546,31 +564,35 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
pac->i_id_len, 1);
eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info",
pac->a_id_info, pac->a_id_info_len, 1);
- pos += snprintf(pos, buf + buf_len - pos, "END\n");
- count++;
- pac = pac->next;
-
if (buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
"data");
return -1;
}
+ ret = os_snprintf(pos, buf + buf_len - pos, "END\n");
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
+ count++;
+ pac = pac->next;
}
- if (strncmp(pac_file, "blob://", 7) == 0) {
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
struct wpa_config_blob *blob;
- blob = malloc(sizeof(*blob));
+ blob = os_zalloc(sizeof(*blob));
if (blob == NULL) {
- free(buf);
+ os_free(buf);
return -1;
}
- memset(blob, 0, sizeof(*blob));
blob->data = (u8 *) buf;
blob->len = pos - buf;
buf = NULL;
- blob->name = strdup(pac_file + 7);
+ blob->name = os_strdup(pac_file + 7);
if (blob->name == NULL) {
- wpa_config_free_blob(blob);
+ os_free(blob->data);
+ os_free(blob);
return -1;
}
eap_set_config_blob(sm, blob);
@@ -579,11 +601,11 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
if (f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
"file '%s' for writing", pac_file);
- free(buf);
+ os_free(buf);
return -1;
}
fprintf(f, "%s", buf);
- free(buf);
+ os_free(buf);
fclose(f);
}
@@ -599,14 +621,13 @@ static void * eap_fast_init(struct eap_sm *sm)
struct eap_fast_data *data;
struct wpa_ssid *config = eap_get_config(sm);
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
data->fast_version = EAP_FAST_VERSION;
if (config && config->phase1) {
- if (strstr(config->phase1, "fast_provisioning=1")) {
+ if (os_strstr(config->phase1, "fast_provisioning=1")) {
data->provisioning_allowed = 1;
wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC "
"provisioning is allowed");
@@ -615,15 +636,17 @@ static void * eap_fast_init(struct eap_sm *sm)
if (config && config->phase2) {
char *start, *pos, *buf;
- u8 method, *methods = NULL, *_methods;
+ struct eap_method_type *methods = NULL, *_methods;
+ u8 method;
size_t num_methods = 0;
- start = buf = strdup(config->phase2);
+ start = buf = os_strdup(config->phase2);
if (buf == NULL) {
eap_fast_deinit(sm, data);
return NULL;
}
while (start && *start != '\0') {
- pos = strstr(start, "auth=");
+ int vendor;
+ pos = os_strstr(start, "auth=");
if (pos == NULL)
break;
if (start != pos && *(pos - 1) != ' ') {
@@ -632,28 +655,33 @@ static void * eap_fast_init(struct eap_sm *sm)
}
start = pos + 5;
- pos = strchr(start, ' ');
+ pos = os_strchr(start, ' ');
if (pos)
*pos++ = '\0';
- method = eap_get_phase2_type(start);
- if (method == EAP_TYPE_NONE) {
+ method = eap_get_phase2_type(start, &vendor);
+ if (vendor == EAP_VENDOR_IETF &&
+ method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported "
"Phase2 method '%s'", start);
} else {
num_methods++;
- _methods = realloc(methods, num_methods);
+ _methods = os_realloc(
+ methods,
+ num_methods * sizeof(*methods));
if (_methods == NULL) {
- free(methods);
+ os_free(methods);
+ os_free(buf);
eap_fast_deinit(sm, data);
return NULL;
}
methods = _methods;
- methods[num_methods - 1] = method;
+ methods[num_methods - 1].vendor = vendor;
+ methods[num_methods - 1].method = method;
}
start = pos;
}
- free(buf);
+ os_free(buf);
data->phase2_types = methods;
data->num_phase2_types = num_methods;
}
@@ -667,8 +695,10 @@ static void * eap_fast_init(struct eap_sm *sm)
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- data->phase2_type = EAP_TYPE_NONE;
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
@@ -706,9 +736,8 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
return;
if (data->phase2_priv && data->phase2_method)
data->phase2_method->deinit(sm, data->phase2_priv);
- free(data->phase2_types);
- free(data->key_block_a);
- free(data->key_block_p);
+ os_free(data->phase2_types);
+ os_free(data->key_block_p);
eap_tls_ssl_deinit(sm, &data->ssl);
pac = data->pac;
@@ -718,7 +747,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
pac = pac->next;
eap_fast_free_pac(prev);
}
- free(data);
+ os_free(data);
}
@@ -732,7 +761,7 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
/* TODO: add support for fragmentation, if needed. This will need to
* add TLS Message Length field, if the frame is fragmented. */
- resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
if (resp == NULL)
return 0;
@@ -749,7 +778,7 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (res < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
"data");
- free(resp);
+ os_free(resp);
return 0;
}
@@ -760,53 +789,57 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
}
-static int eap_fast_phase2_nak(struct eap_sm *sm,
- struct eap_fast_data *data,
+static int eap_fast_phase2_nak(struct eap_fast_data *data,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct eap_hdr *resp_hdr;
u8 *pos = (u8 *) (hdr + 1);
+ size_t i;
+ /* TODO: add support for expanded Nak */
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos);
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
- *resp = malloc(*resp_len);
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ *resp_len = sizeof(struct eap_hdr) + 1;
+ *resp = os_malloc(*resp_len + data->num_phase2_types);
if (*resp == NULL)
return -1;
resp_hdr = (struct eap_hdr *) (*resp);
resp_hdr->code = EAP_CODE_RESPONSE;
resp_hdr->identifier = hdr->identifier;
- resp_hdr->length = host_to_be16(*resp_len);
pos = (u8 *) (resp_hdr + 1);
*pos++ = EAP_TYPE_NAK;
- memcpy(pos, data->phase2_types, data->num_phase2_types);
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
+ data->phase2_types[i].method < 256) {
+ (*resp_len)++;
+ *pos++ = data->phase2_types[i].method;
+ }
+ }
+ resp_hdr->length = host_to_be16(*resp_len);
return 0;
}
-static int eap_fast_derive_msk(struct eap_sm *sm, struct eap_fast_data *data)
+static int eap_fast_derive_msk(struct eap_fast_data *data)
{
- u8 isk[32];
- u8 imck[60];
-
- if (data->key_block_a == NULL)
- return -1;
-
- memset(isk, 0, sizeof(isk));
- sha1_t_prf(data->key_block_a->session_key_seed,
- sizeof(data->key_block_a->session_key_seed),
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
- sha1_t_prf(imck, 40, "Session Key Generating Function", (u8 *) "", 0,
+ /* Derive EAP Master Session Keys (section 5.4) */
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
data->key_data, EAP_FAST_KEY_LEN);
-
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
data->key_data, EAP_FAST_KEY_LEN);
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function",
+ (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+ data->emsk, EAP_EMSK_LEN);
+
data->success = 1;
return 0;
@@ -823,7 +856,8 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
size_t seed_len, server_random_len;
if (data->tls_master_secret_set || !data->current_pac ||
- tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys)) {
+ tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
+ keys.client_random == NULL) {
return 0;
}
@@ -857,14 +891,13 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
server_random, server_random_len);
-
seed_len = keys.client_random_len + server_random_len;
- seed = malloc(seed_len);
+ seed = os_malloc(seed_len);
if (seed == NULL)
return -1;
- memcpy(seed, server_random, server_random_len);
- memcpy(seed + server_random_len,
- keys.client_random, keys.client_random_len);
+ os_memcpy(seed, server_random, server_random_len);
+ os_memcpy(seed + server_random_len,
+ keys.client_random, keys.client_random_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
@@ -874,7 +907,7 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
"PAC to master secret label hash",
seed, seed_len, master_secret, sizeof(master_secret));
- free(seed);
+ os_free(seed);
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
master_secret, sizeof(master_secret));
@@ -890,63 +923,86 @@ static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
- u8 *rnd;
- u8 *out;
+ u8 *rnd = NULL, *out;
int block_size;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
- return NULL;
block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
if (block_size < 0)
return NULL;
- out = malloc(block_size + len);
- rnd = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || rnd == NULL) {
- free(out);
- free(rnd);
+
+ out = os_malloc(block_size + len);
+ if (out == NULL)
return NULL;
+
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
+ block_size + len) == 0) {
+ os_memmove(out, out + block_size, len);
+ return out;
}
- memcpy(rnd, keys.server_random, keys.server_random_len);
- memcpy(rnd + keys.server_random_len, keys.client_random,
- keys.client_random_len);
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ goto fail;
+
+ rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+ if (rnd == NULL)
+ goto fail;
+
+ os_memcpy(rnd, keys.server_random, keys.server_random_len);
+ os_memcpy(rnd + keys.server_random_len, keys.client_random,
+ keys.client_random_len);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
"expansion", keys.master_key, keys.master_key_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, rnd, keys.client_random_len +
- keys.server_random_len, out, block_size + len)) {
- free(rnd);
- free(out);
- return NULL;
- }
- free(rnd);
- memmove(out, out + block_size, len);
+ keys.server_random_len, out, block_size + len))
+ goto fail;
+ os_free(rnd);
+ os_memmove(out, out + block_size, len);
return out;
+
+fail:
+ os_free(rnd);
+ os_free(out);
+ return NULL;
}
static void eap_fast_derive_key_auth(struct eap_sm *sm,
struct eap_fast_data *data)
{
- free(data->key_block_a);
- data->key_block_a = (struct eap_fast_key_block_auth *)
- eap_fast_derive_key(sm, &data->ssl, "key expansion",
- sizeof(*data->key_block_a));
- if (data->key_block_a == NULL) {
+ u8 *sks;
+
+ /* draft-cam-winget-eap-fast-05.txt:
+ * 5.1 EAP-FAST Authentication Phase 1: Key Derivations
+ * Extra key material after TLS key_block: session_ket_seed[40]
+ */
+
+ sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ EAP_FAST_SKS_LEN);
+ if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
"session_key_seed");
return;
}
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
- data->key_block_a->session_key_seed,
- sizeof(data->key_block_a->session_key_seed));
+
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+ sks, EAP_FAST_SKS_LEN);
+ data->simck_idx = 0;
+ os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+ os_free(sks);
}
static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
struct eap_fast_data *data)
{
- free(data->key_block_p);
+ os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm, &data->ssl, "key expansion",
sizeof(*data->key_block_p));
@@ -954,9 +1010,17 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
return;
}
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
data->key_block_p->session_key_seed,
sizeof(data->key_block_p->session_key_seed));
+ data->simck_idx = 0;
+ os_memcpy(data->simck, data->key_block_p->session_key_seed,
+ EAP_FAST_SIMCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
data->key_block_p->server_challenge,
sizeof(data->key_block_p->server_challenge));
@@ -979,7 +1043,6 @@ static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
static int eap_fast_phase2_request(struct eap_sm *sm,
struct eap_fast_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -996,30 +1059,40 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
switch (*pos) {
case EAP_TYPE_IDENTITY:
- *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
break;
default:
- if (data->phase2_type == EAP_TYPE_NONE) {
- int i;
+ if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+ data->phase2_type.method == EAP_TYPE_NONE) {
+ size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i] != *pos)
+ if (data->phase2_types[i].vendor !=
+ EAP_VENDOR_IETF ||
+ data->phase2_types[i].method != *pos)
continue;
- data->phase2_type = *pos;
+ data->phase2_type.vendor =
+ data->phase2_types[i].vendor;
+ data->phase2_type.method =
+ data->phase2_types[i].method;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected "
- "Phase 2 EAP method %d",
- data->phase2_type);
+ "Phase 2 EAP vendor %d method %d",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
break;
}
}
- if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
- if (eap_fast_phase2_nak(sm, data, hdr, resp, resp_len))
+ if (*pos != data->phase2_type.method ||
+ *pos == EAP_TYPE_NONE) {
+ if (eap_fast_phase2_nak(data, hdr, resp, resp_len))
return -1;
return 0;
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_sm_get_eap_methods(*pos);
+ data->phase2_method = eap_sm_get_eap_methods(
+ data->phase2_type.vendor,
+ data->phase2_type.method);
if (data->phase2_method) {
if (data->key_block_p) {
sm->auth_challenge =
@@ -1030,9 +1103,11 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
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;
}
@@ -1044,7 +1119,7 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
ret->decision = DECISION_FAIL;
return -1;
}
- memset(&iret, 0, sizeof(iret));
+ os_memset(&iret, 0, sizeof(iret));
*resp = data->phase2_method->process(sm, data->phase2_priv,
&iret, (u8 *) hdr, len,
resp_len);
@@ -1071,7 +1146,7 @@ static u8 * eap_fast_tlv_nak(int vendor_id, int tlv_type, size_t *len)
{
struct eap_tlv_nak_tlv *nak;
*len = sizeof(*nak);
- nak = malloc(*len);
+ nak = os_malloc(*len);
if (nak == NULL)
return NULL;
nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
@@ -1086,7 +1161,7 @@ static u8 * eap_fast_tlv_result(int status, int intermediate, size_t *len)
{
struct eap_tlv_intermediate_result_tlv *result;
*len = sizeof(*result);
- result = malloc(*len);
+ result = os_malloc(*len);
if (result == NULL)
return NULL;
result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
@@ -1105,11 +1180,10 @@ static u8 * eap_fast_tlv_pac_ack(size_t *len)
struct eap_tlv_pac_ack_tlv *ack;
*len = sizeof(*res) + sizeof(*ack);
- res = malloc(*len);
+ res = os_zalloc(*len);
if (res == NULL)
return NULL;
- memset(res, 0, *len);
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));
@@ -1132,19 +1206,19 @@ static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
struct eap_tlv_hdr *tlv;
/* Encapsulate EAP packet in EAP Payload TLV */
- tlv = malloc(sizeof(*tlv) + *len);
+ tlv = os_malloc(sizeof(*tlv) + *len);
if (tlv == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
"allocate memory for TLV "
"encapsulation");
- free(buf);
+ os_free(buf);
return NULL;
}
tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
EAP_TLV_EAP_PAYLOAD_TLV);
tlv->length = host_to_be16(*len);
- memcpy(tlv + 1, buf, *len);
- free(buf);
+ os_memcpy(tlv + 1, buf, *len);
+ os_free(buf);
*len += sizeof(*tlv);
return (u8 *) tlv;
}
@@ -1153,10 +1227,10 @@ static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
static u8 * eap_fast_process_crypto_binding(
struct eap_sm *sm, struct eap_fast_data *data,
struct eap_method_ret *ret,
- struct eap_tlv_crypto_binding__tlv *bind, size_t bind_len,
+ struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len,
size_t *resp_len, int final)
{
- u8 *resp, *sks = NULL;
+ u8 *resp;
struct eap_tlv_intermediate_result_tlv *rresult;
struct eap_tlv_crypto_binding__tlv *rbind;
u8 isk[32], imck[60], *cmk, cmac[20], *key;
@@ -1165,46 +1239,37 @@ static u8 * eap_fast_process_crypto_binding(
wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
- bind->version, bind->received_version, bind->subtype);
+ _bind->version, _bind->received_version, _bind->subtype);
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
- bind->nonce, sizeof(bind->nonce));
+ _bind->nonce, sizeof(_bind->nonce));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
- bind->compound_mac, sizeof(bind->compound_mac));
+ _bind->compound_mac, sizeof(_bind->compound_mac));
- if (bind->version != EAP_FAST_VERSION ||
- bind->received_version != EAP_FAST_VERSION ||
- bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
+ if (_bind->version != EAP_FAST_VERSION ||
+ _bind->received_version != EAP_FAST_VERSION ||
+ _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
"Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
- bind->version, bind->received_version,
- bind->subtype);
+ _bind->version, _bind->received_version,
+ _bind->subtype);
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
resp_len);
return resp;
}
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
+ "calculation", data->simck_idx + 1);
- if (data->provisioning) {
- if (data->key_block_p) {
- sks = data->key_block_p->session_key_seed;
- }
- } else {
- if (data->key_block_a) {
- sks = data->key_block_a->session_key_seed;
- }
- }
- if (sks == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: No Session Key Seed available "
- "for processing Crypto-Binding TLV");
- return NULL;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK for Compound MIC "
- "calculation");
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[0] = SKS", sks, 40);
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+ * MSK[j], 60)
+ * S-IMCK[j] = first 40 octets of IMCK[j]
+ * CMK[j] = last 20 octets of IMCK[j]
+ */
- memset(isk, 0, sizeof(isk));
+ os_memset(isk, 0, sizeof(isk));
if (data->phase2_method == NULL || data->phase2_priv == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
"available");
@@ -1222,45 +1287,42 @@ static u8 * eap_fast_process_crypto_binding(
}
if (key_len > sizeof(isk))
key_len = sizeof(isk);
- /* FIX: which end is being padded? */
-#if 0
- memcpy(isk + (sizeof(isk) - key_len), key, key_len);
-#else
- memcpy(isk, key, key_len);
-#endif
- free(key);
+ os_memcpy(isk, key, key_len);
+ os_free(key);
}
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[0]", isk, sizeof(isk));
- sha1_t_prf(sks, 40, "Inner Methods Compound Keys",
+ 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));
- /* S-IMCK[1] = imkc[0..39] */
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[1]", imck, 40);
- cmk = imck + 40;
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK", cmk, 20);
-
- memcpy(cmac, bind->compound_mac, sizeof(cmac));
- memset(bind->compound_mac, 0, sizeof(cmac));
+ data->simck_idx++;
+ os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+ data->simck, EAP_FAST_SIMCK_LEN);
+ cmk = imck + EAP_FAST_SIMCK_LEN;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
+
+ os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
+ os_memset(_bind->compound_mac, 0, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
- "MAC calculation", (u8 *) bind, bind_len);
- hmac_sha1(cmk, 20, (u8 *) bind, bind_len, bind->compound_mac);
- res = memcmp(cmac, bind->compound_mac, sizeof(cmac));
+ "MAC calculation", (u8 *) _bind, bind_len);
+ hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
+ res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
cmac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
- bind->compound_mac, sizeof(cmac));
+ _bind->compound_mac, sizeof(cmac));
if (res != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
resp_len);
- memcpy(bind->compound_mac, cmac, sizeof(cmac));
+ os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
return resp;
}
*resp_len = sizeof(*rresult) + sizeof(*rbind);
- resp = malloc(*resp_len);
+ resp = os_zalloc(*resp_len);
if (resp == NULL)
return NULL;
- memset(resp, 0, *resp_len);
/* Both intermediate and final Result TLVs are identical, so ok to use
* the same structure definition for them. */
@@ -1272,7 +1334,7 @@ static u8 * eap_fast_process_crypto_binding(
rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
if (!data->provisioning && data->phase2_success &&
- eap_fast_derive_msk(sm, data) < 0) {
+ eap_fast_derive_msk(data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -1286,10 +1348,10 @@ static u8 * eap_fast_process_crypto_binding(
rbind->length = host_to_be16(sizeof(*rbind) -
sizeof(struct eap_tlv_hdr));
rbind->version = EAP_FAST_VERSION;
- rbind->received_version = bind->version;
+ rbind->received_version = _bind->version;
rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
- memcpy(rbind->nonce, bind->nonce, sizeof(bind->nonce));
- inc_byte_array(rbind->nonce, sizeof(bind->nonce));
+ os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
+ inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
@@ -1322,7 +1384,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
int type, pac_key_found = 0;
struct eap_fast_pac entry;
- memset(&entry, 0, sizeof(entry));
+ os_memset(&entry, 0, sizeof(entry));
pos = pac;
left = pac_len;
while (left > sizeof(*hdr)) {
@@ -1350,7 +1412,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
break;
}
pac_key_found = 1;
- memcpy(entry.pac_key, pos, len);
+ os_memcpy(entry.pac_key, pos, len);
break;
case PAC_TYPE_PAC_OPAQUE:
wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
@@ -1463,10 +1525,10 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted, *pos, *end;
- int buf_len, len_decrypted, len;
+ int len_decrypted, len;
struct eap_hdr *hdr;
u8 *resp = NULL;
- size_t resp_len;
+ size_t buf_len, resp_len;
int mandatory, tlv_type;
u8 *eap_payload_tlv = NULL, *pac = NULL;
size_t eap_payload_tlv_len = 0, pac_len = 0;
@@ -1475,7 +1537,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
size_t crypto_binding_len = 0;
const u8 *msg;
size_t msg_len;
- int need_more_input;
+ int need_more_input, stop;
wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1488,9 +1550,9 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
buf_len = data->ssl.tls_in_total;
- in_decrypted = malloc(buf_len);
+ in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-FAST: failed to allocate memory "
@@ -1501,13 +1563,13 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
msg, msg_len,
in_decrypted, buf_len);
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
if (len_decrypted < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
"data");
- free(in_decrypted);
+ os_free(in_decrypted);
return -1;
}
@@ -1515,7 +1577,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
in_decrypted, len_decrypted);
if (len_decrypted < 4) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
"TLV frame (len=%d)", len_decrypted);
return -1;
@@ -1523,14 +1585,15 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
pos = in_decrypted;
end = in_decrypted + len_decrypted;
- while (pos + 4 < end) {
+ stop = 0;
+ while (pos + 4 < end && !stop) {
mandatory = pos[0] & 0x80;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
if (pos + len > end) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return 0;
}
@@ -1613,7 +1676,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
"mandatory TLV type %d", tlv_type);
resp = eap_fast_tlv_nak(0, tlv_type,
&resp_len);
- pos = end;
+ stop = 1;
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
"unknown optional TLV type %d",
@@ -1629,7 +1692,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1638,7 +1701,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1648,31 +1711,33 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
"Payload TLV (len=%lu)",
(unsigned long) eap_payload_tlv_len);
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
hdr = (struct eap_hdr *) eap_payload_tlv;
if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow "
"in EAP Payload TLV");
+ os_free(in_decrypted);
+ return 0;
}
if (hdr->code == EAP_CODE_REQUEST) {
- if (eap_fast_phase2_request(sm, data, ret, req, hdr,
+ if (eap_fast_phase2_request(sm, data, ret, hdr,
&resp, &resp_len)) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: Phase2 "
"Request processing failed");
return 0;
}
resp = eap_fast_tlv_eap_payload(resp, &resp_len);
if (resp == NULL) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
} else {
wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
"Phase 2 EAP header", hdr->code);
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1684,7 +1749,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
crypto_binding_len,
&resp_len, final);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1695,7 +1760,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1704,17 +1769,17 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_process_pac(sm, data, ret, pac, pac_len,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
- free(in_decrypted);
+ os_free(in_decrypted);
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
"empty response packet");
- resp = malloc(1);
+ resp = os_malloc(1);
if (resp == NULL)
return 0;
resp_len = 0;
@@ -1727,7 +1792,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
"frame");
}
- free(resp);
+ os_free(resp);
return 0;
}
@@ -1803,17 +1868,17 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
} else if (data->current_pac) {
u8 *tlv;
size_t tlv_len, olen;
- struct eap_tlv_hdr *hdr;
+ struct eap_tlv_hdr *ehdr;
olen = data->current_pac->pac_opaque_len;
- tlv_len = sizeof(*hdr) + olen;
- tlv = malloc(tlv_len);
+ tlv_len = sizeof(*ehdr) + olen;
+ tlv = os_malloc(tlv_len);
if (tlv) {
- hdr = (struct eap_tlv_hdr *) tlv;
- hdr->tlv_type =
+ ehdr = (struct eap_tlv_hdr *) tlv;
+ ehdr->tlv_type =
host_to_be16(PAC_TYPE_PAC_OPAQUE);
- hdr->length = host_to_be16(olen);
- memcpy(hdr + 1, data->current_pac->pac_opaque,
- olen);
+ ehdr->length = host_to_be16(olen);
+ os_memcpy(ehdr + 1,
+ data->current_pac->pac_opaque, olen);
}
if (tlv == NULL ||
tls_connection_client_hello_ext(
@@ -1821,11 +1886,12 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
"add PAC-Opaque TLS extension");
- free(tlv);
+ os_free(tlv);
return NULL;
}
- free(tlv);
+ os_free(tlv);
} else {
+ u8 ciphers[2];
if (!data->provisioning_allowed) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found "
"and provisioning disabled");
@@ -1833,8 +1899,11 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
}
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
"starting provisioning");
- if (tls_connection_set_anon_dh(sm->ssl_ctx,
- data->ssl.conn)) {
+ ciphers[0] = TLS_CIPHER_ANON_DH_AES128_SHA;
+ ciphers[1] = TLS_CIPHER_NONE;
+ if (tls_connection_set_cipher_list(sm->ssl_ctx,
+ data->ssl.conn,
+ ciphers)) {
wpa_printf(MSG_INFO, "EAP-FAST: Could not "
"configure anonymous DH for TLS "
"connection");
@@ -1903,6 +1972,9 @@ static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
+ struct eap_fast_data *data = priv;
+ os_free(data->key_block_p);
+ data->key_block_p = NULL;
}
@@ -1910,12 +1982,16 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
if (eap_tls_reauth_init(sm, &data->ssl)) {
- free(data);
+ os_free(data);
return NULL;
}
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->init_for_reauth)
+ data->phase2_method->init_for_reauth(sm, data->phase2_priv);
data->phase2_success = 0;
data->resuming = 1;
data->provisioning = 0;
+ data->simck_idx = 0;
return priv;
}
#endif
@@ -1925,7 +2001,18 @@ static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
size_t buflen, int verbose)
{
struct eap_fast_data *data = priv;
- return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ int len, ret;
+
+ len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ if (data->phase2_method) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "EAP-FAST Phase2 method=%s\n",
+ data->phase2_method->name);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+ }
+ return len;
}
@@ -1944,30 +2031,61 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (!data->success)
return NULL;
- key = malloc(EAP_FAST_KEY_LEN);
+ key = os_malloc(EAP_FAST_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_FAST_KEY_LEN;
- memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
+ os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
return key;
}
-const struct eap_method eap_method_fast =
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_FAST,
- .name = "FAST",
- .init = eap_fast_init,
- .deinit = eap_fast_deinit,
- .process = eap_fast_process,
- .isKeyAvailable = eap_fast_isKeyAvailable,
- .getKey = eap_fast_getKey,
- .get_status = eap_fast_get_status,
+ struct eap_fast_data *data = priv;
+ u8 *key;
+
+ if (!data->success)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
+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");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_fast_init;
+ eap->deinit = eap_fast_deinit;
+ eap->process = eap_fast_process;
+ eap->isKeyAvailable = eap_fast_isKeyAvailable;
+ eap->getKey = eap_fast_getKey;
+ eap->get_status = eap_fast_get_status;
#if 0
- .has_reauth_data = eap_fast_has_reauth_data,
- .deinit_for_reauth = eap_fast_deinit_for_reauth,
- .init_for_reauth = eap_fast_init_for_reauth,
+ eap->has_reauth_data = eap_fast_has_reauth_data;
+ eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
+ eap->init_for_reauth = eap_fast_init_for_reauth;
#endif
-};
+ eap->get_emsk = eap_fast_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
OpenPOWER on IntegriCloud