18dbcf02cSchristos /* 28dbcf02cSchristos * hostapd / EAP Full Authenticator state machine (RFC 4137) 3bb610346Schristos * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 5e604d861Schristos * This software may be distributed under the terms of the BSD license. 6e604d861Schristos * See README for more details. 78dbcf02cSchristos * 88dbcf02cSchristos * This state machine is based on the full authenticator state machine defined 98dbcf02cSchristos * in RFC 4137. However, to support backend authentication in RADIUS 108dbcf02cSchristos * authentication server functionality, parts of backend authenticator (also 118dbcf02cSchristos * from RFC 4137) are mixed in. This functionality is enabled by setting 12*45d3cc13Schristos * backend_auth configuration variable to true. 138dbcf02cSchristos */ 148dbcf02cSchristos 158dbcf02cSchristos #include "includes.h" 168dbcf02cSchristos 178dbcf02cSchristos #include "common.h" 18bb610346Schristos #include "crypto/sha256.h" 198dbcf02cSchristos #include "eap_i.h" 208dbcf02cSchristos #include "state_machine.h" 218dbcf02cSchristos #include "common/wpa_ctrl.h" 228dbcf02cSchristos 238dbcf02cSchristos #define STATE_MACHINE_DATA struct eap_sm 248dbcf02cSchristos #define STATE_MACHINE_DEBUG_PREFIX "EAP" 258dbcf02cSchristos 268dbcf02cSchristos /* EAP state machines are described in RFC 4137 */ 278dbcf02cSchristos 288dbcf02cSchristos static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 298dbcf02cSchristos int eapSRTT, int eapRTTVAR, 308dbcf02cSchristos int methodTimeout); 318dbcf02cSchristos static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); 328dbcf02cSchristos static int eap_sm_getId(const struct wpabuf *data); 338dbcf02cSchristos static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); 348dbcf02cSchristos static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); 358dbcf02cSchristos static int eap_sm_nextId(struct eap_sm *sm, int id); 368dbcf02cSchristos static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 378dbcf02cSchristos size_t len); 38*45d3cc13Schristos static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, 39*45d3cc13Schristos int *vendor); 408dbcf02cSchristos static int eap_sm_Policy_getDecision(struct eap_sm *sm); 41*45d3cc13Schristos static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method); 428dbcf02cSchristos 438dbcf02cSchristos 44bb610346Schristos static int eap_get_erp_send_reauth_start(struct eap_sm *sm) 45bb610346Schristos { 46bb610346Schristos if (sm->eapol_cb->get_erp_send_reauth_start) 47bb610346Schristos return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx); 48bb610346Schristos return 0; 49bb610346Schristos } 50bb610346Schristos 51bb610346Schristos 52bb610346Schristos static const char * eap_get_erp_domain(struct eap_sm *sm) 53bb610346Schristos { 54bb610346Schristos if (sm->eapol_cb->get_erp_domain) 55bb610346Schristos return sm->eapol_cb->get_erp_domain(sm->eapol_ctx); 56bb610346Schristos return NULL; 57bb610346Schristos } 58bb610346Schristos 59bb610346Schristos 60bb610346Schristos #ifdef CONFIG_ERP 61bb610346Schristos 62bb610346Schristos static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm, 63bb610346Schristos const char *keyname) 64bb610346Schristos { 65bb610346Schristos if (sm->eapol_cb->erp_get_key) 66bb610346Schristos return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname); 67bb610346Schristos return NULL; 68bb610346Schristos } 69bb610346Schristos 70bb610346Schristos 71bb610346Schristos static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp) 72bb610346Schristos { 73bb610346Schristos if (sm->eapol_cb->erp_add_key) 74bb610346Schristos return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp); 75bb610346Schristos return -1; 76bb610346Schristos } 77bb610346Schristos 78bb610346Schristos #endif /* CONFIG_ERP */ 79bb610346Schristos 80bb610346Schristos 81bb610346Schristos static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm, 82bb610346Schristos u8 id) 83bb610346Schristos { 84bb610346Schristos const char *domain; 85bb610346Schristos size_t plen = 1; 86bb610346Schristos struct wpabuf *msg; 87bb610346Schristos size_t domain_len = 0; 88bb610346Schristos 89bb610346Schristos domain = eap_get_erp_domain(sm); 90bb610346Schristos if (domain) { 91bb610346Schristos domain_len = os_strlen(domain); 92bb610346Schristos plen += 2 + domain_len; 93bb610346Schristos } 94bb610346Schristos 95ecc36642Schristos msg = eap_msg_alloc(EAP_VENDOR_IETF, 96*45d3cc13Schristos (enum eap_type) EAP_ERP_TYPE_REAUTH_START, plen, 97bb610346Schristos EAP_CODE_INITIATE, id); 98bb610346Schristos if (msg == NULL) 99bb610346Schristos return NULL; 100bb610346Schristos wpabuf_put_u8(msg, 0); /* Reserved */ 101bb610346Schristos if (domain) { 102bb610346Schristos /* Domain name TLV */ 103bb610346Schristos wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME); 104bb610346Schristos wpabuf_put_u8(msg, domain_len); 105bb610346Schristos wpabuf_put_data(msg, domain, domain_len); 106bb610346Schristos } 107bb610346Schristos 108bb610346Schristos return msg; 109bb610346Schristos } 110bb610346Schristos 111bb610346Schristos 1128dbcf02cSchristos static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) 1138dbcf02cSchristos { 1148dbcf02cSchristos if (src == NULL) 1158dbcf02cSchristos return -1; 1168dbcf02cSchristos 1178dbcf02cSchristos wpabuf_free(*dst); 1188dbcf02cSchristos *dst = wpabuf_dup(src); 1198dbcf02cSchristos return *dst ? 0 : -1; 1208dbcf02cSchristos } 1218dbcf02cSchristos 1228dbcf02cSchristos 1238dbcf02cSchristos static int eap_copy_data(u8 **dst, size_t *dst_len, 1248dbcf02cSchristos const u8 *src, size_t src_len) 1258dbcf02cSchristos { 1268dbcf02cSchristos if (src == NULL) 1278dbcf02cSchristos return -1; 1288dbcf02cSchristos 1298dbcf02cSchristos os_free(*dst); 1308dbcf02cSchristos *dst = os_malloc(src_len); 1318dbcf02cSchristos if (*dst) { 1328dbcf02cSchristos os_memcpy(*dst, src, src_len); 1338dbcf02cSchristos *dst_len = src_len; 1348dbcf02cSchristos return 0; 1358dbcf02cSchristos } else { 1368dbcf02cSchristos *dst_len = 0; 1378dbcf02cSchristos return -1; 1388dbcf02cSchristos } 1398dbcf02cSchristos } 1408dbcf02cSchristos 1418dbcf02cSchristos #define EAP_COPY(dst, src) \ 1428dbcf02cSchristos eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) 1438dbcf02cSchristos 1448dbcf02cSchristos 1458dbcf02cSchristos /** 1468dbcf02cSchristos * eap_user_get - Fetch user information from the database 1478dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1488dbcf02cSchristos * @identity: Identity (User-Name) of the user 1498dbcf02cSchristos * @identity_len: Length of identity in bytes 1508dbcf02cSchristos * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user 1518dbcf02cSchristos * Returns: 0 on success, or -1 on failure 1528dbcf02cSchristos * 1538dbcf02cSchristos * This function is used to fetch user information for EAP. The user will be 1548dbcf02cSchristos * selected based on the specified identity. sm->user and 1558dbcf02cSchristos * sm->user_eap_method_index are updated for the new user when a matching user 1568dbcf02cSchristos * is found. sm->user can be used to get user information (e.g., password). 1578dbcf02cSchristos */ 1588dbcf02cSchristos int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, 1598dbcf02cSchristos int phase2) 1608dbcf02cSchristos { 1618dbcf02cSchristos struct eap_user *user; 1628dbcf02cSchristos 1638dbcf02cSchristos if (sm == NULL || sm->eapol_cb == NULL || 1648dbcf02cSchristos sm->eapol_cb->get_eap_user == NULL) 1658dbcf02cSchristos return -1; 1668dbcf02cSchristos 1678dbcf02cSchristos eap_user_free(sm->user); 1688dbcf02cSchristos sm->user = NULL; 1698dbcf02cSchristos 1708dbcf02cSchristos user = os_zalloc(sizeof(*user)); 1718dbcf02cSchristos if (user == NULL) 1728dbcf02cSchristos return -1; 1738dbcf02cSchristos 1748dbcf02cSchristos if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, 1758dbcf02cSchristos identity_len, phase2, user) != 0) { 1768dbcf02cSchristos eap_user_free(user); 1778dbcf02cSchristos return -1; 1788dbcf02cSchristos } 1798dbcf02cSchristos 1808dbcf02cSchristos sm->user = user; 1818dbcf02cSchristos sm->user_eap_method_index = 0; 1828dbcf02cSchristos 1838dbcf02cSchristos return 0; 1848dbcf02cSchristos } 1858dbcf02cSchristos 1868dbcf02cSchristos 1873c260e60Schristos void eap_log_msg(struct eap_sm *sm, const char *fmt, ...) 1883c260e60Schristos { 1893c260e60Schristos va_list ap; 1903c260e60Schristos char *buf; 1913c260e60Schristos int buflen; 1923c260e60Schristos 1933c260e60Schristos if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL) 1943c260e60Schristos return; 1953c260e60Schristos 1963c260e60Schristos va_start(ap, fmt); 1973c260e60Schristos buflen = vsnprintf(NULL, 0, fmt, ap) + 1; 1983c260e60Schristos va_end(ap); 1993c260e60Schristos 2003c260e60Schristos buf = os_malloc(buflen); 2013c260e60Schristos if (buf == NULL) 2023c260e60Schristos return; 2033c260e60Schristos va_start(ap, fmt); 2043c260e60Schristos vsnprintf(buf, buflen, fmt, ap); 2053c260e60Schristos va_end(ap); 2063c260e60Schristos 2073c260e60Schristos sm->eapol_cb->log_msg(sm->eapol_ctx, buf); 2083c260e60Schristos 2093c260e60Schristos os_free(buf); 2103c260e60Schristos } 2113c260e60Schristos 2123c260e60Schristos 2138dbcf02cSchristos SM_STATE(EAP, DISABLED) 2148dbcf02cSchristos { 2158dbcf02cSchristos SM_ENTRY(EAP, DISABLED); 2168dbcf02cSchristos sm->num_rounds = 0; 217*45d3cc13Schristos sm->num_rounds_short = 0; 2188dbcf02cSchristos } 2198dbcf02cSchristos 2208dbcf02cSchristos 2218dbcf02cSchristos SM_STATE(EAP, INITIALIZE) 2228dbcf02cSchristos { 2238dbcf02cSchristos SM_ENTRY(EAP, INITIALIZE); 2248dbcf02cSchristos 225*45d3cc13Schristos if (sm->eap_if.eapRestart && !sm->cfg->eap_server && sm->identity) { 226111b9fd8Schristos /* 227111b9fd8Schristos * Need to allow internal Identity method to be used instead 228111b9fd8Schristos * of passthrough at the beginning of reauthentication. 229111b9fd8Schristos */ 230111b9fd8Schristos eap_server_clear_identity(sm); 231111b9fd8Schristos } 232111b9fd8Schristos 233*45d3cc13Schristos sm->try_initiate_reauth = false; 2348dbcf02cSchristos sm->currentId = -1; 235*45d3cc13Schristos sm->eap_if.eapSuccess = false; 236*45d3cc13Schristos sm->eap_if.eapFail = false; 237*45d3cc13Schristos sm->eap_if.eapTimeout = false; 2383c260e60Schristos bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 2398dbcf02cSchristos sm->eap_if.eapKeyData = NULL; 2408dbcf02cSchristos sm->eap_if.eapKeyDataLen = 0; 241bb610346Schristos os_free(sm->eap_if.eapSessionId); 242bb610346Schristos sm->eap_if.eapSessionId = NULL; 243bb610346Schristos sm->eap_if.eapSessionIdLen = 0; 244*45d3cc13Schristos sm->eap_if.eapKeyAvailable = false; 245*45d3cc13Schristos sm->eap_if.eapRestart = false; 2468dbcf02cSchristos 2478dbcf02cSchristos /* 2488dbcf02cSchristos * This is not defined in RFC 4137, but method state needs to be 2498dbcf02cSchristos * reseted here so that it does not remain in success state when 2508dbcf02cSchristos * re-authentication starts. 2518dbcf02cSchristos */ 2528dbcf02cSchristos if (sm->m && sm->eap_method_priv) { 2538dbcf02cSchristos sm->m->reset(sm, sm->eap_method_priv); 2548dbcf02cSchristos sm->eap_method_priv = NULL; 2558dbcf02cSchristos } 2568dbcf02cSchristos sm->m = NULL; 2578dbcf02cSchristos sm->user_eap_method_index = 0; 2588dbcf02cSchristos 259*45d3cc13Schristos if (sm->cfg->backend_auth) { 2608dbcf02cSchristos sm->currentMethod = EAP_TYPE_NONE; 2618dbcf02cSchristos /* parse rxResp, respId, respMethod */ 2628dbcf02cSchristos eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 2638dbcf02cSchristos if (sm->rxResp) { 2648dbcf02cSchristos sm->currentId = sm->respId; 2658dbcf02cSchristos } 2668dbcf02cSchristos } 2678dbcf02cSchristos sm->num_rounds = 0; 268*45d3cc13Schristos sm->num_rounds_short = 0; 2698dbcf02cSchristos sm->method_pending = METHOD_PENDING_NONE; 2708dbcf02cSchristos 271*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED 2728dbcf02cSchristos MACSTR, MAC2STR(sm->peer_addr)); 2738dbcf02cSchristos } 2748dbcf02cSchristos 2758dbcf02cSchristos 2768dbcf02cSchristos SM_STATE(EAP, PICK_UP_METHOD) 2778dbcf02cSchristos { 2788dbcf02cSchristos SM_ENTRY(EAP, PICK_UP_METHOD); 2798dbcf02cSchristos 2808dbcf02cSchristos if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { 2818dbcf02cSchristos sm->currentMethod = sm->respMethod; 2828dbcf02cSchristos if (sm->m && sm->eap_method_priv) { 2838dbcf02cSchristos sm->m->reset(sm, sm->eap_method_priv); 2848dbcf02cSchristos sm->eap_method_priv = NULL; 2858dbcf02cSchristos } 2868dbcf02cSchristos sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, 2878dbcf02cSchristos sm->currentMethod); 2888dbcf02cSchristos if (sm->m && sm->m->initPickUp) { 2898dbcf02cSchristos sm->eap_method_priv = sm->m->initPickUp(sm); 2908dbcf02cSchristos if (sm->eap_method_priv == NULL) { 2918dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Failed to " 2928dbcf02cSchristos "initialize EAP method %d", 2938dbcf02cSchristos sm->currentMethod); 2948dbcf02cSchristos sm->m = NULL; 2958dbcf02cSchristos sm->currentMethod = EAP_TYPE_NONE; 2968dbcf02cSchristos } 2978dbcf02cSchristos } else { 2988dbcf02cSchristos sm->m = NULL; 2998dbcf02cSchristos sm->currentMethod = EAP_TYPE_NONE; 3008dbcf02cSchristos } 3018dbcf02cSchristos } 3028dbcf02cSchristos 303*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 3048dbcf02cSchristos "method=%u", sm->currentMethod); 3058dbcf02cSchristos } 3068dbcf02cSchristos 3078dbcf02cSchristos 3088dbcf02cSchristos SM_STATE(EAP, IDLE) 3098dbcf02cSchristos { 3108dbcf02cSchristos SM_ENTRY(EAP, IDLE); 3118dbcf02cSchristos 3128dbcf02cSchristos sm->eap_if.retransWhile = eap_sm_calculateTimeout( 3138dbcf02cSchristos sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 3148dbcf02cSchristos sm->methodTimeout); 3158dbcf02cSchristos } 3168dbcf02cSchristos 3178dbcf02cSchristos 3188dbcf02cSchristos SM_STATE(EAP, RETRANSMIT) 3198dbcf02cSchristos { 3208dbcf02cSchristos SM_ENTRY(EAP, RETRANSMIT); 3218dbcf02cSchristos 3228dbcf02cSchristos sm->retransCount++; 3238dbcf02cSchristos if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 3248dbcf02cSchristos if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 325*45d3cc13Schristos sm->eap_if.eapReq = true; 3268dbcf02cSchristos } 327be6b3c4dSchristos 328*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR, 329be6b3c4dSchristos MAC2STR(sm->peer_addr)); 3308dbcf02cSchristos } 3318dbcf02cSchristos 3328dbcf02cSchristos 3338dbcf02cSchristos SM_STATE(EAP, RECEIVED) 3348dbcf02cSchristos { 3358dbcf02cSchristos SM_ENTRY(EAP, RECEIVED); 3368dbcf02cSchristos 3378dbcf02cSchristos /* parse rxResp, respId, respMethod */ 3388dbcf02cSchristos eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 3398dbcf02cSchristos sm->num_rounds++; 340*45d3cc13Schristos if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20) 341*45d3cc13Schristos sm->num_rounds_short++; 342*45d3cc13Schristos else 343*45d3cc13Schristos sm->num_rounds_short = 0; 3448dbcf02cSchristos } 3458dbcf02cSchristos 3468dbcf02cSchristos 3478dbcf02cSchristos SM_STATE(EAP, DISCARD) 3488dbcf02cSchristos { 3498dbcf02cSchristos SM_ENTRY(EAP, DISCARD); 350*45d3cc13Schristos sm->eap_if.eapResp = false; 351*45d3cc13Schristos sm->eap_if.eapNoReq = true; 3528dbcf02cSchristos } 3538dbcf02cSchristos 3548dbcf02cSchristos 3558dbcf02cSchristos SM_STATE(EAP, SEND_REQUEST) 3568dbcf02cSchristos { 3578dbcf02cSchristos SM_ENTRY(EAP, SEND_REQUEST); 3588dbcf02cSchristos 3598dbcf02cSchristos sm->retransCount = 0; 3608dbcf02cSchristos if (sm->eap_if.eapReqData) { 361*45d3cc13Schristos if (wpabuf_len(sm->eap_if.eapReqData) >= 20) 362*45d3cc13Schristos sm->num_rounds_short = 0; 3638dbcf02cSchristos if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 3648dbcf02cSchristos { 365*45d3cc13Schristos sm->eap_if.eapResp = false; 366*45d3cc13Schristos sm->eap_if.eapReq = true; 3678dbcf02cSchristos } else { 368*45d3cc13Schristos sm->eap_if.eapResp = false; 369*45d3cc13Schristos sm->eap_if.eapReq = false; 3708dbcf02cSchristos } 3718dbcf02cSchristos } else { 3728dbcf02cSchristos wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); 373*45d3cc13Schristos sm->eap_if.eapResp = false; 374*45d3cc13Schristos sm->eap_if.eapReq = false; 375*45d3cc13Schristos sm->eap_if.eapNoReq = true; 3768dbcf02cSchristos } 3778dbcf02cSchristos } 3788dbcf02cSchristos 3798dbcf02cSchristos 3808dbcf02cSchristos SM_STATE(EAP, INTEGRITY_CHECK) 3818dbcf02cSchristos { 3828dbcf02cSchristos SM_ENTRY(EAP, INTEGRITY_CHECK); 3838dbcf02cSchristos 384e604d861Schristos if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) { 385*45d3cc13Schristos sm->ignore = true; 386e604d861Schristos return; 387e604d861Schristos } 388e604d861Schristos 3898dbcf02cSchristos if (sm->m->check) { 3908dbcf02cSchristos sm->ignore = sm->m->check(sm, sm->eap_method_priv, 3918dbcf02cSchristos sm->eap_if.eapRespData); 3928dbcf02cSchristos } 3938dbcf02cSchristos } 3948dbcf02cSchristos 3958dbcf02cSchristos 3968dbcf02cSchristos SM_STATE(EAP, METHOD_REQUEST) 3978dbcf02cSchristos { 3988dbcf02cSchristos SM_ENTRY(EAP, METHOD_REQUEST); 3998dbcf02cSchristos 4008dbcf02cSchristos if (sm->m == NULL) { 4018dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: method not initialized"); 4028dbcf02cSchristos return; 4038dbcf02cSchristos } 4048dbcf02cSchristos 4058dbcf02cSchristos sm->currentId = eap_sm_nextId(sm, sm->currentId); 4068dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", 4078dbcf02cSchristos sm->currentId); 4088dbcf02cSchristos sm->lastId = sm->currentId; 4098dbcf02cSchristos wpabuf_free(sm->eap_if.eapReqData); 4108dbcf02cSchristos sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, 4118dbcf02cSchristos sm->currentId); 4128dbcf02cSchristos if (sm->m->getTimeout) 4138dbcf02cSchristos sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); 4148dbcf02cSchristos else 4158dbcf02cSchristos sm->methodTimeout = 0; 4168dbcf02cSchristos } 4178dbcf02cSchristos 4188dbcf02cSchristos 419bb610346Schristos static void eap_server_erp_init(struct eap_sm *sm) 420bb610346Schristos { 421bb610346Schristos #ifdef CONFIG_ERP 422bb610346Schristos u8 *emsk = NULL; 423bb610346Schristos size_t emsk_len = 0; 424bb610346Schristos u8 EMSKname[EAP_EMSK_NAME_LEN]; 425be6b3c4dSchristos u8 len[2], ctx[3]; 426bb610346Schristos const char *domain; 427bb610346Schristos size_t domain_len, nai_buf_len; 428bb610346Schristos struct eap_server_erp_key *erp = NULL; 429bb610346Schristos int pos; 430bb610346Schristos 431bb610346Schristos domain = eap_get_erp_domain(sm); 432bb610346Schristos if (!domain) 433bb610346Schristos return; 434bb610346Schristos 435bb610346Schristos domain_len = os_strlen(domain); 436bb610346Schristos 437bb610346Schristos nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len; 438bb610346Schristos if (nai_buf_len > 253) { 439bb610346Schristos /* 440bb610346Schristos * keyName-NAI has a maximum length of 253 octet to fit in 441bb610346Schristos * RADIUS attributes. 442bb610346Schristos */ 443bb610346Schristos wpa_printf(MSG_DEBUG, 444bb610346Schristos "EAP: Too long realm for ERP keyName-NAI maximum length"); 445bb610346Schristos return; 446bb610346Schristos } 447bb610346Schristos nai_buf_len++; /* null termination */ 448bb610346Schristos erp = os_zalloc(sizeof(*erp) + nai_buf_len); 449bb610346Schristos if (erp == NULL) 450bb610346Schristos goto fail; 451bb610346Schristos erp->recv_seq = (u32) -1; 452bb610346Schristos 453bb610346Schristos emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len); 454bb610346Schristos if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) { 455bb610346Schristos wpa_printf(MSG_DEBUG, 456bb610346Schristos "EAP: No suitable EMSK available for ERP"); 457bb610346Schristos goto fail; 458bb610346Schristos } 459bb610346Schristos 460bb610346Schristos wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len); 461bb610346Schristos 462be6b3c4dSchristos WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN); 463bb610346Schristos if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen, 464bb610346Schristos "EMSK", len, sizeof(len), 465bb610346Schristos EMSKname, EAP_EMSK_NAME_LEN) < 0) { 466bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname"); 467bb610346Schristos goto fail; 468bb610346Schristos } 469bb610346Schristos wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN); 470bb610346Schristos 471bb610346Schristos pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len, 472bb610346Schristos EMSKname, EAP_EMSK_NAME_LEN); 473bb610346Schristos erp->keyname_nai[pos] = '@'; 474bb610346Schristos os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len); 475bb610346Schristos 476bb610346Schristos WPA_PUT_BE16(len, emsk_len); 477bb610346Schristos if (hmac_sha256_kdf(emsk, emsk_len, 478bb610346Schristos "EAP Re-authentication Root Key@ietf.org", 479bb610346Schristos len, sizeof(len), erp->rRK, emsk_len) < 0) { 480bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP"); 481bb610346Schristos goto fail; 482bb610346Schristos } 483bb610346Schristos erp->rRK_len = emsk_len; 484bb610346Schristos wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len); 485bb610346Schristos 486be6b3c4dSchristos ctx[0] = EAP_ERP_CS_HMAC_SHA256_128; 487be6b3c4dSchristos WPA_PUT_BE16(&ctx[1], erp->rRK_len); 488bb610346Schristos if (hmac_sha256_kdf(erp->rRK, erp->rRK_len, 489be6b3c4dSchristos "Re-authentication Integrity Key@ietf.org", 490be6b3c4dSchristos ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) { 491bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP"); 492bb610346Schristos goto fail; 493bb610346Schristos } 494bb610346Schristos erp->rIK_len = erp->rRK_len; 495bb610346Schristos wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len); 496bb610346Schristos 497bb610346Schristos if (eap_erp_add_key(sm, erp) == 0) { 498bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", 499bb610346Schristos erp->keyname_nai); 500bb610346Schristos erp = NULL; 501bb610346Schristos } 502bb610346Schristos 503bb610346Schristos fail: 504bb610346Schristos bin_clear_free(emsk, emsk_len); 505bb610346Schristos bin_clear_free(erp, sizeof(*erp)); 506bb610346Schristos #endif /* CONFIG_ERP */ 507bb610346Schristos } 508bb610346Schristos 509bb610346Schristos 5108dbcf02cSchristos SM_STATE(EAP, METHOD_RESPONSE) 5118dbcf02cSchristos { 5128dbcf02cSchristos SM_ENTRY(EAP, METHOD_RESPONSE); 5138dbcf02cSchristos 514e604d861Schristos if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) 515e604d861Schristos return; 516e604d861Schristos 5178dbcf02cSchristos sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); 5188dbcf02cSchristos if (sm->m->isDone(sm, sm->eap_method_priv)) { 5198dbcf02cSchristos eap_sm_Policy_update(sm, NULL, 0); 5203c260e60Schristos bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 5218dbcf02cSchristos if (sm->m->getKey) { 5228dbcf02cSchristos sm->eap_if.eapKeyData = sm->m->getKey( 5238dbcf02cSchristos sm, sm->eap_method_priv, 5248dbcf02cSchristos &sm->eap_if.eapKeyDataLen); 5258dbcf02cSchristos } else { 5268dbcf02cSchristos sm->eap_if.eapKeyData = NULL; 5278dbcf02cSchristos sm->eap_if.eapKeyDataLen = 0; 5288dbcf02cSchristos } 529bb610346Schristos os_free(sm->eap_if.eapSessionId); 530bb610346Schristos sm->eap_if.eapSessionId = NULL; 531bb610346Schristos if (sm->m->getSessionId) { 532bb610346Schristos sm->eap_if.eapSessionId = sm->m->getSessionId( 533bb610346Schristos sm, sm->eap_method_priv, 534bb610346Schristos &sm->eap_if.eapSessionIdLen); 535bb610346Schristos wpa_hexdump(MSG_DEBUG, "EAP: Session-Id", 536bb610346Schristos sm->eap_if.eapSessionId, 537bb610346Schristos sm->eap_if.eapSessionIdLen); 538bb610346Schristos } 539*45d3cc13Schristos if (sm->cfg->erp && sm->m->get_emsk && sm->eap_if.eapSessionId) 540bb610346Schristos eap_server_erp_init(sm); 5418dbcf02cSchristos sm->methodState = METHOD_END; 5428dbcf02cSchristos } else { 5438dbcf02cSchristos sm->methodState = METHOD_CONTINUE; 5448dbcf02cSchristos } 5458dbcf02cSchristos } 5468dbcf02cSchristos 5478dbcf02cSchristos 5488dbcf02cSchristos SM_STATE(EAP, PROPOSE_METHOD) 5498dbcf02cSchristos { 5508dbcf02cSchristos int vendor; 551*45d3cc13Schristos enum eap_type type; 5528dbcf02cSchristos 5538dbcf02cSchristos SM_ENTRY(EAP, PROPOSE_METHOD); 5548dbcf02cSchristos 555*45d3cc13Schristos sm->try_initiate_reauth = false; 5563c260e60Schristos try_another_method: 5578dbcf02cSchristos type = eap_sm_Policy_getNextMethod(sm, &vendor); 5588dbcf02cSchristos if (vendor == EAP_VENDOR_IETF) 5598dbcf02cSchristos sm->currentMethod = type; 5608dbcf02cSchristos else 5618dbcf02cSchristos sm->currentMethod = EAP_TYPE_EXPANDED; 5628dbcf02cSchristos if (sm->m && sm->eap_method_priv) { 5638dbcf02cSchristos sm->m->reset(sm, sm->eap_method_priv); 5648dbcf02cSchristos sm->eap_method_priv = NULL; 5658dbcf02cSchristos } 5668dbcf02cSchristos sm->m = eap_server_get_eap_method(vendor, type); 5678dbcf02cSchristos if (sm->m) { 5688dbcf02cSchristos sm->eap_method_priv = sm->m->init(sm); 5698dbcf02cSchristos if (sm->eap_method_priv == NULL) { 5708dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " 5718dbcf02cSchristos "method %d", sm->currentMethod); 5728dbcf02cSchristos sm->m = NULL; 5738dbcf02cSchristos sm->currentMethod = EAP_TYPE_NONE; 5743c260e60Schristos goto try_another_method; 5758dbcf02cSchristos } 5768dbcf02cSchristos } 5773c260e60Schristos if (sm->m == NULL) { 5783c260e60Schristos wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method"); 5793c260e60Schristos eap_log_msg(sm, "Could not find suitable EAP method"); 5803c260e60Schristos sm->decision = DECISION_FAILURE; 5813c260e60Schristos return; 5823c260e60Schristos } 5838dbcf02cSchristos if (sm->currentMethod == EAP_TYPE_IDENTITY || 5848dbcf02cSchristos sm->currentMethod == EAP_TYPE_NOTIFICATION) 5858dbcf02cSchristos sm->methodState = METHOD_CONTINUE; 5868dbcf02cSchristos else 5878dbcf02cSchristos sm->methodState = METHOD_PROPOSED; 5888dbcf02cSchristos 589*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 5908dbcf02cSchristos "vendor=%u method=%u", vendor, sm->currentMethod); 5913c260e60Schristos eap_log_msg(sm, "Propose EAP method vendor=%u method=%u", 5923c260e60Schristos vendor, sm->currentMethod); 5938dbcf02cSchristos } 5948dbcf02cSchristos 5958dbcf02cSchristos 5968dbcf02cSchristos SM_STATE(EAP, NAK) 5978dbcf02cSchristos { 5988dbcf02cSchristos const struct eap_hdr *nak; 5998dbcf02cSchristos size_t len = 0; 6008dbcf02cSchristos const u8 *pos; 6018dbcf02cSchristos const u8 *nak_list = NULL; 6028dbcf02cSchristos 6038dbcf02cSchristos SM_ENTRY(EAP, NAK); 6048dbcf02cSchristos 6058dbcf02cSchristos if (sm->eap_method_priv) { 6068dbcf02cSchristos sm->m->reset(sm, sm->eap_method_priv); 6078dbcf02cSchristos sm->eap_method_priv = NULL; 6088dbcf02cSchristos } 6098dbcf02cSchristos sm->m = NULL; 6108dbcf02cSchristos 611e604d861Schristos if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) 612e604d861Schristos return; 613e604d861Schristos 6148dbcf02cSchristos nak = wpabuf_head(sm->eap_if.eapRespData); 6158dbcf02cSchristos if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { 6168dbcf02cSchristos len = be_to_host16(nak->length); 6178dbcf02cSchristos if (len > wpabuf_len(sm->eap_if.eapRespData)) 6188dbcf02cSchristos len = wpabuf_len(sm->eap_if.eapRespData); 6198dbcf02cSchristos pos = (const u8 *) (nak + 1); 6208dbcf02cSchristos len -= sizeof(*nak); 6218dbcf02cSchristos if (*pos == EAP_TYPE_NAK) { 6228dbcf02cSchristos pos++; 6238dbcf02cSchristos len--; 6248dbcf02cSchristos nak_list = pos; 6258dbcf02cSchristos } 6268dbcf02cSchristos } 6278dbcf02cSchristos eap_sm_Policy_update(sm, nak_list, len); 6288dbcf02cSchristos } 6298dbcf02cSchristos 6308dbcf02cSchristos 6318dbcf02cSchristos SM_STATE(EAP, SELECT_ACTION) 6328dbcf02cSchristos { 6338dbcf02cSchristos SM_ENTRY(EAP, SELECT_ACTION); 6348dbcf02cSchristos 6358dbcf02cSchristos sm->decision = eap_sm_Policy_getDecision(sm); 6368dbcf02cSchristos } 6378dbcf02cSchristos 6388dbcf02cSchristos 6398dbcf02cSchristos SM_STATE(EAP, TIMEOUT_FAILURE) 6408dbcf02cSchristos { 6418dbcf02cSchristos SM_ENTRY(EAP, TIMEOUT_FAILURE); 6428dbcf02cSchristos 643*45d3cc13Schristos sm->eap_if.eapTimeout = true; 644be6b3c4dSchristos 645*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, 646*45d3cc13Schristos WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR, MAC2STR(sm->peer_addr)); 6478dbcf02cSchristos } 6488dbcf02cSchristos 6498dbcf02cSchristos 6508dbcf02cSchristos SM_STATE(EAP, FAILURE) 6518dbcf02cSchristos { 6528dbcf02cSchristos SM_ENTRY(EAP, FAILURE); 6538dbcf02cSchristos 6548dbcf02cSchristos wpabuf_free(sm->eap_if.eapReqData); 6558dbcf02cSchristos sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); 6568dbcf02cSchristos wpabuf_free(sm->lastReqData); 6578dbcf02cSchristos sm->lastReqData = NULL; 658*45d3cc13Schristos sm->eap_if.eapFail = true; 6598dbcf02cSchristos 660*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE 6618dbcf02cSchristos MACSTR, MAC2STR(sm->peer_addr)); 6628dbcf02cSchristos } 6638dbcf02cSchristos 6648dbcf02cSchristos 6658dbcf02cSchristos SM_STATE(EAP, SUCCESS) 6668dbcf02cSchristos { 6678dbcf02cSchristos SM_ENTRY(EAP, SUCCESS); 6688dbcf02cSchristos 6698dbcf02cSchristos wpabuf_free(sm->eap_if.eapReqData); 6708dbcf02cSchristos sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); 6718dbcf02cSchristos wpabuf_free(sm->lastReqData); 6728dbcf02cSchristos sm->lastReqData = NULL; 6738dbcf02cSchristos if (sm->eap_if.eapKeyData) 674*45d3cc13Schristos sm->eap_if.eapKeyAvailable = true; 675*45d3cc13Schristos sm->eap_if.eapSuccess = true; 6768dbcf02cSchristos 677*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS 6788dbcf02cSchristos MACSTR, MAC2STR(sm->peer_addr)); 6798dbcf02cSchristos } 6808dbcf02cSchristos 6818dbcf02cSchristos 682bb610346Schristos SM_STATE(EAP, INITIATE_REAUTH_START) 683bb610346Schristos { 684bb610346Schristos SM_ENTRY(EAP, INITIATE_REAUTH_START); 685bb610346Schristos 686*45d3cc13Schristos sm->initiate_reauth_start_sent = true; 687*45d3cc13Schristos sm->try_initiate_reauth = true; 688bb610346Schristos sm->currentId = eap_sm_nextId(sm, sm->currentId); 689bb610346Schristos wpa_printf(MSG_DEBUG, 690bb610346Schristos "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d", 691bb610346Schristos sm->currentId); 692bb610346Schristos sm->lastId = sm->currentId; 693bb610346Schristos wpabuf_free(sm->eap_if.eapReqData); 694bb610346Schristos sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm, 695bb610346Schristos sm->currentId); 696bb610346Schristos wpabuf_free(sm->lastReqData); 697bb610346Schristos sm->lastReqData = NULL; 698bb610346Schristos } 699bb610346Schristos 700bb610346Schristos 701bb610346Schristos #ifdef CONFIG_ERP 702bb610346Schristos 703bb610346Schristos static void erp_send_finish_reauth(struct eap_sm *sm, 704bb610346Schristos struct eap_server_erp_key *erp, u8 id, 705bb610346Schristos u8 flags, u16 seq, const char *nai) 706bb610346Schristos { 707bb610346Schristos size_t plen; 708bb610346Schristos struct wpabuf *msg; 709bb610346Schristos u8 hash[SHA256_MAC_LEN]; 710bb610346Schristos size_t hash_len; 711bb610346Schristos u8 seed[4]; 712bb610346Schristos 713bb610346Schristos if (erp) { 714bb610346Schristos switch (erp->cryptosuite) { 715bb610346Schristos case EAP_ERP_CS_HMAC_SHA256_256: 716bb610346Schristos hash_len = 32; 717bb610346Schristos break; 718bb610346Schristos case EAP_ERP_CS_HMAC_SHA256_128: 719bb610346Schristos hash_len = 16; 720bb610346Schristos break; 721bb610346Schristos default: 722bb610346Schristos return; 723bb610346Schristos } 724bb610346Schristos } else 725bb610346Schristos hash_len = 0; 726bb610346Schristos 727bb610346Schristos plen = 1 + 2 + 2 + os_strlen(nai); 728bb610346Schristos if (hash_len) 729bb610346Schristos plen += 1 + hash_len; 730*45d3cc13Schristos msg = eap_msg_alloc(EAP_VENDOR_IETF, 731*45d3cc13Schristos (enum eap_type) EAP_ERP_TYPE_REAUTH, 732ecc36642Schristos plen, EAP_CODE_FINISH, id); 733bb610346Schristos if (msg == NULL) 734bb610346Schristos return; 735bb610346Schristos wpabuf_put_u8(msg, flags); 736bb610346Schristos wpabuf_put_be16(msg, seq); 737bb610346Schristos 738bb610346Schristos wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI); 739bb610346Schristos wpabuf_put_u8(msg, os_strlen(nai)); 740bb610346Schristos wpabuf_put_str(msg, nai); 741bb610346Schristos 742bb610346Schristos if (erp) { 743bb610346Schristos wpabuf_put_u8(msg, erp->cryptosuite); 744bb610346Schristos if (hmac_sha256(erp->rIK, erp->rIK_len, 745bb610346Schristos wpabuf_head(msg), wpabuf_len(msg), hash) < 0) { 746bb610346Schristos wpabuf_free(msg); 747bb610346Schristos return; 748bb610346Schristos } 749bb610346Schristos wpabuf_put_data(msg, hash, hash_len); 750bb610346Schristos } 751bb610346Schristos 752bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)", 753bb610346Schristos flags & 0x80 ? "failure" : "success"); 754bb610346Schristos 755bb610346Schristos sm->lastId = sm->currentId; 756bb610346Schristos sm->currentId = id; 757bb610346Schristos wpabuf_free(sm->eap_if.eapReqData); 758bb610346Schristos sm->eap_if.eapReqData = msg; 759bb610346Schristos wpabuf_free(sm->lastReqData); 760bb610346Schristos sm->lastReqData = NULL; 761bb610346Schristos 762ecc36642Schristos if ((flags & 0x80) || !erp) { 763*45d3cc13Schristos sm->eap_if.eapFail = true; 764*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE 765bb610346Schristos MACSTR, MAC2STR(sm->peer_addr)); 766bb610346Schristos return; 767bb610346Schristos } 768bb610346Schristos 769bb610346Schristos bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 770bb610346Schristos sm->eap_if.eapKeyDataLen = 0; 771bb610346Schristos sm->eap_if.eapKeyData = os_malloc(erp->rRK_len); 772bb610346Schristos if (!sm->eap_if.eapKeyData) 773bb610346Schristos return; 774bb610346Schristos 775bb610346Schristos WPA_PUT_BE16(seed, seq); 776bb610346Schristos WPA_PUT_BE16(&seed[2], erp->rRK_len); 777bb610346Schristos if (hmac_sha256_kdf(erp->rRK, erp->rRK_len, 778bb610346Schristos "Re-authentication Master Session Key@ietf.org", 779bb610346Schristos seed, sizeof(seed), 780bb610346Schristos sm->eap_if.eapKeyData, erp->rRK_len) < 0) { 781bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP"); 782bb610346Schristos bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len); 783bb610346Schristos sm->eap_if.eapKeyData = NULL; 784bb610346Schristos return; 785bb610346Schristos } 786bb610346Schristos sm->eap_if.eapKeyDataLen = erp->rRK_len; 787*45d3cc13Schristos sm->eap_if.eapKeyAvailable = true; 788bb610346Schristos wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK", 789bb610346Schristos sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 790*45d3cc13Schristos sm->eap_if.eapSuccess = true; 791bb610346Schristos 792*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS 793bb610346Schristos MACSTR, MAC2STR(sm->peer_addr)); 794bb610346Schristos } 795bb610346Schristos 796bb610346Schristos 797bb610346Schristos SM_STATE(EAP, INITIATE_RECEIVED) 798bb610346Schristos { 799bb610346Schristos const u8 *pos, *end, *start, *tlvs, *hdr; 800bb610346Schristos const struct eap_hdr *ehdr; 801bb610346Schristos size_t len; 802bb610346Schristos u8 flags; 803bb610346Schristos u16 seq; 804bb610346Schristos char nai[254]; 805bb610346Schristos struct eap_server_erp_key *erp; 806bb610346Schristos int max_len; 807bb610346Schristos u8 hash[SHA256_MAC_LEN]; 808bb610346Schristos size_t hash_len; 809bb610346Schristos struct erp_tlvs parse; 810bb610346Schristos u8 resp_flags = 0x80; /* default to failure; cleared on success */ 811bb610346Schristos 812bb610346Schristos SM_ENTRY(EAP, INITIATE_RECEIVED); 813bb610346Schristos 814*45d3cc13Schristos sm->rxInitiate = false; 815bb610346Schristos 816*45d3cc13Schristos pos = eap_hdr_validate(EAP_VENDOR_IETF, 817*45d3cc13Schristos (enum eap_type) EAP_ERP_TYPE_REAUTH, 818bb610346Schristos sm->eap_if.eapRespData, &len); 819bb610346Schristos if (pos == NULL) { 820bb610346Schristos wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame"); 821bb610346Schristos goto fail; 822bb610346Schristos } 823bb610346Schristos hdr = wpabuf_head(sm->eap_if.eapRespData); 824bb610346Schristos ehdr = wpabuf_head(sm->eap_if.eapRespData); 825bb610346Schristos 826bb610346Schristos wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len); 827bb610346Schristos if (len < 4) { 828bb610346Schristos wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth"); 829bb610346Schristos goto fail; 830bb610346Schristos } 831bb610346Schristos end = pos + len; 832bb610346Schristos 833bb610346Schristos flags = *pos++; 834bb610346Schristos seq = WPA_GET_BE16(pos); 835bb610346Schristos pos += 2; 836bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq); 837bb610346Schristos tlvs = pos; 838bb610346Schristos 839bb610346Schristos /* 840bb610346Schristos * Parse TVs/TLVs. Since we do not yet know the length of the 841bb610346Schristos * Authentication Tag, stop parsing if an unknown TV/TLV is seen and 842bb610346Schristos * just try to find the keyName-NAI first so that we can check the 843bb610346Schristos * Authentication Tag. 844bb610346Schristos */ 845bb610346Schristos if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0) 846bb610346Schristos goto fail; 847bb610346Schristos 848bb610346Schristos if (!parse.keyname) { 849bb610346Schristos wpa_printf(MSG_DEBUG, 850bb610346Schristos "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet"); 851bb610346Schristos goto fail; 852bb610346Schristos } 853bb610346Schristos 854bb610346Schristos wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI", 855bb610346Schristos parse.keyname, parse.keyname_len); 856bb610346Schristos if (parse.keyname_len > 253) { 857bb610346Schristos wpa_printf(MSG_DEBUG, 858bb610346Schristos "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth"); 859bb610346Schristos goto fail; 860bb610346Schristos } 861bb610346Schristos os_memcpy(nai, parse.keyname, parse.keyname_len); 862bb610346Schristos nai[parse.keyname_len] = '\0'; 863bb610346Schristos 864*45d3cc13Schristos if (!sm->cfg->eap_server) { 865bb610346Schristos /* 866bb610346Schristos * In passthrough case, EAP-Initiate/Re-auth replaces 867bb610346Schristos * EAP Identity exchange. Use keyName-NAI as the user identity 868bb610346Schristos * and forward EAP-Initiate/Re-auth to the backend 869bb610346Schristos * authentication server. 870bb610346Schristos */ 871bb610346Schristos wpa_printf(MSG_DEBUG, 872bb610346Schristos "EAP: Use keyName-NAI as user identity for backend authentication"); 873bb610346Schristos eap_server_clear_identity(sm); 874bb610346Schristos sm->identity = (u8 *) dup_binstr(parse.keyname, 875bb610346Schristos parse.keyname_len); 876bb610346Schristos if (!sm->identity) 877bb610346Schristos goto fail; 878bb610346Schristos sm->identity_len = parse.keyname_len; 879bb610346Schristos return; 880bb610346Schristos } 881bb610346Schristos 882bb610346Schristos erp = eap_erp_get_key(sm, nai); 883bb610346Schristos if (!erp) { 884bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s", 885bb610346Schristos nai); 886bb610346Schristos goto report_error; 887bb610346Schristos } 888bb610346Schristos 889bb610346Schristos if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) { 890bb610346Schristos wpa_printf(MSG_DEBUG, 891bb610346Schristos "EAP: SEQ=%u replayed (already received SEQ=%u)", 892bb610346Schristos seq, erp->recv_seq); 893bb610346Schristos goto fail; 894bb610346Schristos } 895bb610346Schristos 896bb610346Schristos /* Is there enough room for Cryptosuite and Authentication Tag? */ 897bb610346Schristos start = parse.keyname + parse.keyname_len; 898bb610346Schristos max_len = end - start; 899bb610346Schristos if (max_len < 900bb610346Schristos 1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) { 901bb610346Schristos wpa_printf(MSG_DEBUG, 902bb610346Schristos "EAP: Not enough room for Authentication Tag"); 903bb610346Schristos goto fail; 904bb610346Schristos } 905bb610346Schristos 906bb610346Schristos switch (erp->cryptosuite) { 907bb610346Schristos case EAP_ERP_CS_HMAC_SHA256_256: 908bb610346Schristos if (end[-33] != erp->cryptosuite) { 909bb610346Schristos wpa_printf(MSG_DEBUG, 910bb610346Schristos "EAP: Different Cryptosuite used"); 911bb610346Schristos goto fail; 912bb610346Schristos } 913bb610346Schristos hash_len = 32; 914bb610346Schristos break; 915bb610346Schristos case EAP_ERP_CS_HMAC_SHA256_128: 916bb610346Schristos if (end[-17] != erp->cryptosuite) { 917bb610346Schristos wpa_printf(MSG_DEBUG, 918bb610346Schristos "EAP: Different Cryptosuite used"); 919bb610346Schristos goto fail; 920bb610346Schristos } 921bb610346Schristos hash_len = 16; 922bb610346Schristos break; 923bb610346Schristos default: 924bb610346Schristos hash_len = 0; 925bb610346Schristos break; 926bb610346Schristos } 927bb610346Schristos 928bb610346Schristos if (hash_len) { 929bb610346Schristos if (hmac_sha256(erp->rIK, erp->rIK_len, hdr, 930bb610346Schristos end - hdr - hash_len, hash) < 0) 931bb610346Schristos goto fail; 932bb610346Schristos if (os_memcmp(end - hash_len, hash, hash_len) != 0) { 933bb610346Schristos wpa_printf(MSG_DEBUG, 934bb610346Schristos "EAP: Authentication Tag mismatch"); 935bb610346Schristos goto fail; 936bb610346Schristos } 937bb610346Schristos } 938bb610346Schristos 939bb610346Schristos /* Check if any supported CS results in matching tag */ 940bb610346Schristos if (!hash_len && max_len >= 1 + 32 && 941bb610346Schristos end[-33] == EAP_ERP_CS_HMAC_SHA256_256) { 942bb610346Schristos if (hmac_sha256(erp->rIK, erp->rIK_len, hdr, 943bb610346Schristos end - hdr - 32, hash) < 0) 944bb610346Schristos goto fail; 945bb610346Schristos if (os_memcmp(end - 32, hash, 32) == 0) { 946bb610346Schristos wpa_printf(MSG_DEBUG, 947bb610346Schristos "EAP: Authentication Tag match using HMAC-SHA256-256"); 948bb610346Schristos hash_len = 32; 949bb610346Schristos erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256; 950bb610346Schristos } 951bb610346Schristos } 952bb610346Schristos 953bb610346Schristos if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) { 954bb610346Schristos if (hmac_sha256(erp->rIK, erp->rIK_len, hdr, 955bb610346Schristos end - hdr - 16, hash) < 0) 956bb610346Schristos goto fail; 957bb610346Schristos if (os_memcmp(end - 16, hash, 16) == 0) { 958bb610346Schristos wpa_printf(MSG_DEBUG, 959bb610346Schristos "EAP: Authentication Tag match using HMAC-SHA256-128"); 960bb610346Schristos hash_len = 16; 961bb610346Schristos erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128; 962bb610346Schristos } 963bb610346Schristos } 964bb610346Schristos 965bb610346Schristos if (!hash_len) { 966bb610346Schristos wpa_printf(MSG_DEBUG, 967bb610346Schristos "EAP: No supported cryptosuite matched Authentication Tag"); 968bb610346Schristos goto fail; 969bb610346Schristos } 970bb610346Schristos end -= 1 + hash_len; 971bb610346Schristos 972bb610346Schristos /* 973bb610346Schristos * Parse TVs/TLVs again now that we know the exact part of the buffer 974bb610346Schristos * that contains them. 975bb610346Schristos */ 976bb610346Schristos wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs", 977bb610346Schristos tlvs, end - tlvs); 978bb610346Schristos if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0) 979bb610346Schristos goto fail; 980bb610346Schristos 981bb610346Schristos wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u", 982bb610346Schristos erp->keyname_nai, seq); 983bb610346Schristos erp->recv_seq = seq; 984bb610346Schristos resp_flags &= ~0x80; /* R=0 - success */ 985bb610346Schristos 986bb610346Schristos report_error: 987bb610346Schristos erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai); 988bb610346Schristos return; 989bb610346Schristos 990bb610346Schristos fail: 991*45d3cc13Schristos sm->ignore = true; 992bb610346Schristos } 993bb610346Schristos 994bb610346Schristos #endif /* CONFIG_ERP */ 995bb610346Schristos 996bb610346Schristos 9978dbcf02cSchristos SM_STATE(EAP, INITIALIZE_PASSTHROUGH) 9988dbcf02cSchristos { 9998dbcf02cSchristos SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); 10008dbcf02cSchristos 10018dbcf02cSchristos wpabuf_free(sm->eap_if.aaaEapRespData); 10028dbcf02cSchristos sm->eap_if.aaaEapRespData = NULL; 1003*45d3cc13Schristos sm->try_initiate_reauth = false; 10048dbcf02cSchristos } 10058dbcf02cSchristos 10068dbcf02cSchristos 10078dbcf02cSchristos SM_STATE(EAP, IDLE2) 10088dbcf02cSchristos { 10098dbcf02cSchristos SM_ENTRY(EAP, IDLE2); 10108dbcf02cSchristos 10118dbcf02cSchristos sm->eap_if.retransWhile = eap_sm_calculateTimeout( 10128dbcf02cSchristos sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 10138dbcf02cSchristos sm->methodTimeout); 10148dbcf02cSchristos } 10158dbcf02cSchristos 10168dbcf02cSchristos 10178dbcf02cSchristos SM_STATE(EAP, RETRANSMIT2) 10188dbcf02cSchristos { 10198dbcf02cSchristos SM_ENTRY(EAP, RETRANSMIT2); 10208dbcf02cSchristos 10218dbcf02cSchristos sm->retransCount++; 10228dbcf02cSchristos if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 10238dbcf02cSchristos if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 1024*45d3cc13Schristos sm->eap_if.eapReq = true; 10258dbcf02cSchristos } 1026be6b3c4dSchristos 1027*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR, 1028be6b3c4dSchristos MAC2STR(sm->peer_addr)); 10298dbcf02cSchristos } 10308dbcf02cSchristos 10318dbcf02cSchristos 10328dbcf02cSchristos SM_STATE(EAP, RECEIVED2) 10338dbcf02cSchristos { 10348dbcf02cSchristos SM_ENTRY(EAP, RECEIVED2); 10358dbcf02cSchristos 10368dbcf02cSchristos /* parse rxResp, respId, respMethod */ 10378dbcf02cSchristos eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 10388dbcf02cSchristos } 10398dbcf02cSchristos 10408dbcf02cSchristos 10418dbcf02cSchristos SM_STATE(EAP, DISCARD2) 10428dbcf02cSchristos { 10438dbcf02cSchristos SM_ENTRY(EAP, DISCARD2); 1044*45d3cc13Schristos sm->eap_if.eapResp = false; 1045*45d3cc13Schristos sm->eap_if.eapNoReq = true; 10468dbcf02cSchristos } 10478dbcf02cSchristos 10488dbcf02cSchristos 10498dbcf02cSchristos SM_STATE(EAP, SEND_REQUEST2) 10508dbcf02cSchristos { 10518dbcf02cSchristos SM_ENTRY(EAP, SEND_REQUEST2); 10528dbcf02cSchristos 10538dbcf02cSchristos sm->retransCount = 0; 10548dbcf02cSchristos if (sm->eap_if.eapReqData) { 10558dbcf02cSchristos if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 10568dbcf02cSchristos { 1057*45d3cc13Schristos sm->eap_if.eapResp = false; 1058*45d3cc13Schristos sm->eap_if.eapReq = true; 10598dbcf02cSchristos } else { 1060*45d3cc13Schristos sm->eap_if.eapResp = false; 1061*45d3cc13Schristos sm->eap_if.eapReq = false; 10628dbcf02cSchristos } 10638dbcf02cSchristos } else { 10648dbcf02cSchristos wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); 1065*45d3cc13Schristos sm->eap_if.eapResp = false; 1066*45d3cc13Schristos sm->eap_if.eapReq = false; 1067*45d3cc13Schristos sm->eap_if.eapNoReq = true; 10688dbcf02cSchristos } 10698dbcf02cSchristos } 10708dbcf02cSchristos 10718dbcf02cSchristos 10728dbcf02cSchristos SM_STATE(EAP, AAA_REQUEST) 10738dbcf02cSchristos { 10748dbcf02cSchristos SM_ENTRY(EAP, AAA_REQUEST); 10758dbcf02cSchristos 10768dbcf02cSchristos if (sm->eap_if.eapRespData == NULL) { 10778dbcf02cSchristos wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); 10788dbcf02cSchristos return; 10798dbcf02cSchristos } 10808dbcf02cSchristos 10818dbcf02cSchristos /* 10828dbcf02cSchristos * if (respMethod == IDENTITY) 10838dbcf02cSchristos * aaaIdentity = eapRespData 10848dbcf02cSchristos * This is already taken care of by the EAP-Identity method which 10858dbcf02cSchristos * stores the identity into sm->identity. 10868dbcf02cSchristos */ 10878dbcf02cSchristos 10888dbcf02cSchristos eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); 10898dbcf02cSchristos } 10908dbcf02cSchristos 10918dbcf02cSchristos 10928dbcf02cSchristos SM_STATE(EAP, AAA_RESPONSE) 10938dbcf02cSchristos { 10948dbcf02cSchristos SM_ENTRY(EAP, AAA_RESPONSE); 10958dbcf02cSchristos 10968dbcf02cSchristos eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 10978dbcf02cSchristos sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); 10988dbcf02cSchristos sm->methodTimeout = sm->eap_if.aaaMethodTimeout; 10998dbcf02cSchristos } 11008dbcf02cSchristos 11018dbcf02cSchristos 11028dbcf02cSchristos SM_STATE(EAP, AAA_IDLE) 11038dbcf02cSchristos { 11048dbcf02cSchristos SM_ENTRY(EAP, AAA_IDLE); 11058dbcf02cSchristos 1106*45d3cc13Schristos sm->eap_if.aaaFail = false; 1107*45d3cc13Schristos sm->eap_if.aaaSuccess = false; 1108*45d3cc13Schristos sm->eap_if.aaaEapReq = false; 1109*45d3cc13Schristos sm->eap_if.aaaEapNoReq = false; 1110*45d3cc13Schristos sm->eap_if.aaaEapResp = true; 11118dbcf02cSchristos } 11128dbcf02cSchristos 11138dbcf02cSchristos 11148dbcf02cSchristos SM_STATE(EAP, TIMEOUT_FAILURE2) 11158dbcf02cSchristos { 11168dbcf02cSchristos SM_ENTRY(EAP, TIMEOUT_FAILURE2); 11178dbcf02cSchristos 1118*45d3cc13Schristos sm->eap_if.eapTimeout = true; 1119be6b3c4dSchristos 1120*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, 1121*45d3cc13Schristos WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR, MAC2STR(sm->peer_addr)); 11228dbcf02cSchristos } 11238dbcf02cSchristos 11248dbcf02cSchristos 11258dbcf02cSchristos SM_STATE(EAP, FAILURE2) 11268dbcf02cSchristos { 11278dbcf02cSchristos SM_ENTRY(EAP, FAILURE2); 11288dbcf02cSchristos 11298dbcf02cSchristos eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 1130*45d3cc13Schristos sm->eap_if.eapFail = true; 1131be6b3c4dSchristos 1132*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR, 1133be6b3c4dSchristos MAC2STR(sm->peer_addr)); 11348dbcf02cSchristos } 11358dbcf02cSchristos 11368dbcf02cSchristos 11378dbcf02cSchristos SM_STATE(EAP, SUCCESS2) 11388dbcf02cSchristos { 11398dbcf02cSchristos SM_ENTRY(EAP, SUCCESS2); 11408dbcf02cSchristos 11418dbcf02cSchristos eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 11428dbcf02cSchristos 11438dbcf02cSchristos sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; 11448dbcf02cSchristos if (sm->eap_if.aaaEapKeyAvailable) { 11458dbcf02cSchristos EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); 11468dbcf02cSchristos } else { 11473c260e60Schristos bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 11488dbcf02cSchristos sm->eap_if.eapKeyData = NULL; 11498dbcf02cSchristos sm->eap_if.eapKeyDataLen = 0; 11508dbcf02cSchristos } 11518dbcf02cSchristos 1152*45d3cc13Schristos sm->eap_if.eapSuccess = true; 11538dbcf02cSchristos 11548dbcf02cSchristos /* 11558dbcf02cSchristos * Start reauthentication with identity request even though we know the 11568dbcf02cSchristos * previously used identity. This is needed to get reauthentication 11578dbcf02cSchristos * started properly. 11588dbcf02cSchristos */ 1159*45d3cc13Schristos sm->start_reauth = true; 1160be6b3c4dSchristos 1161*45d3cc13Schristos wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR, 1162be6b3c4dSchristos MAC2STR(sm->peer_addr)); 11638dbcf02cSchristos } 11648dbcf02cSchristos 11658dbcf02cSchristos 11668dbcf02cSchristos SM_STEP(EAP) 11678dbcf02cSchristos { 11688dbcf02cSchristos if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) 11698dbcf02cSchristos SM_ENTER_GLOBAL(EAP, INITIALIZE); 11708dbcf02cSchristos else if (!sm->eap_if.portEnabled) 11718dbcf02cSchristos SM_ENTER_GLOBAL(EAP, DISABLED); 1172*45d3cc13Schristos else if (sm->num_rounds > sm->cfg->max_auth_rounds) { 1173*45d3cc13Schristos if (sm->num_rounds == sm->cfg->max_auth_rounds + 1) { 11748dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: more than %d " 11758dbcf02cSchristos "authentication rounds - abort", 1176*45d3cc13Schristos sm->cfg->max_auth_rounds); 11778dbcf02cSchristos sm->num_rounds++; 11788dbcf02cSchristos SM_ENTER_GLOBAL(EAP, FAILURE); 11798dbcf02cSchristos } 1180*45d3cc13Schristos } else if (sm->num_rounds_short > sm->cfg->max_auth_rounds_short) { 1181*45d3cc13Schristos if (sm->num_rounds_short == 1182*45d3cc13Schristos sm->cfg->max_auth_rounds_short + 1) { 1183*45d3cc13Schristos wpa_printf(MSG_DEBUG, 1184*45d3cc13Schristos "EAP: more than %d authentication rounds (short) - abort", 1185*45d3cc13Schristos sm->cfg->max_auth_rounds_short); 1186*45d3cc13Schristos sm->num_rounds_short++; 1187*45d3cc13Schristos SM_ENTER_GLOBAL(EAP, FAILURE); 1188*45d3cc13Schristos } 11898dbcf02cSchristos } else switch (sm->EAP_state) { 11908dbcf02cSchristos case EAP_INITIALIZE: 1191*45d3cc13Schristos if (sm->cfg->backend_auth) { 11928dbcf02cSchristos if (!sm->rxResp) 11938dbcf02cSchristos SM_ENTER(EAP, SELECT_ACTION); 11948dbcf02cSchristos else if (sm->rxResp && 11958dbcf02cSchristos (sm->respMethod == EAP_TYPE_NAK || 11968dbcf02cSchristos (sm->respMethod == EAP_TYPE_EXPANDED && 11978dbcf02cSchristos sm->respVendor == EAP_VENDOR_IETF && 11988dbcf02cSchristos sm->respVendorMethod == EAP_TYPE_NAK))) 11998dbcf02cSchristos SM_ENTER(EAP, NAK); 12008dbcf02cSchristos else 12018dbcf02cSchristos SM_ENTER(EAP, PICK_UP_METHOD); 12028dbcf02cSchristos } else { 12038dbcf02cSchristos SM_ENTER(EAP, SELECT_ACTION); 12048dbcf02cSchristos } 12058dbcf02cSchristos break; 12068dbcf02cSchristos case EAP_PICK_UP_METHOD: 12078dbcf02cSchristos if (sm->currentMethod == EAP_TYPE_NONE) { 12088dbcf02cSchristos SM_ENTER(EAP, SELECT_ACTION); 12098dbcf02cSchristos } else { 12108dbcf02cSchristos SM_ENTER(EAP, METHOD_RESPONSE); 12118dbcf02cSchristos } 12128dbcf02cSchristos break; 12138dbcf02cSchristos case EAP_DISABLED: 12148dbcf02cSchristos if (sm->eap_if.portEnabled) 12158dbcf02cSchristos SM_ENTER(EAP, INITIALIZE); 12168dbcf02cSchristos break; 12178dbcf02cSchristos case EAP_IDLE: 1218bb610346Schristos if (sm->eap_if.retransWhile == 0) { 1219bb610346Schristos if (sm->try_initiate_reauth) { 1220*45d3cc13Schristos sm->try_initiate_reauth = false; 1221bb610346Schristos SM_ENTER(EAP, SELECT_ACTION); 1222bb610346Schristos } else { 12238dbcf02cSchristos SM_ENTER(EAP, RETRANSMIT); 1224bb610346Schristos } 1225bb610346Schristos } else if (sm->eap_if.eapResp) 12268dbcf02cSchristos SM_ENTER(EAP, RECEIVED); 12278dbcf02cSchristos break; 12288dbcf02cSchristos case EAP_RETRANSMIT: 12298dbcf02cSchristos if (sm->retransCount > sm->MaxRetrans) 12308dbcf02cSchristos SM_ENTER(EAP, TIMEOUT_FAILURE); 12318dbcf02cSchristos else 12328dbcf02cSchristos SM_ENTER(EAP, IDLE); 12338dbcf02cSchristos break; 12348dbcf02cSchristos case EAP_RECEIVED: 12358dbcf02cSchristos if (sm->rxResp && (sm->respId == sm->currentId) && 12368dbcf02cSchristos (sm->respMethod == EAP_TYPE_NAK || 12378dbcf02cSchristos (sm->respMethod == EAP_TYPE_EXPANDED && 12388dbcf02cSchristos sm->respVendor == EAP_VENDOR_IETF && 12398dbcf02cSchristos sm->respVendorMethod == EAP_TYPE_NAK)) 12408dbcf02cSchristos && (sm->methodState == METHOD_PROPOSED)) 12418dbcf02cSchristos SM_ENTER(EAP, NAK); 12428dbcf02cSchristos else if (sm->rxResp && (sm->respId == sm->currentId) && 12438dbcf02cSchristos ((sm->respMethod == sm->currentMethod) || 12448dbcf02cSchristos (sm->respMethod == EAP_TYPE_EXPANDED && 12458dbcf02cSchristos sm->respVendor == EAP_VENDOR_IETF && 12468dbcf02cSchristos sm->respVendorMethod == sm->currentMethod))) 12478dbcf02cSchristos SM_ENTER(EAP, INTEGRITY_CHECK); 1248bb610346Schristos #ifdef CONFIG_ERP 1249bb610346Schristos else if (sm->rxInitiate) 1250bb610346Schristos SM_ENTER(EAP, INITIATE_RECEIVED); 1251bb610346Schristos #endif /* CONFIG_ERP */ 12528dbcf02cSchristos else { 12538dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " 12548dbcf02cSchristos "rxResp=%d respId=%d currentId=%d " 12558dbcf02cSchristos "respMethod=%d currentMethod=%d", 12568dbcf02cSchristos sm->rxResp, sm->respId, sm->currentId, 12578dbcf02cSchristos sm->respMethod, sm->currentMethod); 12583c260e60Schristos eap_log_msg(sm, "Discard received EAP message"); 12598dbcf02cSchristos SM_ENTER(EAP, DISCARD); 12608dbcf02cSchristos } 12618dbcf02cSchristos break; 12628dbcf02cSchristos case EAP_DISCARD: 12638dbcf02cSchristos SM_ENTER(EAP, IDLE); 12648dbcf02cSchristos break; 12658dbcf02cSchristos case EAP_SEND_REQUEST: 12668dbcf02cSchristos SM_ENTER(EAP, IDLE); 12678dbcf02cSchristos break; 12688dbcf02cSchristos case EAP_INTEGRITY_CHECK: 12698dbcf02cSchristos if (sm->ignore) 12708dbcf02cSchristos SM_ENTER(EAP, DISCARD); 12718dbcf02cSchristos else 12728dbcf02cSchristos SM_ENTER(EAP, METHOD_RESPONSE); 12738dbcf02cSchristos break; 12748dbcf02cSchristos case EAP_METHOD_REQUEST: 12753c260e60Schristos if (sm->m == NULL) { 12763c260e60Schristos /* 12773c260e60Schristos * This transition is not mentioned in RFC 4137, but it 12783c260e60Schristos * is needed to handle cleanly a case where EAP method 12793c260e60Schristos * initialization fails. 12803c260e60Schristos */ 12813c260e60Schristos SM_ENTER(EAP, FAILURE); 12823c260e60Schristos break; 12833c260e60Schristos } 12848dbcf02cSchristos SM_ENTER(EAP, SEND_REQUEST); 1285ecc36642Schristos if (sm->eap_if.eapNoReq && !sm->eap_if.eapReq) { 1286ecc36642Schristos /* 1287ecc36642Schristos * This transition is not mentioned in RFC 4137, but it 1288ecc36642Schristos * is needed to handle cleanly a case where EAP method 1289ecc36642Schristos * buildReq fails. 1290ecc36642Schristos */ 1291ecc36642Schristos wpa_printf(MSG_DEBUG, 1292ecc36642Schristos "EAP: Method did not return a request"); 1293ecc36642Schristos SM_ENTER(EAP, FAILURE); 1294ecc36642Schristos break; 1295ecc36642Schristos } 12968dbcf02cSchristos break; 12978dbcf02cSchristos case EAP_METHOD_RESPONSE: 12988dbcf02cSchristos /* 12998dbcf02cSchristos * Note: Mechanism to allow EAP methods to wait while going 13008dbcf02cSchristos * through pending processing is an extension to RFC 4137 13018dbcf02cSchristos * which only defines the transits to SELECT_ACTION and 13028dbcf02cSchristos * METHOD_REQUEST from this METHOD_RESPONSE state. 13038dbcf02cSchristos */ 13048dbcf02cSchristos if (sm->methodState == METHOD_END) 13058dbcf02cSchristos SM_ENTER(EAP, SELECT_ACTION); 13068dbcf02cSchristos else if (sm->method_pending == METHOD_PENDING_WAIT) { 13078dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Method has pending " 13088dbcf02cSchristos "processing - wait before proceeding to " 13098dbcf02cSchristos "METHOD_REQUEST state"); 13108dbcf02cSchristos } else if (sm->method_pending == METHOD_PENDING_CONT) { 13118dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Method has completed " 13128dbcf02cSchristos "pending processing - reprocess pending " 13138dbcf02cSchristos "EAP message"); 13148dbcf02cSchristos sm->method_pending = METHOD_PENDING_NONE; 13158dbcf02cSchristos SM_ENTER(EAP, METHOD_RESPONSE); 13168dbcf02cSchristos } else 13178dbcf02cSchristos SM_ENTER(EAP, METHOD_REQUEST); 13188dbcf02cSchristos break; 13198dbcf02cSchristos case EAP_PROPOSE_METHOD: 13208dbcf02cSchristos /* 13218dbcf02cSchristos * Note: Mechanism to allow EAP methods to wait while going 13228dbcf02cSchristos * through pending processing is an extension to RFC 4137 13238dbcf02cSchristos * which only defines the transit to METHOD_REQUEST from this 13248dbcf02cSchristos * PROPOSE_METHOD state. 13258dbcf02cSchristos */ 13268dbcf02cSchristos if (sm->method_pending == METHOD_PENDING_WAIT) { 13278dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Method has pending " 13288dbcf02cSchristos "processing - wait before proceeding to " 13298dbcf02cSchristos "METHOD_REQUEST state"); 13308dbcf02cSchristos if (sm->user_eap_method_index > 0) 13318dbcf02cSchristos sm->user_eap_method_index--; 13328dbcf02cSchristos } else if (sm->method_pending == METHOD_PENDING_CONT) { 13338dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Method has completed " 13348dbcf02cSchristos "pending processing - reprocess pending " 13358dbcf02cSchristos "EAP message"); 13368dbcf02cSchristos sm->method_pending = METHOD_PENDING_NONE; 13378dbcf02cSchristos SM_ENTER(EAP, PROPOSE_METHOD); 13388dbcf02cSchristos } else 13398dbcf02cSchristos SM_ENTER(EAP, METHOD_REQUEST); 13408dbcf02cSchristos break; 13418dbcf02cSchristos case EAP_NAK: 13428dbcf02cSchristos SM_ENTER(EAP, SELECT_ACTION); 13438dbcf02cSchristos break; 13448dbcf02cSchristos case EAP_SELECT_ACTION: 13458dbcf02cSchristos if (sm->decision == DECISION_FAILURE) 13468dbcf02cSchristos SM_ENTER(EAP, FAILURE); 13478dbcf02cSchristos else if (sm->decision == DECISION_SUCCESS) 13488dbcf02cSchristos SM_ENTER(EAP, SUCCESS); 13498dbcf02cSchristos else if (sm->decision == DECISION_PASSTHROUGH) 13508dbcf02cSchristos SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); 1351bb610346Schristos else if (sm->decision == DECISION_INITIATE_REAUTH_START) 1352bb610346Schristos SM_ENTER(EAP, INITIATE_REAUTH_START); 1353bb610346Schristos #ifdef CONFIG_ERP 1354*45d3cc13Schristos else if (sm->cfg->eap_server && sm->cfg->erp && sm->rxInitiate) 1355bb610346Schristos SM_ENTER(EAP, INITIATE_RECEIVED); 1356bb610346Schristos #endif /* CONFIG_ERP */ 13578dbcf02cSchristos else 13588dbcf02cSchristos SM_ENTER(EAP, PROPOSE_METHOD); 13598dbcf02cSchristos break; 1360bb610346Schristos case EAP_INITIATE_REAUTH_START: 1361bb610346Schristos SM_ENTER(EAP, SEND_REQUEST); 1362bb610346Schristos break; 1363bb610346Schristos case EAP_INITIATE_RECEIVED: 1364*45d3cc13Schristos if (!sm->cfg->eap_server) 1365bb610346Schristos SM_ENTER(EAP, SELECT_ACTION); 1366bb610346Schristos break; 13678dbcf02cSchristos case EAP_TIMEOUT_FAILURE: 13688dbcf02cSchristos break; 13698dbcf02cSchristos case EAP_FAILURE: 13708dbcf02cSchristos break; 13718dbcf02cSchristos case EAP_SUCCESS: 13728dbcf02cSchristos break; 13738dbcf02cSchristos 13748dbcf02cSchristos case EAP_INITIALIZE_PASSTHROUGH: 13758dbcf02cSchristos if (sm->currentId == -1) 13768dbcf02cSchristos SM_ENTER(EAP, AAA_IDLE); 13778dbcf02cSchristos else 13788dbcf02cSchristos SM_ENTER(EAP, AAA_REQUEST); 13798dbcf02cSchristos break; 13808dbcf02cSchristos case EAP_IDLE2: 13818dbcf02cSchristos if (sm->eap_if.eapResp) 13828dbcf02cSchristos SM_ENTER(EAP, RECEIVED2); 13838dbcf02cSchristos else if (sm->eap_if.retransWhile == 0) 13848dbcf02cSchristos SM_ENTER(EAP, RETRANSMIT2); 13858dbcf02cSchristos break; 13868dbcf02cSchristos case EAP_RETRANSMIT2: 13878dbcf02cSchristos if (sm->retransCount > sm->MaxRetrans) 13888dbcf02cSchristos SM_ENTER(EAP, TIMEOUT_FAILURE2); 13898dbcf02cSchristos else 13908dbcf02cSchristos SM_ENTER(EAP, IDLE2); 13918dbcf02cSchristos break; 13928dbcf02cSchristos case EAP_RECEIVED2: 13938dbcf02cSchristos if (sm->rxResp && (sm->respId == sm->currentId)) 13948dbcf02cSchristos SM_ENTER(EAP, AAA_REQUEST); 13958dbcf02cSchristos else 13968dbcf02cSchristos SM_ENTER(EAP, DISCARD2); 13978dbcf02cSchristos break; 13988dbcf02cSchristos case EAP_DISCARD2: 13998dbcf02cSchristos SM_ENTER(EAP, IDLE2); 14008dbcf02cSchristos break; 14018dbcf02cSchristos case EAP_SEND_REQUEST2: 14028dbcf02cSchristos SM_ENTER(EAP, IDLE2); 14038dbcf02cSchristos break; 14048dbcf02cSchristos case EAP_AAA_REQUEST: 14058dbcf02cSchristos SM_ENTER(EAP, AAA_IDLE); 14068dbcf02cSchristos break; 14078dbcf02cSchristos case EAP_AAA_RESPONSE: 14088dbcf02cSchristos SM_ENTER(EAP, SEND_REQUEST2); 14098dbcf02cSchristos break; 14108dbcf02cSchristos case EAP_AAA_IDLE: 14118dbcf02cSchristos if (sm->eap_if.aaaFail) 14128dbcf02cSchristos SM_ENTER(EAP, FAILURE2); 14138dbcf02cSchristos else if (sm->eap_if.aaaSuccess) 14148dbcf02cSchristos SM_ENTER(EAP, SUCCESS2); 14158dbcf02cSchristos else if (sm->eap_if.aaaEapReq) 14168dbcf02cSchristos SM_ENTER(EAP, AAA_RESPONSE); 14178dbcf02cSchristos else if (sm->eap_if.aaaTimeout) 14188dbcf02cSchristos SM_ENTER(EAP, TIMEOUT_FAILURE2); 14198dbcf02cSchristos break; 14208dbcf02cSchristos case EAP_TIMEOUT_FAILURE2: 14218dbcf02cSchristos break; 14228dbcf02cSchristos case EAP_FAILURE2: 14238dbcf02cSchristos break; 14248dbcf02cSchristos case EAP_SUCCESS2: 14258dbcf02cSchristos break; 14268dbcf02cSchristos } 14278dbcf02cSchristos } 14288dbcf02cSchristos 14298dbcf02cSchristos 14308dbcf02cSchristos static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 14318dbcf02cSchristos int eapSRTT, int eapRTTVAR, 14328dbcf02cSchristos int methodTimeout) 14338dbcf02cSchristos { 14348dbcf02cSchristos int rto, i; 14358dbcf02cSchristos 1436bb610346Schristos if (sm->try_initiate_reauth) { 1437bb610346Schristos wpa_printf(MSG_DEBUG, 1438bb610346Schristos "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start"); 1439bb610346Schristos return 1; 1440bb610346Schristos } 1441bb610346Schristos 14428dbcf02cSchristos if (methodTimeout) { 14438dbcf02cSchristos /* 14448dbcf02cSchristos * EAP method (either internal or through AAA server, provided 14458dbcf02cSchristos * timeout hint. Use that as-is as a timeout for retransmitting 14468dbcf02cSchristos * the EAP request if no response is received. 14478dbcf02cSchristos */ 14488dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 14498dbcf02cSchristos "(from EAP method hint)", methodTimeout); 14508dbcf02cSchristos return methodTimeout; 14518dbcf02cSchristos } 14528dbcf02cSchristos 14538dbcf02cSchristos /* 14548dbcf02cSchristos * RFC 3748 recommends algorithms described in RFC 2988 for estimation 14558dbcf02cSchristos * of the retransmission timeout. This should be implemented once 14568dbcf02cSchristos * round-trip time measurements are available. For nowm a simple 14578dbcf02cSchristos * backoff mechanism is used instead if there are no EAP method 14588dbcf02cSchristos * specific hints. 14598dbcf02cSchristos * 14608dbcf02cSchristos * SRTT = smoothed round-trip time 14618dbcf02cSchristos * RTTVAR = round-trip time variation 14628dbcf02cSchristos * RTO = retransmission timeout 14638dbcf02cSchristos */ 14648dbcf02cSchristos 14658dbcf02cSchristos /* 14668dbcf02cSchristos * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for 14678dbcf02cSchristos * initial retransmission and then double the RTO to provide back off 14688dbcf02cSchristos * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 14698dbcf02cSchristos * modified RTOmax. 14708dbcf02cSchristos */ 14718dbcf02cSchristos rto = 3; 14728dbcf02cSchristos for (i = 0; i < retransCount; i++) { 14738dbcf02cSchristos rto *= 2; 14748dbcf02cSchristos if (rto >= 20) { 14758dbcf02cSchristos rto = 20; 14768dbcf02cSchristos break; 14778dbcf02cSchristos } 14788dbcf02cSchristos } 14798dbcf02cSchristos 14808dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 14818dbcf02cSchristos "(from dynamic back off; retransCount=%d)", 14828dbcf02cSchristos rto, retransCount); 14838dbcf02cSchristos 14848dbcf02cSchristos return rto; 14858dbcf02cSchristos } 14868dbcf02cSchristos 14878dbcf02cSchristos 14888dbcf02cSchristos static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) 14898dbcf02cSchristos { 14908dbcf02cSchristos const struct eap_hdr *hdr; 14918dbcf02cSchristos size_t plen; 14928dbcf02cSchristos 14938dbcf02cSchristos /* parse rxResp, respId, respMethod */ 1494*45d3cc13Schristos sm->rxResp = false; 1495*45d3cc13Schristos sm->rxInitiate = false; 14968dbcf02cSchristos sm->respId = -1; 14978dbcf02cSchristos sm->respMethod = EAP_TYPE_NONE; 14988dbcf02cSchristos sm->respVendor = EAP_VENDOR_IETF; 14998dbcf02cSchristos sm->respVendorMethod = EAP_TYPE_NONE; 15008dbcf02cSchristos 15018dbcf02cSchristos if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { 15028dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " 15038dbcf02cSchristos "len=%lu", resp, 15048dbcf02cSchristos resp ? (unsigned long) wpabuf_len(resp) : 0); 15058dbcf02cSchristos return; 15068dbcf02cSchristos } 15078dbcf02cSchristos 15088dbcf02cSchristos hdr = wpabuf_head(resp); 15098dbcf02cSchristos plen = be_to_host16(hdr->length); 15108dbcf02cSchristos if (plen > wpabuf_len(resp)) { 15118dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " 15128dbcf02cSchristos "(len=%lu plen=%lu)", 15138dbcf02cSchristos (unsigned long) wpabuf_len(resp), 15148dbcf02cSchristos (unsigned long) plen); 15158dbcf02cSchristos return; 15168dbcf02cSchristos } 15178dbcf02cSchristos 15188dbcf02cSchristos sm->respId = hdr->identifier; 15198dbcf02cSchristos 15208dbcf02cSchristos if (hdr->code == EAP_CODE_RESPONSE) 1521*45d3cc13Schristos sm->rxResp = true; 1522bb610346Schristos else if (hdr->code == EAP_CODE_INITIATE) 1523*45d3cc13Schristos sm->rxInitiate = true; 15248dbcf02cSchristos 15258dbcf02cSchristos if (plen > sizeof(*hdr)) { 15268dbcf02cSchristos u8 *pos = (u8 *) (hdr + 1); 15278dbcf02cSchristos sm->respMethod = *pos++; 15288dbcf02cSchristos if (sm->respMethod == EAP_TYPE_EXPANDED) { 15298dbcf02cSchristos if (plen < sizeof(*hdr) + 8) { 15308dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " 15318dbcf02cSchristos "expanded EAP-Packet (plen=%lu)", 15328dbcf02cSchristos (unsigned long) plen); 15338dbcf02cSchristos return; 15348dbcf02cSchristos } 15358dbcf02cSchristos sm->respVendor = WPA_GET_BE24(pos); 15368dbcf02cSchristos pos += 3; 15378dbcf02cSchristos sm->respVendorMethod = WPA_GET_BE32(pos); 15388dbcf02cSchristos } 15398dbcf02cSchristos } 15408dbcf02cSchristos 1541bb610346Schristos wpa_printf(MSG_DEBUG, 1542bb610346Schristos "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u", 1543bb610346Schristos sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod, 1544bb610346Schristos sm->respVendor, sm->respVendorMethod); 15458dbcf02cSchristos } 15468dbcf02cSchristos 15478dbcf02cSchristos 15488dbcf02cSchristos static int eap_sm_getId(const struct wpabuf *data) 15498dbcf02cSchristos { 15508dbcf02cSchristos const struct eap_hdr *hdr; 15518dbcf02cSchristos 15528dbcf02cSchristos if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) 15538dbcf02cSchristos return -1; 15548dbcf02cSchristos 15558dbcf02cSchristos hdr = wpabuf_head(data); 15568dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); 15578dbcf02cSchristos return hdr->identifier; 15588dbcf02cSchristos } 15598dbcf02cSchristos 15608dbcf02cSchristos 15618dbcf02cSchristos static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) 15628dbcf02cSchristos { 15638dbcf02cSchristos struct wpabuf *msg; 15648dbcf02cSchristos struct eap_hdr *resp; 15658dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); 15668dbcf02cSchristos 15678dbcf02cSchristos msg = wpabuf_alloc(sizeof(*resp)); 15688dbcf02cSchristos if (msg == NULL) 15698dbcf02cSchristos return NULL; 15708dbcf02cSchristos resp = wpabuf_put(msg, sizeof(*resp)); 15718dbcf02cSchristos resp->code = EAP_CODE_SUCCESS; 15728dbcf02cSchristos resp->identifier = id; 15738dbcf02cSchristos resp->length = host_to_be16(sizeof(*resp)); 15748dbcf02cSchristos 15758dbcf02cSchristos return msg; 15768dbcf02cSchristos } 15778dbcf02cSchristos 15788dbcf02cSchristos 15798dbcf02cSchristos static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) 15808dbcf02cSchristos { 15818dbcf02cSchristos struct wpabuf *msg; 15828dbcf02cSchristos struct eap_hdr *resp; 15838dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); 15848dbcf02cSchristos 15858dbcf02cSchristos msg = wpabuf_alloc(sizeof(*resp)); 15868dbcf02cSchristos if (msg == NULL) 15878dbcf02cSchristos return NULL; 15888dbcf02cSchristos resp = wpabuf_put(msg, sizeof(*resp)); 15898dbcf02cSchristos resp->code = EAP_CODE_FAILURE; 15908dbcf02cSchristos resp->identifier = id; 15918dbcf02cSchristos resp->length = host_to_be16(sizeof(*resp)); 15928dbcf02cSchristos 15938dbcf02cSchristos return msg; 15948dbcf02cSchristos } 15958dbcf02cSchristos 15968dbcf02cSchristos 15978dbcf02cSchristos static int eap_sm_nextId(struct eap_sm *sm, int id) 15988dbcf02cSchristos { 15998dbcf02cSchristos if (id < 0) { 16008dbcf02cSchristos /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a 16018dbcf02cSchristos * random number */ 16028dbcf02cSchristos id = rand() & 0xff; 16038dbcf02cSchristos if (id != sm->lastId) 16048dbcf02cSchristos return id; 16058dbcf02cSchristos } 16068dbcf02cSchristos return (id + 1) & 0xff; 16078dbcf02cSchristos } 16088dbcf02cSchristos 16098dbcf02cSchristos 16108dbcf02cSchristos /** 16118dbcf02cSchristos * eap_sm_process_nak - Process EAP-Response/Nak 16128dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 16138dbcf02cSchristos * @nak_list: Nak list (allowed methods) from the supplicant 16148dbcf02cSchristos * @len: Length of nak_list in bytes 16158dbcf02cSchristos * 16168dbcf02cSchristos * This function is called when EAP-Response/Nak is received from the 16178dbcf02cSchristos * supplicant. This can happen for both phase 1 and phase 2 authentications. 16188dbcf02cSchristos */ 16198dbcf02cSchristos void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) 16208dbcf02cSchristos { 16218dbcf02cSchristos int i; 16228dbcf02cSchristos size_t j; 16238dbcf02cSchristos 16248dbcf02cSchristos if (sm->user == NULL) 16258dbcf02cSchristos return; 16268dbcf02cSchristos 16278dbcf02cSchristos wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " 16288dbcf02cSchristos "index %d)", sm->user_eap_method_index); 16298dbcf02cSchristos 16308dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", 16318dbcf02cSchristos (u8 *) sm->user->methods, 16328dbcf02cSchristos EAP_MAX_METHODS * sizeof(sm->user->methods[0])); 16338dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", 16348dbcf02cSchristos nak_list, len); 16358dbcf02cSchristos 16368dbcf02cSchristos i = sm->user_eap_method_index; 16378dbcf02cSchristos while (i < EAP_MAX_METHODS && 16388dbcf02cSchristos (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 16398dbcf02cSchristos sm->user->methods[i].method != EAP_TYPE_NONE)) { 16408dbcf02cSchristos if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) 16418dbcf02cSchristos goto not_found; 16428dbcf02cSchristos for (j = 0; j < len; j++) { 16438dbcf02cSchristos if (nak_list[j] == sm->user->methods[i].method) { 16448dbcf02cSchristos break; 16458dbcf02cSchristos } 16468dbcf02cSchristos } 16478dbcf02cSchristos 16488dbcf02cSchristos if (j < len) { 16498dbcf02cSchristos /* found */ 16508dbcf02cSchristos i++; 16518dbcf02cSchristos continue; 16528dbcf02cSchristos } 16538dbcf02cSchristos 16548dbcf02cSchristos not_found: 16558dbcf02cSchristos /* not found - remove from the list */ 1656111b9fd8Schristos if (i + 1 < EAP_MAX_METHODS) { 1657111b9fd8Schristos os_memmove(&sm->user->methods[i], 1658111b9fd8Schristos &sm->user->methods[i + 1], 16598dbcf02cSchristos (EAP_MAX_METHODS - i - 1) * 16608dbcf02cSchristos sizeof(sm->user->methods[0])); 1661111b9fd8Schristos } 16628dbcf02cSchristos sm->user->methods[EAP_MAX_METHODS - 1].vendor = 16638dbcf02cSchristos EAP_VENDOR_IETF; 16648dbcf02cSchristos sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; 16658dbcf02cSchristos } 16668dbcf02cSchristos 16678dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", 16688dbcf02cSchristos (u8 *) sm->user->methods, EAP_MAX_METHODS * 16698dbcf02cSchristos sizeof(sm->user->methods[0])); 16708dbcf02cSchristos } 16718dbcf02cSchristos 16728dbcf02cSchristos 16738dbcf02cSchristos static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 16748dbcf02cSchristos size_t len) 16758dbcf02cSchristos { 16768dbcf02cSchristos if (nak_list == NULL || sm == NULL || sm->user == NULL) 16778dbcf02cSchristos return; 16788dbcf02cSchristos 16798dbcf02cSchristos if (sm->user->phase2) { 16808dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" 16818dbcf02cSchristos " info was selected - reject"); 16828dbcf02cSchristos sm->decision = DECISION_FAILURE; 16838dbcf02cSchristos return; 16848dbcf02cSchristos } 16858dbcf02cSchristos 16868dbcf02cSchristos eap_sm_process_nak(sm, nak_list, len); 16878dbcf02cSchristos } 16888dbcf02cSchristos 16898dbcf02cSchristos 1690*45d3cc13Schristos static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) 16918dbcf02cSchristos { 1692*45d3cc13Schristos enum eap_type next; 16938dbcf02cSchristos int idx = sm->user_eap_method_index; 16948dbcf02cSchristos 16958dbcf02cSchristos /* In theory, there should be no problems with starting 16968dbcf02cSchristos * re-authentication with something else than EAP-Request/Identity and 16978dbcf02cSchristos * this does indeed work with wpa_supplicant. However, at least Funk 16988dbcf02cSchristos * Supplicant seemed to ignore re-auth if it skipped 16998dbcf02cSchristos * EAP-Request/Identity. 17008dbcf02cSchristos * Re-auth sets currentId == -1, so that can be used here to select 17018dbcf02cSchristos * whether Identity needs to be requested again. */ 17028dbcf02cSchristos if (sm->identity == NULL || sm->currentId == -1) { 17038dbcf02cSchristos *vendor = EAP_VENDOR_IETF; 17048dbcf02cSchristos next = EAP_TYPE_IDENTITY; 1705*45d3cc13Schristos sm->update_user = true; 17068dbcf02cSchristos } else if (sm->user && idx < EAP_MAX_METHODS && 17078dbcf02cSchristos (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || 17088dbcf02cSchristos sm->user->methods[idx].method != EAP_TYPE_NONE)) { 17098dbcf02cSchristos *vendor = sm->user->methods[idx].vendor; 17108dbcf02cSchristos next = sm->user->methods[idx].method; 17118dbcf02cSchristos sm->user_eap_method_index++; 17128dbcf02cSchristos } else { 17138dbcf02cSchristos *vendor = EAP_VENDOR_IETF; 17148dbcf02cSchristos next = EAP_TYPE_NONE; 17158dbcf02cSchristos } 17168dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", 17178dbcf02cSchristos *vendor, next); 17188dbcf02cSchristos return next; 17198dbcf02cSchristos } 17208dbcf02cSchristos 17218dbcf02cSchristos 17228dbcf02cSchristos static int eap_sm_Policy_getDecision(struct eap_sm *sm) 17238dbcf02cSchristos { 1724*45d3cc13Schristos if (!sm->cfg->eap_server && sm->identity && !sm->start_reauth) { 17258dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); 17268dbcf02cSchristos return DECISION_PASSTHROUGH; 17278dbcf02cSchristos } 17288dbcf02cSchristos 17298dbcf02cSchristos if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && 17308dbcf02cSchristos sm->m->isSuccess(sm, sm->eap_method_priv)) { 17318dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " 17328dbcf02cSchristos "SUCCESS"); 1733*45d3cc13Schristos sm->update_user = true; 17348dbcf02cSchristos return DECISION_SUCCESS; 17358dbcf02cSchristos } 17368dbcf02cSchristos 17378dbcf02cSchristos if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && 17388dbcf02cSchristos !sm->m->isSuccess(sm, sm->eap_method_priv)) { 17398dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " 17408dbcf02cSchristos "FAILURE"); 1741*45d3cc13Schristos sm->update_user = true; 17428dbcf02cSchristos return DECISION_FAILURE; 17438dbcf02cSchristos } 17448dbcf02cSchristos 17458dbcf02cSchristos if ((sm->user == NULL || sm->update_user) && sm->identity && 17468dbcf02cSchristos !sm->start_reauth) { 17478dbcf02cSchristos /* 17488dbcf02cSchristos * Allow Identity method to be started once to allow identity 17498dbcf02cSchristos * selection hint to be sent from the authentication server, 17508dbcf02cSchristos * but prevent a loop of Identity requests by only allowing 17518dbcf02cSchristos * this to happen once. 17528dbcf02cSchristos */ 17538dbcf02cSchristos int id_req = 0; 17548dbcf02cSchristos if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && 17558dbcf02cSchristos sm->user->methods[0].vendor == EAP_VENDOR_IETF && 17568dbcf02cSchristos sm->user->methods[0].method == EAP_TYPE_IDENTITY) 17578dbcf02cSchristos id_req = 1; 17588dbcf02cSchristos if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { 17598dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " 17608dbcf02cSchristos "found from database -> FAILURE"); 17618dbcf02cSchristos return DECISION_FAILURE; 17628dbcf02cSchristos } 17638dbcf02cSchristos if (id_req && sm->user && 17648dbcf02cSchristos sm->user->methods[0].vendor == EAP_VENDOR_IETF && 17658dbcf02cSchristos sm->user->methods[0].method == EAP_TYPE_IDENTITY) { 17668dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " 17678dbcf02cSchristos "identity request loop -> FAILURE"); 1768*45d3cc13Schristos sm->update_user = true; 17698dbcf02cSchristos return DECISION_FAILURE; 17708dbcf02cSchristos } 1771*45d3cc13Schristos sm->update_user = false; 17728dbcf02cSchristos } 1773*45d3cc13Schristos sm->start_reauth = false; 17748dbcf02cSchristos 17758dbcf02cSchristos if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 17768dbcf02cSchristos (sm->user->methods[sm->user_eap_method_index].vendor != 17778dbcf02cSchristos EAP_VENDOR_IETF || 17788dbcf02cSchristos sm->user->methods[sm->user_eap_method_index].method != 17798dbcf02cSchristos EAP_TYPE_NONE)) { 17808dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " 17818dbcf02cSchristos "available -> CONTINUE"); 17828dbcf02cSchristos return DECISION_CONTINUE; 17838dbcf02cSchristos } 17848dbcf02cSchristos 1785bb610346Schristos if (!sm->identity && eap_get_erp_send_reauth_start(sm) && 1786bb610346Schristos !sm->initiate_reauth_start_sent) { 1787bb610346Schristos wpa_printf(MSG_DEBUG, 1788bb610346Schristos "EAP: getDecision: send EAP-Initiate/Re-auth-Start"); 1789bb610346Schristos return DECISION_INITIATE_REAUTH_START; 1790bb610346Schristos } 1791bb610346Schristos 17928dbcf02cSchristos if (sm->identity == NULL || sm->currentId == -1) { 17938dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " 17948dbcf02cSchristos "yet -> CONTINUE"); 17958dbcf02cSchristos return DECISION_CONTINUE; 17968dbcf02cSchristos } 17978dbcf02cSchristos 17988dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " 17998dbcf02cSchristos "FAILURE"); 18008dbcf02cSchristos return DECISION_FAILURE; 18018dbcf02cSchristos } 18028dbcf02cSchristos 18038dbcf02cSchristos 1804*45d3cc13Schristos static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method) 18058dbcf02cSchristos { 1806*45d3cc13Schristos return method == EAP_TYPE_IDENTITY; 18078dbcf02cSchristos } 18088dbcf02cSchristos 18098dbcf02cSchristos 18108dbcf02cSchristos /** 18118dbcf02cSchristos * eap_server_sm_step - Step EAP server state machine 18128dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 18138dbcf02cSchristos * Returns: 1 if EAP state was changed or 0 if not 18148dbcf02cSchristos * 18158dbcf02cSchristos * This function advances EAP state machine to a new state to match with the 18168dbcf02cSchristos * current variables. This should be called whenever variables used by the EAP 18178dbcf02cSchristos * state machine have changed. 18188dbcf02cSchristos */ 18198dbcf02cSchristos int eap_server_sm_step(struct eap_sm *sm) 18208dbcf02cSchristos { 18218dbcf02cSchristos int res = 0; 18228dbcf02cSchristos do { 1823*45d3cc13Schristos sm->changed = false; 18248dbcf02cSchristos SM_STEP_RUN(EAP); 18258dbcf02cSchristos if (sm->changed) 18268dbcf02cSchristos res = 1; 18278dbcf02cSchristos } while (sm->changed); 18288dbcf02cSchristos return res; 18298dbcf02cSchristos } 18308dbcf02cSchristos 18318dbcf02cSchristos 1832460bb4fcSchristos void eap_user_free(struct eap_user *user) 18338dbcf02cSchristos { 18348dbcf02cSchristos if (user == NULL) 18358dbcf02cSchristos return; 18363c260e60Schristos bin_clear_free(user->password, user->password_len); 18378dbcf02cSchristos user->password = NULL; 1838be6b3c4dSchristos bin_clear_free(user->salt, user->salt_len); 1839be6b3c4dSchristos user->salt = NULL; 18408dbcf02cSchristos os_free(user); 18418dbcf02cSchristos } 18428dbcf02cSchristos 18438dbcf02cSchristos 18448dbcf02cSchristos /** 18458dbcf02cSchristos * eap_server_sm_init - Allocate and initialize EAP server state machine 18468dbcf02cSchristos * @eapol_ctx: Context data to be used with eapol_cb calls 18478dbcf02cSchristos * @eapol_cb: Pointer to EAPOL callback functions 18488dbcf02cSchristos * @conf: EAP configuration 18498dbcf02cSchristos * Returns: Pointer to the allocated EAP state machine or %NULL on failure 18508dbcf02cSchristos * 18518dbcf02cSchristos * This function allocates and initializes an EAP state machine. 18528dbcf02cSchristos */ 18538dbcf02cSchristos struct eap_sm * eap_server_sm_init(void *eapol_ctx, 1854ecc36642Schristos const struct eapol_callbacks *eapol_cb, 1855*45d3cc13Schristos const struct eap_config *conf, 1856*45d3cc13Schristos const struct eap_session_data *sess) 18578dbcf02cSchristos { 18588dbcf02cSchristos struct eap_sm *sm; 18598dbcf02cSchristos 18608dbcf02cSchristos sm = os_zalloc(sizeof(*sm)); 18618dbcf02cSchristos if (sm == NULL) 18628dbcf02cSchristos return NULL; 18638dbcf02cSchristos sm->eapol_ctx = eapol_ctx; 18648dbcf02cSchristos sm->eapol_cb = eapol_cb; 18658dbcf02cSchristos sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ 1866*45d3cc13Schristos sm->cfg = conf; 1867*45d3cc13Schristos if (sess->assoc_wps_ie) 1868*45d3cc13Schristos sm->assoc_wps_ie = wpabuf_dup(sess->assoc_wps_ie); 1869*45d3cc13Schristos if (sess->assoc_p2p_ie) 1870*45d3cc13Schristos sm->assoc_p2p_ie = wpabuf_dup(sess->assoc_p2p_ie); 1871*45d3cc13Schristos if (sess->peer_addr) 1872*45d3cc13Schristos os_memcpy(sm->peer_addr, sess->peer_addr, ETH_ALEN); 18733c260e60Schristos #ifdef CONFIG_TESTING_OPTIONS 1874*45d3cc13Schristos sm->tls_test_flags = sess->tls_test_flags; 18753c260e60Schristos #endif /* CONFIG_TESTING_OPTIONS */ 18768dbcf02cSchristos 18778dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); 18788dbcf02cSchristos 18798dbcf02cSchristos return sm; 18808dbcf02cSchristos } 18818dbcf02cSchristos 18828dbcf02cSchristos 18838dbcf02cSchristos /** 18848dbcf02cSchristos * eap_server_sm_deinit - Deinitialize and free an EAP server state machine 18858dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 18868dbcf02cSchristos * 18878dbcf02cSchristos * This function deinitializes EAP state machine and frees all allocated 18888dbcf02cSchristos * resources. 18898dbcf02cSchristos */ 18908dbcf02cSchristos void eap_server_sm_deinit(struct eap_sm *sm) 18918dbcf02cSchristos { 18928dbcf02cSchristos if (sm == NULL) 18938dbcf02cSchristos return; 18948dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); 18958dbcf02cSchristos if (sm->m && sm->eap_method_priv) 18968dbcf02cSchristos sm->m->reset(sm, sm->eap_method_priv); 18978dbcf02cSchristos wpabuf_free(sm->eap_if.eapReqData); 18983c260e60Schristos bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); 1899bb610346Schristos os_free(sm->eap_if.eapSessionId); 19008dbcf02cSchristos wpabuf_free(sm->lastReqData); 19018dbcf02cSchristos wpabuf_free(sm->eap_if.eapRespData); 19028dbcf02cSchristos os_free(sm->identity); 1903be6b3c4dSchristos os_free(sm->serial_num); 19048dbcf02cSchristos wpabuf_free(sm->eap_if.aaaEapReqData); 19058dbcf02cSchristos wpabuf_free(sm->eap_if.aaaEapRespData); 19063c260e60Schristos bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen); 19078dbcf02cSchristos eap_user_free(sm->user); 19088dbcf02cSchristos wpabuf_free(sm->assoc_wps_ie); 1909111b9fd8Schristos wpabuf_free(sm->assoc_p2p_ie); 19108dbcf02cSchristos os_free(sm); 19118dbcf02cSchristos } 19128dbcf02cSchristos 19138dbcf02cSchristos 19148dbcf02cSchristos /** 19158dbcf02cSchristos * eap_sm_notify_cached - Notify EAP state machine of cached PMK 19168dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 19178dbcf02cSchristos * 19188dbcf02cSchristos * This function is called when PMKSA caching is used to skip EAP 19198dbcf02cSchristos * authentication. 19208dbcf02cSchristos */ 19218dbcf02cSchristos void eap_sm_notify_cached(struct eap_sm *sm) 19228dbcf02cSchristos { 19238dbcf02cSchristos if (sm == NULL) 19248dbcf02cSchristos return; 19258dbcf02cSchristos 19268dbcf02cSchristos sm->EAP_state = EAP_SUCCESS; 19278dbcf02cSchristos } 19288dbcf02cSchristos 19298dbcf02cSchristos 19308dbcf02cSchristos /** 19318dbcf02cSchristos * eap_sm_pending_cb - EAP state machine callback for a pending EAP request 19328dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 19338dbcf02cSchristos * 19348dbcf02cSchristos * This function is called when data for a pending EAP-Request is received. 19358dbcf02cSchristos */ 19368dbcf02cSchristos void eap_sm_pending_cb(struct eap_sm *sm) 19378dbcf02cSchristos { 19388dbcf02cSchristos if (sm == NULL) 19398dbcf02cSchristos return; 19408dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); 19418dbcf02cSchristos if (sm->method_pending == METHOD_PENDING_WAIT) 19428dbcf02cSchristos sm->method_pending = METHOD_PENDING_CONT; 19438dbcf02cSchristos } 19448dbcf02cSchristos 19458dbcf02cSchristos 19468dbcf02cSchristos /** 19478dbcf02cSchristos * eap_sm_method_pending - Query whether EAP method is waiting for pending data 19488dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 19498dbcf02cSchristos * Returns: 1 if method is waiting for pending data or 0 if not 19508dbcf02cSchristos */ 19518dbcf02cSchristos int eap_sm_method_pending(struct eap_sm *sm) 19528dbcf02cSchristos { 19538dbcf02cSchristos if (sm == NULL) 19548dbcf02cSchristos return 0; 19558dbcf02cSchristos return sm->method_pending == METHOD_PENDING_WAIT; 19568dbcf02cSchristos } 19578dbcf02cSchristos 19588dbcf02cSchristos 19598dbcf02cSchristos /** 19608dbcf02cSchristos * eap_get_identity - Get the user identity (from EAP-Response/Identity) 19618dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 19628dbcf02cSchristos * @len: Buffer for returning identity length 19638dbcf02cSchristos * Returns: Pointer to the user identity or %NULL if not available 19648dbcf02cSchristos */ 19658dbcf02cSchristos const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) 19668dbcf02cSchristos { 19678dbcf02cSchristos *len = sm->identity_len; 19688dbcf02cSchristos return sm->identity; 19698dbcf02cSchristos } 19708dbcf02cSchristos 19718dbcf02cSchristos 19728dbcf02cSchristos /** 1973be6b3c4dSchristos * eap_get_serial_num - Get the serial number of user certificate 1974be6b3c4dSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1975be6b3c4dSchristos * Returns: Pointer to the serial number or %NULL if not available 1976be6b3c4dSchristos */ 1977be6b3c4dSchristos const char * eap_get_serial_num(struct eap_sm *sm) 1978be6b3c4dSchristos { 1979be6b3c4dSchristos return sm->serial_num; 1980be6b3c4dSchristos } 1981be6b3c4dSchristos 1982be6b3c4dSchristos 1983460bb4fcSchristos /** 1984460bb4fcSchristos * eap_get_method - Get the used EAP method 1985460bb4fcSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1986460bb4fcSchristos * Returns: Pointer to the method name or %NULL if not available 1987460bb4fcSchristos */ 1988460bb4fcSchristos const char * eap_get_method(struct eap_sm *sm) 1989460bb4fcSchristos { 1990460bb4fcSchristos if (!sm || !sm->m) 1991460bb4fcSchristos return NULL; 1992460bb4fcSchristos return sm->m->name; 1993460bb4fcSchristos } 1994460bb4fcSchristos 1995460bb4fcSchristos 1996460bb4fcSchristos /** 1997460bb4fcSchristos * eap_get_imsi - Get IMSI of the user 1998460bb4fcSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1999460bb4fcSchristos * Returns: Pointer to IMSI or %NULL if not available 2000460bb4fcSchristos */ 2001460bb4fcSchristos const char * eap_get_imsi(struct eap_sm *sm) 2002460bb4fcSchristos { 2003460bb4fcSchristos if (!sm || sm->imsi[0] == '\0') 2004460bb4fcSchristos return NULL; 2005460bb4fcSchristos return sm->imsi; 2006460bb4fcSchristos } 2007460bb4fcSchristos 2008460bb4fcSchristos 2009be6b3c4dSchristos void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len) 2010be6b3c4dSchristos { 2011be6b3c4dSchristos #ifdef CONFIG_ERP 2012be6b3c4dSchristos const struct eap_hdr *hdr; 2013be6b3c4dSchristos const u8 *pos, *end; 2014be6b3c4dSchristos struct erp_tlvs parse; 2015be6b3c4dSchristos 2016be6b3c4dSchristos if (len < sizeof(*hdr) + 1) 2017be6b3c4dSchristos return; 2018be6b3c4dSchristos hdr = (const struct eap_hdr *) eap; 2019be6b3c4dSchristos end = eap + len; 2020be6b3c4dSchristos pos = (const u8 *) (hdr + 1); 2021be6b3c4dSchristos if (hdr->code != EAP_CODE_INITIATE || *pos != EAP_ERP_TYPE_REAUTH) 2022be6b3c4dSchristos return; 2023be6b3c4dSchristos pos++; 2024be6b3c4dSchristos if (pos + 3 > end) 2025be6b3c4dSchristos return; 2026be6b3c4dSchristos 2027be6b3c4dSchristos /* Skip Flags and SEQ */ 2028be6b3c4dSchristos pos += 3; 2029be6b3c4dSchristos 2030be6b3c4dSchristos if (erp_parse_tlvs(pos, end, &parse, 1) < 0 || !parse.keyname) 2031be6b3c4dSchristos return; 2032be6b3c4dSchristos wpa_hexdump_ascii(MSG_DEBUG, 2033be6b3c4dSchristos "EAP: Update identity based on EAP-Initiate/Re-auth keyName-NAI", 2034be6b3c4dSchristos parse.keyname, parse.keyname_len); 2035be6b3c4dSchristos os_free(sm->identity); 2036be6b3c4dSchristos sm->identity = os_malloc(parse.keyname_len); 2037be6b3c4dSchristos if (sm->identity) { 2038be6b3c4dSchristos os_memcpy(sm->identity, parse.keyname, parse.keyname_len); 2039be6b3c4dSchristos sm->identity_len = parse.keyname_len; 2040be6b3c4dSchristos } else { 2041be6b3c4dSchristos sm->identity_len = 0; 2042be6b3c4dSchristos } 2043be6b3c4dSchristos #endif /* CONFIG_ERP */ 2044be6b3c4dSchristos } 2045be6b3c4dSchristos 2046be6b3c4dSchristos 2047be6b3c4dSchristos /** 20488dbcf02cSchristos * eap_get_interface - Get pointer to EAP-EAPOL interface data 20498dbcf02cSchristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 20508dbcf02cSchristos * Returns: Pointer to the EAP-EAPOL interface data 20518dbcf02cSchristos */ 20528dbcf02cSchristos struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) 20538dbcf02cSchristos { 20548dbcf02cSchristos return &sm->eap_if; 20558dbcf02cSchristos } 2056111b9fd8Schristos 2057111b9fd8Schristos 2058111b9fd8Schristos /** 2059111b9fd8Schristos * eap_server_clear_identity - Clear EAP identity information 2060111b9fd8Schristos * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 2061111b9fd8Schristos * 2062111b9fd8Schristos * This function can be used to clear the EAP identity information in the EAP 2063111b9fd8Schristos * server context. This allows the EAP/Identity method to be used again after 2064111b9fd8Schristos * EAPOL-Start or EAPOL-Logoff. 2065111b9fd8Schristos */ 2066111b9fd8Schristos void eap_server_clear_identity(struct eap_sm *sm) 2067111b9fd8Schristos { 2068111b9fd8Schristos os_free(sm->identity); 2069111b9fd8Schristos sm->identity = NULL; 2070111b9fd8Schristos } 2071ecc36642Schristos 2072ecc36642Schristos 2073ecc36642Schristos #ifdef CONFIG_TESTING_OPTIONS 2074ecc36642Schristos void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source, 2075ecc36642Schristos const u8 *username, size_t username_len, 2076ecc36642Schristos const u8 *challenge, const u8 *response) 2077ecc36642Schristos { 2078ecc36642Schristos char hex_challenge[30], hex_response[90], user[100]; 2079ecc36642Schristos 2080ecc36642Schristos /* Print out Challenge and Response in format supported by asleap. */ 2081ecc36642Schristos if (username) 2082ecc36642Schristos printf_encode(user, sizeof(user), username, username_len); 2083ecc36642Schristos else 2084ecc36642Schristos user[0] = '\0'; 2085ecc36642Schristos wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge), 2086ecc36642Schristos challenge, sizeof(challenge), ':'); 2087ecc36642Schristos wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24, 2088ecc36642Schristos ':'); 2089ecc36642Schristos wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s", 2090ecc36642Schristos source, user, hex_challenge, hex_response); 2091ecc36642Schristos } 2092ecc36642Schristos #endif /* CONFIG_TESTING_OPTIONS */ 2093*45d3cc13Schristos 2094*45d3cc13Schristos 2095*45d3cc13Schristos void eap_server_config_free(struct eap_config *cfg) 2096*45d3cc13Schristos { 2097*45d3cc13Schristos if (!cfg) 2098*45d3cc13Schristos return; 2099*45d3cc13Schristos os_free(cfg->pac_opaque_encr_key); 2100*45d3cc13Schristos os_free(cfg->eap_fast_a_id); 2101*45d3cc13Schristos os_free(cfg->eap_fast_a_id_info); 2102*45d3cc13Schristos os_free(cfg->server_id); 2103*45d3cc13Schristos os_free(cfg); 2104*45d3cc13Schristos } 2105