aboutsummaryrefslogtreecommitdiffstats
path: root/src/eap_server
diff options
context:
space:
mode:
Diffstat (limited to 'src/eap_server')
-rw-r--r--src/eap_server/eap.h22
-rw-r--r--src/eap_server/eap_i.h23
-rw-r--r--src/eap_server/eap_server.c544
-rw-r--r--src/eap_server/eap_server_aka.c24
-rw-r--r--src/eap_server/eap_server_fast.c16
-rw-r--r--src/eap_server/eap_server_gpsk.c36
-rw-r--r--src/eap_server/eap_server_ikev2.c37
-rw-r--r--src/eap_server/eap_server_mschapv2.c17
-rw-r--r--src/eap_server/eap_server_pax.c25
-rw-r--r--src/eap_server/eap_server_peap.c13
-rw-r--r--src/eap_server/eap_server_psk.c23
-rw-r--r--src/eap_server/eap_server_pwd.c22
-rw-r--r--src/eap_server/eap_server_sake.c23
-rw-r--r--src/eap_server/eap_server_sim.c24
-rw-r--r--src/eap_server/eap_server_tls.c15
-rw-r--r--src/eap_server/eap_server_tls_common.c41
-rw-r--r--src/eap_server/eap_server_ttls.c48
-rw-r--r--src/eap_server/eap_server_wsc.c2
-rw-r--r--src/eap_server/eap_sim_db.c23
-rw-r--r--src/eap_server/eap_tls_common.h3
20 files changed, 943 insertions, 38 deletions
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 1253bd6e..9de6cb62 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define EAP_H
#include "common/defs.h"
+#include "utils/list.h"
#include "eap_common/eap_defs.h"
#include "eap_server/eap_methods.h"
#include "wpabuf.h"
@@ -58,6 +59,8 @@ struct eap_eapol_interface {
struct wpabuf *eapReqData;
u8 *eapKeyData;
size_t eapKeyDataLen;
+ u8 *eapSessionId;
+ size_t eapSessionIdLen;
Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
/* AAA interface to full authenticator variables */
@@ -78,11 +81,27 @@ struct eap_eapol_interface {
Boolean aaaTimeout;
};
+struct eap_server_erp_key {
+ struct dl_list list;
+ size_t rRK_len;
+ size_t rIK_len;
+ u8 rRK[ERP_MAX_KEY_LEN];
+ u8 rIK[ERP_MAX_KEY_LEN];
+ u32 recv_seq;
+ u8 cryptosuite;
+ char keyname_nai[];
+};
+
struct eapol_callbacks {
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
void (*log_msg)(void *ctx, const char *msg);
+ int (*get_erp_send_reauth_start)(void *ctx);
+ const char * (*get_erp_domain)(void *ctx);
+ struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+ const char *keyname);
+ int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
};
struct eap_config {
@@ -111,6 +130,7 @@ struct eap_config {
const u8 *server_id;
size_t server_id_len;
+ int erp;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3a6802b7..7d723091 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -88,6 +88,19 @@ struct eap_method {
* private data or this function may derive the key.
*/
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * getSessionId - Get EAP method specific Session-Id
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store Session-Id length
+ * Returns: Session-Id or %NULL if not available
+ *
+ * This function can be used to get the Session-Id from the EAP method.
+ * The Session-Id may already be stored in the method-specific private
+ * data or this function may derive the Session-Id.
+ */
+ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};
/**
@@ -103,7 +116,8 @@ struct eap_sm {
EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
- EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
+ EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
+ EAP_INITIATE_REAUTH_START, EAP_INITIATE_RECEIVED
} EAP_state;
/* Constants */
@@ -125,6 +139,7 @@ struct eap_sm {
/* Short-term (not maintained between packets) */
Boolean rxResp;
+ Boolean rxInitiate;
int respId;
EapType respMethod;
int respVendor;
@@ -132,7 +147,7 @@ struct eap_sm {
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
- DECISION_PASSTHROUGH
+ DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
} decision;
/* Miscellaneous variables */
@@ -192,6 +207,10 @@ struct eap_sm {
const u8 *server_id;
size_t server_id_len;
+ Boolean initiate_reauth_start_sent;
+ Boolean try_initiate_reauth;
+ int erp;
+
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index c1bb6b83..bd919e57 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,6 +15,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "eap_i.h"
#include "state_machine.h"
#include "common/wpa_ctrl.h"
@@ -44,6 +45,73 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm);
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_send_reauth_start)
+ return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
+ return 0;
+}
+
+
+static const char * eap_get_erp_domain(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_domain)
+ return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
+ return NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
+ const char *keyname)
+{
+ if (sm->eapol_cb->erp_get_key)
+ return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
+ return NULL;
+}
+
+
+static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
+{
+ if (sm->eapol_cb->erp_add_key)
+ return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
+ return -1;
+}
+
+#endif /* CONFIG_ERP */
+
+
+static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
+ u8 id)
+{
+ const char *domain;
+ size_t plen = 1;
+ struct wpabuf *msg;
+ size_t domain_len = 0;
+
+ domain = eap_get_erp_domain(sm);
+ if (domain) {
+ domain_len = os_strlen(domain);
+ plen += 2 + domain_len;
+ }
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
+ EAP_CODE_INITIATE, id);
+ if (msg == NULL)
+ return NULL;
+ wpabuf_put_u8(msg, 0); /* Reserved */
+ if (domain) {
+ /* Domain name TLV */
+ wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
+ wpabuf_put_u8(msg, domain_len);
+ wpabuf_put_data(msg, domain, domain_len);
+ }
+
+ return msg;
+}
+
+
static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
{
if (src == NULL)
@@ -164,6 +232,7 @@ SM_STATE(EAP, INITIALIZE)
eap_server_clear_identity(sm);
}
+ sm->try_initiate_reauth = FALSE;
sm->currentId = -1;
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
@@ -171,6 +240,9 @@ SM_STATE(EAP, INITIALIZE)
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ sm->eap_if.eapSessionIdLen = 0;
sm->eap_if.eapKeyAvailable = FALSE;
sm->eap_if.eapRestart = FALSE;
@@ -336,6 +408,95 @@ SM_STATE(EAP, METHOD_REQUEST)
}
+static void eap_server_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ u8 *emsk = NULL;
+ size_t emsk_len = 0;
+ u8 EMSKname[EAP_EMSK_NAME_LEN];
+ u8 len[2];
+ const char *domain;
+ size_t domain_len, nai_buf_len;
+ struct eap_server_erp_key *erp = NULL;
+ int pos;
+
+ domain = eap_get_erp_domain(sm);
+ if (!domain)
+ return;
+
+ domain_len = os_strlen(domain);
+
+ nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
+ if (nai_buf_len > 253) {
+ /*
+ * keyName-NAI has a maximum length of 253 octet to fit in
+ * RADIUS attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long realm for ERP keyName-NAI maximum length");
+ return;
+ }
+ nai_buf_len++; /* null termination */
+ erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+ if (erp == NULL)
+ goto fail;
+ erp->recv_seq = (u32) -1;
+
+ emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+ if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No suitable EMSK available for ERP");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+ WPA_PUT_BE16(len, 8);
+ if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
+ "EMSK", len, sizeof(len),
+ EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+ pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+ EMSKname, EAP_EMSK_NAME_LEN);
+ erp->keyname_nai[pos] = '@';
+ os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
+
+ WPA_PUT_BE16(len, emsk_len);
+ if (hmac_sha256_kdf(emsk, emsk_len,
+ "EAP Re-authentication Root Key@ietf.org",
+ len, sizeof(len), erp->rRK, emsk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+ goto fail;
+ }
+ erp->rRK_len = emsk_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "EAP Re-authentication Integrity Key@ietf.org",
+ len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+ goto fail;
+ }
+ erp->rIK_len = erp->rRK_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+ if (eap_erp_add_key(sm, erp) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
+ erp->keyname_nai);
+ erp = NULL;
+ }
+
+fail:
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(erp, sizeof(*erp));
+#endif /* CONFIG_ERP */
+}
+
+
SM_STATE(EAP, METHOD_RESPONSE)
{
SM_ENTRY(EAP, METHOD_RESPONSE);
@@ -355,6 +516,18 @@ SM_STATE(EAP, METHOD_RESPONSE)
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
}
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ if (sm->m->getSessionId) {
+ sm->eap_if.eapSessionId = sm->m->getSessionId(
+ sm, sm->eap_method_priv,
+ &sm->eap_if.eapSessionIdLen);
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eap_if.eapSessionId,
+ sm->eap_if.eapSessionIdLen);
+ }
+ if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
sm->methodState = METHOD_CONTINUE;
@@ -369,6 +542,7 @@ SM_STATE(EAP, PROPOSE_METHOD)
SM_ENTRY(EAP, PROPOSE_METHOD);
+ sm->try_initiate_reauth = FALSE;
try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
@@ -492,12 +666,326 @@ SM_STATE(EAP, SUCCESS)
}
+SM_STATE(EAP, INITIATE_REAUTH_START)
+{
+ SM_ENTRY(EAP, INITIATE_REAUTH_START);
+
+ sm->initiate_reauth_start_sent = TRUE;
+ sm->try_initiate_reauth = TRUE;
+ sm->currentId = eap_sm_nextId(sm, sm->currentId);
+ wpa_printf(MSG_DEBUG,
+ "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
+ sm->currentId);
+ sm->lastId = sm->currentId;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
+ sm->currentId);
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static void erp_send_finish_reauth(struct eap_sm *sm,
+ struct eap_server_erp_key *erp, u8 id,
+ u8 flags, u16 seq, const char *nai)
+{
+ size_t plen;
+ struct wpabuf *msg;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ u8 seed[4];
+
+ if (erp) {
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ hash_len = 16;
+ break;
+ default:
+ return;
+ }
+ } else
+ hash_len = 0;
+
+ plen = 1 + 2 + 2 + os_strlen(nai);
+ if (hash_len)
+ plen += 1 + hash_len;
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
+ EAP_CODE_FINISH, id);
+ if (msg == NULL)
+ return;
+ wpabuf_put_u8(msg, flags);
+ wpabuf_put_be16(msg, seq);
+
+ wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+ wpabuf_put_u8(msg, os_strlen(nai));
+ wpabuf_put_str(msg, nai);
+
+ if (erp) {
+ wpabuf_put_u8(msg, erp->cryptosuite);
+ if (hmac_sha256(erp->rIK, erp->rIK_len,
+ wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+ wpabuf_free(msg);
+ return;
+ }
+ wpabuf_put_data(msg, hash, hash_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
+ flags & 0x80 ? "failure" : "success");
+
+ sm->lastId = sm->currentId;
+ sm->currentId = id;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = msg;
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+
+ if (flags & 0x80) {
+ sm->eap_if.eapFail = TRUE;
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ MACSTR, MAC2STR(sm->peer_addr));
+ return;
+ }
+
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapKeyDataLen = 0;
+ sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
+ if (!sm->eap_if.eapKeyData)
+ return;
+
+ WPA_PUT_BE16(seed, seq);
+ WPA_PUT_BE16(&seed[2], erp->rRK_len);
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "Re-authentication Master Session Key@ietf.org",
+ seed, sizeof(seed),
+ sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+ bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
+ sm->eap_if.eapKeyData = NULL;
+ return;
+ }
+ sm->eap_if.eapKeyDataLen = erp->rRK_len;
+ sm->eap_if.eapKeyAvailable = TRUE;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+ sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapSuccess = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, INITIATE_RECEIVED)
+{
+ const u8 *pos, *end, *start, *tlvs, *hdr;
+ const struct eap_hdr *ehdr;
+ size_t len;
+ u8 flags;
+ u16 seq;
+ char nai[254];
+ struct eap_server_erp_key *erp;
+ int max_len;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ struct erp_tlvs parse;
+ u8 resp_flags = 0x80; /* default to failure; cleared on success */
+
+ SM_ENTRY(EAP, INITIATE_RECEIVED);
+
+ sm->rxInitiate = FALSE;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ sm->eap_if.eapRespData, &len);
+ if (pos == NULL) {
+ wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
+ goto fail;
+ }
+ hdr = wpabuf_head(sm->eap_if.eapRespData);
+ ehdr = wpabuf_head(sm->eap_if.eapRespData);
+
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ end = pos + len;
+
+ flags = *pos++;
+ seq = WPA_GET_BE16(pos);
+ pos += 2;
+ wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+ tlvs = pos;
+
+ /*
+ * Parse TVs/TLVs. Since we do not yet know the length of the
+ * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+ * just try to find the keyName-NAI first so that we can check the
+ * Authentication Tag.
+ */
+ if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
+ goto fail;
+
+ if (!parse.keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
+ goto fail;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ if (parse.keyname_len > 253) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ os_memcpy(nai, parse.keyname, parse.keyname_len);
+ nai[parse.keyname_len] = '\0';
+
+ if (!sm->eap_server) {
+ /*
+ * In passthrough case, EAP-Initiate/Re-auth replaces
+ * EAP Identity exchange. Use keyName-NAI as the user identity
+ * and forward EAP-Initiate/Re-auth to the backend
+ * authentication server.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Use keyName-NAI as user identity for backend authentication");
+ eap_server_clear_identity(sm);
+ sm->identity = (u8 *) dup_binstr(parse.keyname,
+ parse.keyname_len);
+ if (!sm->identity)
+ goto fail;
+ sm->identity_len = parse.keyname_len;
+ return;
+ }
+
+ erp = eap_erp_get_key(sm, nai);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+ nai);
+ goto report_error;
+ }
+
+ if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: SEQ=%u replayed (already received SEQ=%u)",
+ seq, erp->recv_seq);
+ goto fail;
+ }
+
+ /* Is there enough room for Cryptosuite and Authentication Tag? */
+ start = parse.keyname + parse.keyname_len;
+ max_len = end - start;
+ if (max_len <
+ 1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Not enough room for Authentication Tag");
+ goto fail;
+ }
+
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ if (end[-33] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ if (end[-17] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 16;
+ break;
+ default:
+ hash_len = 0;
+ break;
+ }
+
+ if (hash_len) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - hash_len, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag mismatch");
+ goto fail;
+ }
+ }
+
+ /* Check if any supported CS results in matching tag */
+ if (!hash_len && max_len >= 1 + 32 &&
+ end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 32, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 32, hash, 32) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-256");
+ hash_len = 32;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
+ }
+ }
+
+ if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 16, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 16, hash, 16) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-128");
+ hash_len = 16;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
+ }
+ }
+
+ if (!hash_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No supported cryptosuite matched Authentication Tag");
+ goto fail;
+ }
+ end -= 1 + hash_len;
+
+ /*
+ * Parse TVs/TLVs again now that we know the exact part of the buffer
+ * that contains them.
+ */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
+ tlvs, end - tlvs);
+ if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
+ erp->keyname_nai, seq);
+ erp->recv_seq = seq;
+ resp_flags &= ~0x80; /* R=0 - success */
+
+report_error:
+ erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
+ return;
+
+fail:
+ sm->ignore = TRUE;
+}
+
+#endif /* CONFIG_ERP */
+
+
SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
{
SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
wpabuf_free(sm->eap_if.aaaEapRespData);
sm->eap_if.aaaEapRespData = NULL;
+ sm->try_initiate_reauth = FALSE;
}
@@ -691,9 +1179,14 @@ SM_STEP(EAP)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
- if (sm->eap_if.retransWhile == 0)
- SM_ENTER(EAP, RETRANSMIT);
- else if (sm->eap_if.eapResp)
+ if (sm->eap_if.retransWhile == 0) {
+ if (sm->try_initiate_reauth) {
+ sm->try_initiate_reauth = FALSE;
+ SM_ENTER(EAP, SELECT_ACTION);
+ } else {
+ SM_ENTER(EAP, RETRANSMIT);
+ }
+ } else if (sm->eap_if.eapResp)
SM_ENTER(EAP, RECEIVED);
break;
case EAP_RETRANSMIT:
@@ -716,6 +1209,10 @@ SM_STEP(EAP)
sm->respVendor == EAP_VENDOR_IETF &&
sm->respVendorMethod == sm->currentMethod)))
SM_ENTER(EAP, INTEGRITY_CHECK);
+#ifdef CONFIG_ERP
+ else if (sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else {
wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
"rxResp=%d respId=%d currentId=%d "
@@ -804,9 +1301,22 @@ SM_STEP(EAP)
SM_ENTER(EAP, SUCCESS);
else if (sm->decision == DECISION_PASSTHROUGH)
SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
+ else if (sm->decision == DECISION_INITIATE_REAUTH_START)
+ SM_ENTER(EAP, INITIATE_REAUTH_START);
+#ifdef CONFIG_ERP
+ else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else
SM_ENTER(EAP, PROPOSE_METHOD);
break;
+ case EAP_INITIATE_REAUTH_START:
+ SM_ENTER(EAP, SEND_REQUEST);
+ break;
+ case EAP_INITIATE_RECEIVED:
+ if (!sm->eap_server)
+ SM_ENTER(EAP, SELECT_ACTION);
+ break;
case EAP_TIMEOUT_FAILURE:
break;
case EAP_FAILURE:
@@ -876,6 +1386,12 @@ static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
{
int rto, i;
+ if (sm->try_initiate_reauth) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
+ return 1;
+ }
+
if (methodTimeout) {
/*
* EAP method (either internal or through AAA server, provided
@@ -929,6 +1445,7 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
/* parse rxResp, respId, respMethod */
sm->rxResp = FALSE;
+ sm->rxInitiate = FALSE;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
sm->respVendor = EAP_VENDOR_IETF;
@@ -955,6 +1472,8 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
if (hdr->code == EAP_CODE_RESPONSE)
sm->rxResp = TRUE;
+ else if (hdr->code == EAP_CODE_INITIATE)
+ sm->rxInitiate = TRUE;
if (plen > sizeof(*hdr)) {
u8 *pos = (u8 *) (hdr + 1);
@@ -972,10 +1491,10 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
}
}
- wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
- "respMethod=%u respVendor=%u respVendorMethod=%u",
- sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
- sm->respVendorMethod);
+ wpa_printf(MSG_DEBUG,
+ "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
+ sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
+ sm->respVendor, sm->respVendorMethod);
}
@@ -1216,6 +1735,13 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
return DECISION_CONTINUE;
}
+ if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
+ !sm->initiate_reauth_start_sent) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
+ return DECISION_INITIATE_REAUTH_START;
+ }
+
if (sm->identity == NULL || sm->currentId == -1) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
"yet -> CONTINUE");
@@ -1326,6 +1852,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
sm->pbc_in_m1 = conf->pbc_in_m1;
sm->server_id = conf->server_id;
sm->server_id_len = conf->server_id_len;
+ sm->erp = conf->erp;
#ifdef CONFIG_TESTING_OPTIONS
sm->tls_test_flags = conf->tls_test_flags;
@@ -1353,6 +1880,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
sm->m->reset(sm, sm->eap_method_priv);
wpabuf_free(sm->eap_if.eapReqData);
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ os_free(sm->eap_if.eapSessionId);
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 09b976e6..db9b6aa2 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1294,6 +1294,28 @@ static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = data->eap_method;
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_aka_register(void)
{
struct eap_method *eap;
@@ -1313,6 +1335,7 @@ int eap_server_aka_register(void)
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
@@ -1342,6 +1365,7 @@ int eap_server_aka_prime_register(void)
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 2692bced..56ac7f43 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -186,7 +186,6 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
switch (*pos) {
case PAC_OPAQUE_TYPE_PAD:
- pos = end;
goto done;
case PAC_OPAQUE_TYPE_KEY:
if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
@@ -1017,7 +1016,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;
}
@@ -1590,6 +1589,18 @@ 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;
@@ -1609,6 +1620,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)
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index cb369e44..50f15c31 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -24,6 +24,8 @@ struct eap_gpsk_data {
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
#define MAX_NUM_CSUITES 2
@@ -417,6 +419,21 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
return;
}
+ if (eap_gpsk_derive_session_id(sm->user->password,
+ sm->user->password_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ sm->server_id, sm->server_id_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
if (end - pos < (int) miclen) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
@@ -593,6 +610,24 @@ static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_server_gpsk_register(void)
{
struct eap_method *eap;
@@ -612,6 +647,7 @@ int eap_server_gpsk_register(void)
eap->getKey = eap_gpsk_getKey;
eap->isSuccess = eap_gpsk_isSuccess;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 65b2ef69..16e62764 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -309,6 +309,12 @@ static int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
if (data->in_buf == NULL) {
/* First fragment of the message */
+ if (message_length > 50000) {
+ /* Limit maximum memory allocation */
+ wpa_printf(MSG_DEBUG,
+ "EAP-IKEV2: Ignore too long message");
+ return -1;
+ }
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -511,6 +517,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ikev2_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+ size_t offset;
+
+ if (data->state != DONE || !data->keymat_ok)
+ return NULL;
+
+ sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid) {
+ offset = 0;
+ sid[offset] = EAP_TYPE_IKEV2;
+ offset++;
+ os_memcpy(sid + offset, data->ikev2.i_nonce,
+ data->ikev2.i_nonce_len);
+ offset += data->ikev2.i_nonce_len;
+ os_memcpy(sid + offset, data->ikev2.r_nonce,
+ data->ikev2.r_nonce_len);
+ *len = sid_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+ sid, sid_len);
+ }
+
+ return sid;
+}
+
+
int eap_server_ikev2_register(void)
{
struct eap_method *eap;
@@ -531,6 +567,7 @@ int eap_server_ikev2_register(void)
eap->getKey = eap_ikev2_getKey;
eap->isSuccess = eap_ikev2_isSuccess;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index f7a753de..05848d2e 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -414,13 +414,16 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
}
pw_hash = pw_hash_buf;
}
- generate_authenticator_response_pwhash(
- pw_hash, peer_challenge, data->auth_challenge,
- username, username_len, nt_response,
- data->auth_response);
-
- hash_nt_password_hash(pw_hash, pw_hash_hash);
- get_master_key(pw_hash_hash, nt_response, data->master_key);
+ if (generate_authenticator_response_pwhash(
+ pw_hash, peer_challenge, data->auth_challenge,
+ username, username_len, nt_response,
+ data->auth_response) < 0 ||
+ hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 ||
+ get_master_key(pw_hash_hash, nt_response,
+ data->master_key)) {
+ data->state = FAILURE;
+ return;
+ }
data->master_key_valid = 1;
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
data->master_key, MSCHAPV2_KEY_LEN);
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index d9d4375a..0e6b4a06 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -36,6 +36,7 @@ struct eap_pax_data {
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
+ u8 mid[EAP_PAX_MID_LEN];
int keys_set;
char *cid;
size_t cid_len;
@@ -148,7 +149,6 @@ static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
(u8 *) data->cid, data->cid_len, NULL, 0, pos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
- pos += EAP_PAX_MAC_LEN;
/* Optional ADE could be added here, if needed */
@@ -388,7 +388,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
data->rand.e, data->mk, data->ck,
- data->ick) < 0) {
+ data->ick, data->mid) < 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
"key derivation");
data->state = FAILURE;
@@ -542,6 +542,26 @@ static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(1 + EAP_PAX_MID_LEN);
+ if (sid == NULL)
+ return NULL;
+
+ *len = 1 + EAP_PAX_MID_LEN;
+ sid[0] = EAP_TYPE_PAX;
+ os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+ return sid;
+}
+
+
int eap_server_pax_register(void)
{
struct eap_method *eap;
@@ -561,6 +581,7 @@ int eap_server_pax_register(void)
eap->getKey = eap_pax_getKey;
eap->isSuccess = eap_pax_isSuccess;
eap->get_emsk = eap_pax_get_emsk;
+ eap->getSessionId = eap_pax_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 594e02dd..98d608bf 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1229,6 +1229,18 @@ static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
+ len);
+}
+
+
int eap_server_peap_register(void)
{
struct eap_method *eap;
@@ -1247,6 +1259,7 @@ int eap_server_peap_register(void)
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
eap->isSuccess = eap_peap_isSuccess;
+ eap->getSessionId = eap_peap_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index db394e98..12b5d25d 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -485,6 +485,28 @@ static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_PSK_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_PSK;
+ os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_psk_register(void)
{
struct eap_method *eap;
@@ -504,6 +526,7 @@ int eap_server_psk_register(void)
eap->getKey = eap_psk_getKey;
eap->isSuccess = eap_psk_isSuccess;
eap->get_emsk = eap_psk_get_emsk;
+ eap->getSessionId = eap_psk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 7e1278dd..943af0d1 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -1020,6 +1020,25 @@ static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
}
+static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pwd_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ id = os_malloc(1 + SHA256_MAC_LEN);
+ if (id == NULL)
+ return NULL;
+
+ os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
+ *len = 1 + SHA256_MAC_LEN;
+
+ return id;
+}
+
+
int eap_server_pwd_register(void)
{
struct eap_method *eap;
@@ -1028,8 +1047,6 @@ int eap_server_pwd_register(void)
struct timezone tz;
u32 sr;
- EVP_add_digest(EVP_sha256());
-
sr = 0xdeaddada;
(void) gettimeofday(&tp, &tz);
sr ^= (tp.tv_sec ^ tp.tv_usec);
@@ -1050,6 +1067,7 @@ int eap_server_pwd_register(void)
eap->getKey = eap_pwd_getkey;
eap->get_emsk = eap_pwd_get_emsk;
eap->isSuccess = eap_pwd_is_success;
+ eap->getSessionId = eap_pwd_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 1937621c..de707773 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -495,6 +495,28 @@ static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SAKE;
+ os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sake_register(void)
{
struct eap_method *eap;
@@ -514,6 +536,7 @@ int eap_server_sake_register(void)
eap->getKey = eap_sake_getKey;
eap->isSuccess = eap_sake_isSuccess;
eap->get_emsk = eap_sake_get_emsk;
+ eap->getSessionId = eap_sake_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 23ee2b60..ddfb71cf 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -820,6 +820,29 @@ static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SIM;
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sim_register(void)
{
struct eap_method *eap;
@@ -839,6 +862,7 @@ int eap_server_sim_register(void)
eap->getKey = eap_sim_getKey;
eap->isSuccess = eap_sim_isSuccess;
eap->get_emsk = eap_sim_get_emsk;
+ eap->getSessionId = eap_sim_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 6bed62f8..58cfe8ac 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -287,7 +287,7 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (emsk)
os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
EAP_EMSK_LEN);
- os_free(eapKeyData);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
} else
emsk = NULL;
@@ -310,6 +310,18 @@ static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
+ len);
+}
+
+
int eap_server_tls_register(void)
{
struct eap_method *eap;
@@ -329,6 +341,7 @@ int eap_server_tls_register(void)
eap->getKey = eap_tls_getKey;
eap->isSuccess = eap_tls_isSuccess;
eap->get_emsk = eap_tls_get_emsk;
+ eap->getSessionId = eap_tls_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 01853e68..56916c45 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -140,6 +140,47 @@ fail:
}
+/**
+ * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_keys keys;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+
+ if (keys.client_random == NULL || keys.server_random == NULL)
+ return NULL;
+
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
+
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
+}
+
+
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id)
{
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 31e3871d..12a31b07 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -409,7 +409,7 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
*pos++ = data->mschapv2_ident;
ret = os_snprintf((char *) pos, end - pos, "S=");
- if (ret >= 0 && ret < end - pos)
+ if (!os_snprintf_error(end - pos, ret))
pos += ret;
pos += wpa_snprintf_hex_uppercase(
(char *) pos, end - pos, data->mschapv2_auth_response,
@@ -1181,6 +1181,50 @@ static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TTLS,
+ len);
+}
+
+
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_malloc(EAP_EMSK_LEN);
+ if (emsk)
+ os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ } else
+ emsk = NULL;
+
+ if (emsk) {
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive EMSK");
+ }
+
+ return emsk;
+}
+
+
int eap_server_ttls_register(void)
{
struct eap_method *eap;
@@ -1199,6 +1243,8 @@ int eap_server_ttls_register(void)
eap->isDone = eap_ttls_isDone;
eap->getKey = eap_ttls_getKey;
eap->isSuccess = eap_ttls_isSuccess;
+ eap->getSessionId = eap_ttls_get_session_id;
+ eap->get_emsk = eap_ttls_get_emsk;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 97ec0c0e..9d9c28d7 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -380,7 +380,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE16(pos);
pos += 2;
- if (message_length < end - pos) {
+ if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
return;
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index bc2cbe5b..acf54353 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -573,16 +573,14 @@ static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
char buf[1000], *pos, *cmd, *imsi;
int res;
- res = recv(sock, buf, sizeof(buf), 0);
+ res = recv(sock, buf, sizeof(buf) - 1, 0);
if (res < 0)
return;
+ buf[res] = '\0';
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
"external source", (u8 *) buf, res);
if (res == 0)
return;
- if (res >= (int) sizeof(buf))
- res = sizeof(buf) - 1;
- buf[res] = '\0';
if (data->get_complete_cb == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
@@ -924,12 +922,13 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return EAP_SIM_DB_FAILURE;
len += ret;
@@ -966,7 +965,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
pos = id;
end = id + sizeof(buf) * 2 + 2;
*pos++ = prefix;
- pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+ wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
return id;
}
@@ -1387,7 +1386,8 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
@@ -1451,19 +1451,20 @@ int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return -1;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
auts, EAP_AKA_AUTS_LEN);
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 91449afd..ddf90b85 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -74,6 +74,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id);
struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);