From 6c0da2bb83f6915d8260912362692d1a742e057b Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 5 Jan 2015 13:08:17 -0800 Subject: Cumulative patch from commit 8b48e3200680f71ae083b84793e6bdc2099416d2 [DO NOT MERGE] 8b48e32 wpa_cli: Add MAC address randomization in scan fb37588 ctrl_iface: Add MAC address randomization in scan processing 56c76fa scan: Add MAC address randomization in scan handling 86056fe nl80211: Handle MAC address randomization in scan/sched_scan ff23ed2 driver: Add definitions for MAC address randomization in scan 7db53bb wpa_cli: Implement TDLS start/cancel channel switching commands 72b2605 nl80211: Pass TDLS channel-switch start/stop params to kernel 6b90dea TDLS: Propagate enable/disable channel-switch commands to driver d9d3b78 TDLS: Track TDLS channel switch prohibition in BSS 4daa572 TDLS: Add channel-switch capability flag ca16586 Sync with wireless-testing.git include/uapi/linux/nl80211.h 8c42b36 WMM AC: Reconfigure tspecs on reassociation to the same BSS 677e7a9 WMM AC: Do not fail on unknown IEs in Association Response fecc2bb WMM AC: Delete tspecs on roaming 20fe745 WMM AC: Print user-priority in wmm_ac_status 730a0d1 nl80211: Always register management frames handler ... 209702d Add possibility to set the setband parameter ee82e33 Do not trigger the scan during initialization on Android platforms e69ae5f Reject new SCAN commands if there is a pending request ... 59d7148 nl80211: Provide subtype and reason code for AP SME drivers 9d4ff04 Add external EAPOL transmission option for testing purposes 61fc904 P2P: Handle improper WPS termination on GO during group formation 58b40fd P2P: Clear p2p_go_group_formation_completed on GO start c155305 Complete sme-connect radio work when clearing connection state debb2da P2P: Report group removal reason PSK_FAILURE in timeout case 51465a0 The master branch is now used for v2.4 development Change-Id: I9b9cfa5c5cd4d26b2f3f5595f7c226ac60de6258 --- src/eap_server/eap.h | 22 +- src/eap_server/eap_i.h | 23 +- src/eap_server/eap_server.c | 544 ++++++++++++++++++++++++++++++++- src/eap_server/eap_server_aka.c | 24 ++ src/eap_server/eap_server_fast.c | 16 +- src/eap_server/eap_server_gpsk.c | 36 +++ src/eap_server/eap_server_ikev2.c | 37 +++ src/eap_server/eap_server_mschapv2.c | 17 +- src/eap_server/eap_server_pax.c | 25 +- src/eap_server/eap_server_peap.c | 13 + src/eap_server/eap_server_psk.c | 23 ++ src/eap_server/eap_server_pwd.c | 22 +- src/eap_server/eap_server_sake.c | 23 ++ src/eap_server/eap_server_sim.c | 24 ++ src/eap_server/eap_server_tls.c | 15 +- src/eap_server/eap_server_tls_common.c | 41 +++ src/eap_server/eap_server_ttls.c | 48 ++- src/eap_server/eap_server_wsc.c | 2 +- src/eap_server/eap_sim_db.c | 23 +- src/eap_server/eap_tls_common.h | 3 + 20 files changed, 943 insertions(+), 38 deletions(-) (limited to 'src/eap_server') 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 + * Copyright (c) 2004-2014, Jouni Malinen * * 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 + * Copyright (c) 2004-2014, Jouni Malinen * * 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); -- cgit v1.2.3