static struct wpabuf * eap_sim_process_notification( struct eap_sm *sm, struct eap_sim_data *data, u8 id, const struct wpabuf *reqData, struct eap_sim_attrs *attr) { wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification"); if (data->num_notification > 0) { wpa_printf(MSG_INFO, "EAP-SIM: too many notification " "rounds (only one allowed)"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } data->num_notification++; if (attr->notification == -1) { wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in " "Notification message"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if ((attr->notification & 0x4000) == 0 && eap_sim_process_notification_auth(data, reqData, attr)) { return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } eap_sim_report_notification(sm->msg_ctx, attr->notification, 0); if (attr->notification >= 0 && attr->notification < 32768) { eap_sim_state(data, FAILURE); } else if (attr->notification == EAP_SIM_SUCCESS && data->state == RESULT_SUCCESS) eap_sim_state(data, SUCCESS); return eap_sim_response_notification(data, id, attr->notification); }
static void eap_sim_process_notification(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) eap_sim_state(data, SUCCESS); else eap_sim_state(data, FAILURE); }
static void eap_sim_process_client_error(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", attr->client_error_code); if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) eap_sim_state(data, SUCCESS); else eap_sim_state(data, FAILURE); }
static void eap_sim_process_challenge(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, (u8 *) data->sres, data->num_chal * EAP_SIM_SRES_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " "did not include valid AT_MAC"); eap_sim_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " "correct AT_MAC"); if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_sim_state(data, NOTIFICATION); } else eap_sim_state(data, SUCCESS); identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { identity = sm->identity; identity_len = sm->identity_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } }
static void eap_sim_process_client_error(struct eap_sm *sm, struct eap_sim_data *data, u8 *respData, size_t respDataLen, struct eap_sim_attrs *attr) { wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", attr->client_error_code); eap_sim_state(data, FAILURE); }
static void * eap_sim_init(struct eap_sm *sm) { struct eap_sim_data *data; struct eap_peer_config *config = eap_get_config(sm); data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " "for NONCE_MT"); os_free(data); return NULL; } data->min_num_chal = 2; if (config && config->phase1) { char *pos = os_strstr(config->phase1, "sim_min_num_chal="); if (pos) { data->min_num_chal = atoi(pos + 17); if (data->min_num_chal < 2 || data->min_num_chal > 3) { wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " "sim_min_num_chal configuration " "(%lu, expected 2 or 3)", (unsigned long) data->min_num_chal); os_free(data); return NULL; } wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of " "challenges to %lu", (unsigned long) data->min_num_chal); } data->result_ind = os_strstr(config->phase1, "result_ind=1") != NULL; } if (config && config->anonymous_identity) { data->pseudonym = os_malloc(config->anonymous_identity_len); if (data->pseudonym) { os_memcpy(data->pseudonym, config->anonymous_identity, config->anonymous_identity_len); data->pseudonym_len = config->anonymous_identity_len; } } eap_sim_state(data, CONTINUE); return data; }
static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, int err) { struct eap_sim_msg *msg; eap_sim_state(data, FAILURE); data->num_id_req = 0; data->num_notification = 0; msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR); eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); return eap_sim_msg_finish(msg, NULL, NULL, 0); }
static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_sim_data *data = priv; if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " "for NONCE_MT"); os_free(data); return NULL; } data->num_id_req = 0; data->num_notification = 0; eap_sim_state(data, CONTINUE); return priv; }
static void eap_sim_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_sim_data *data = priv; const u8 *pos, *end; u8 subtype; size_t len; struct eap_sim_attrs attr; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); if (pos == NULL || len < 3) return; end = pos + len; subtype = *pos; pos += 3; if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); eap_sim_state(data, FAILURE); return; } if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { eap_sim_process_client_error(sm, data, respData, &attr); return; } switch (data->state) { case START: eap_sim_process_start(sm, data, respData, &attr); break; case CHALLENGE: eap_sim_process_challenge(sm, data, respData, &attr); break; case REAUTH: eap_sim_process_reauth(sm, data, respData, &attr); break; case NOTIFICATION: eap_sim_process_notification(sm, data, respData, &attr); break; default: wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " "process", data->state); break; } }
static void eap_sim_process(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { struct eap_sim_data *data = priv; struct eap_hdr *resp; u8 *pos, subtype; size_t len; struct eap_sim_attrs attr; resp = (struct eap_hdr *) respData; pos = (u8 *) (resp + 1); subtype = pos[1]; len = ntohs(resp->length); pos += 4; if (eap_sim_parse_attr(pos, respData + len, &attr, 0, 0)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); eap_sim_state(data, FAILURE); return; } if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { eap_sim_process_client_error(sm, data, respData, len, &attr); return; } switch (data->state) { case START: eap_sim_process_start(sm, data, respData, len, &attr); break; case CHALLENGE: eap_sim_process_challenge(sm, data, respData, len, &attr); break; case REAUTH: eap_sim_process_reauth(sm, data, respData, len, &attr); break; default: wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " "process", data->state); break; } }
static struct wpabuf * eap_sim_process_reauthentication( struct eap_sm *sm, struct eap_sim_data *data, u8 id, const struct wpabuf *reqData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted; wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication"); if (data->reauth_id == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying " "reauthentication, but no reauth_id available"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } data->reauth = 1; if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "did not have valid AT_MAC"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "message did not include encrypted data"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " "data from reauthentication message"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (eattr.nonce_s == NULL || eattr.counter < 0) { wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet", !eattr.nonce_s ? " AT_NONCE_S" : "", eattr.counter < 0 ? " AT_COUNTER" : ""); os_free(decrypted); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter " "(%d <= %d)", eattr.counter, data->counter); data->counter_too_small = eattr.counter; /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. * However, since it was used in the last EAP-Response-Identity * packet, it has to saved for the following fullauth to be * used in MK derivation. */ os_free(data->last_eap_identity); data->last_eap_identity = data->reauth_id; data->last_eap_identity_len = data->reauth_id_len; data->reauth_id = NULL; data->reauth_id_len = 0; os_free(decrypted); return eap_sim_response_reauth(data, id, 1); } data->counter = eattr.counter; os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S", data->nonce_s, EAP_SIM_NONCE_S_LEN); eap_sim_derive_keys_reauth(data->counter, data->reauth_id, data->reauth_id_len, data->nonce_s, data->mk, data->msk, data->emsk); eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); eap_sim_learn_ids(sm, data, &eattr); if (data->result_ind && attr->result_ind) data->use_result_ind = 1; if (data->state != FAILURE && data->state != RESULT_FAILURE) { eap_sim_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } data->num_id_req = 0; data->num_notification = 0; if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " "fast reauths performed - force fullauth"); eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); } os_free(decrypted); return eap_sim_response_reauth(data, id, 0); }
static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, struct eap_sim_data *data, u8 id, const struct wpabuf *reqData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; struct eap_sim_attrs eattr; wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge"); data->reauth = 0; if (!attr->mac || !attr->rand) { wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " "did not include%s%s", !attr->mac ? " AT_MAC" : "", !attr->rand ? " AT_RAND" : ""); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges", (unsigned long) attr->num_chal); if (attr->num_chal < data->min_num_chal) { wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of " "challenges (%lu)", (unsigned long) attr->num_chal); return eap_sim_client_error(data, id, EAP_SIM_INSUFFICIENT_NUM_OF_CHAL); } if (attr->num_chal > 3) { wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges " "(%lu)", (unsigned long) attr->num_chal); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } /* Verify that RANDs are different */ if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN, GSM_RAND_LEN) == 0 || (attr->num_chal > 2 && (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN, GSM_RAND_LEN) == 0 || os_memcmp(attr->rand + GSM_RAND_LEN, attr->rand + 2 * GSM_RAND_LEN, GSM_RAND_LEN) == 0))) { wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times"); return eap_sim_client_error(data, id, EAP_SIM_RAND_NOT_FRESH); } os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN); data->num_chal = attr->num_chal; if (eap_sim_gsm_auth(sm, data)) { wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } if (data->last_eap_identity) { identity = data->last_eap_identity; identity_len = data->last_eap_identity_len; } else if (data->pseudonym) { identity = data->pseudonym; identity_len = data->pseudonym_len; } else identity = eap_get_config_identity(sm, &identity_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " "derivation", identity, identity_len); eap_sim_derive_mk(identity, identity_len, data->nonce_mt, data->selected_version, data->ver_list, data->ver_list_len, data->num_chal, (const u8 *) data->kc, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " "used invalid AT_MAC"); return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } /* Old reauthentication identity must not be used anymore. In * other words, if no new reauth identity is received, full * authentication will be used on next reauthentication (using * pseudonym identity or permanent identity). */ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); if (attr->encr_data) { u8 *decrypted; decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { return eap_sim_client_error( data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } eap_sim_learn_ids(sm, data, &eattr); os_free(decrypted); } if (data->result_ind && attr->result_ind) data->use_result_ind = 1; if (data->state != FAILURE && data->state != RESULT_FAILURE) { eap_sim_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } data->num_id_req = 0; data->num_notification = 0; /* RFC 4186 specifies that counter is initialized to one after * fullauth, but initializing it to zero makes it easier to implement * reauth verification. */ data->counter = 0; return eap_sim_response_challenge(data, id); }
static void eap_sim_process_reauth(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted = NULL; const u8 *identity, *id2; size_t identity_len, id2_len; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, EAP_SIM_NONCE_S_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "did not include valid AT_MAC"); goto fail; } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "message did not include encrypted data"); goto fail; } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " "data from reauthentication message"); goto fail; } if (eattr.counter != data->counter) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "used incorrect counter %u, expected %u", eattr.counter, data->counter); goto fail; } os_free(decrypted); decrypted = NULL; wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " "the correct AT_MAC"); if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_sim_state(data, NOTIFICATION); } else eap_sim_state(data, SUCCESS); if (data->reauth) { identity = data->reauth->identity; identity_len = data->reauth->identity_len; } else { identity = sm->identity; identity_len = sm->identity_len; } id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, identity_len, &id2_len); if (id2) { identity = id2; identity_len = id2_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } else { eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; } return; fail: eap_sim_state(data, FAILURE); eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; os_free(decrypted); }
static void eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; u8 ver_list[2]; wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); if (attr->identity) { os_free(sm->identity); sm->identity = os_malloc(attr->identity_len); if (sm->identity) { os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; } } identity = NULL; identity_len = 0; if (sm->identity && sm->identity_len > 0 && sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) { identity = sm->identity; identity_len = sm->identity_len; } else { identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { data->reauth = eap_sim_db_get_reauth_entry( sm->eap_sim_db_priv, sm->identity, sm->identity_len); if (data->reauth) { wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast " "re-authentication"); identity = data->reauth->identity; identity_len = data->reauth->identity_len; data->counter = data->reauth->counter; os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); } } } if (identity == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent" " user name"); eap_sim_state(data, FAILURE); return; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", identity, identity_len); if (data->reauth) { eap_sim_state(data, REAUTH); return; } if (attr->nonce_mt == NULL || attr->selected_version < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " "required attributes"); eap_sim_state(data, FAILURE); return; } if (!eap_sim_supported_ver(data, attr->selected_version)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " "version %d", attr->selected_version); eap_sim_state(data, FAILURE); return; } data->counter = 0; /* reset re-auth counter since this is full auth */ data->reauth = NULL; data->num_chal = eap_sim_db_get_gsm_triplets( sm->eap_sim_db_priv, identity, identity_len, EAP_SIM_MAX_CHAL, (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); if (data->num_chal == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " "not yet available - pending request"); sm->method_pending = METHOD_PENDING_WAIT; return; } if (data->num_chal < 2) { wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " "authentication triplets for the peer"); eap_sim_state(data, FAILURE); return; } identity_len = sm->identity_len; while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " "character from identity"); identity_len--; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", sm->identity, identity_len); os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, attr->selected_version, ver_list, sizeof(ver_list), data->num_chal, (const u8 *) data->kc, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); eap_sim_state(data, CHALLENGE); }
static void eap_sim_process_reauth(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted = NULL; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, EAP_SIM_NONCE_S_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "did not include valid AT_MAC"); goto fail; } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "message did not include encrypted data"); goto fail; } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " "data from reauthentication message"); goto fail; } if (eattr.counter != data->counter) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "used incorrect counter %u, expected %u", eattr.counter, data->counter); goto fail; } os_free(decrypted); decrypted = NULL; wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " "the correct AT_MAC"); if (eattr.counter_too_small) { wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " "included AT_COUNTER_TOO_SMALL - starting full " "authentication"); data->start_round = -1; eap_sim_state(data, START); return; } if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_sim_state(data, NOTIFICATION); } else eap_sim_state(data, SUCCESS); if (data->next_reauth_id) { eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } else { eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; } return; fail: data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_sim_state(data, NOTIFICATION); eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; os_free(decrypted); }
static void eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { size_t identity_len; u8 ver_list[2]; u8 *new_identity; char *username; wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); if (data->start_round == 0) { /* * Special case for AT_COUNTER_TOO_SMALL recovery - no identity * was requested since we already know it. */ goto skip_id_update; } /* * We always request identity in SIM/Start, so the peer is required to * have replied with one. */ if (!attr->identity || attr->identity_len == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " "identity"); goto failed; } new_identity = os_malloc(attr->identity_len); if (new_identity == NULL) goto failed; os_free(sm->identity); sm->identity = new_identity; os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", sm->identity, sm->identity_len); username = sim_get_username(sm->identity, sm->identity_len); if (username == NULL) goto failed; if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) { wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'", username); data->reauth = eap_sim_db_get_reauth_entry( sm->eap_sim_db_priv, username); os_free(username); if (data->reauth == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth " "identity - request full auth identity"); /* Remain in START state for another round */ return; } wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); os_strlcpy(data->permanent, data->reauth->permanent, sizeof(data->permanent)); data->counter = data->reauth->counter; os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); eap_sim_state(data, REAUTH); return; } if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) { const char *permanent; wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'", username); permanent = eap_sim_db_get_permanent( sm->eap_sim_db_priv, username); os_free(username); if (permanent == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym " "identity - request permanent identity"); /* Remain in START state for another round */ return; } os_strlcpy(data->permanent, permanent, sizeof(data->permanent)); } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) { wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'", username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", username); os_free(username); goto failed; } skip_id_update: /* Full authentication */ if (attr->nonce_mt == NULL || attr->selected_version < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " "required attributes"); goto failed; } if (!eap_sim_supported_ver(data, attr->selected_version)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " "version %d", attr->selected_version); goto failed; } data->counter = 0; /* reset re-auth counter since this is full auth */ data->reauth = NULL; data->num_chal = eap_sim_db_get_gsm_triplets( sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL, (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); if (data->num_chal == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " "not yet available - pending request"); sm->method_pending = METHOD_PENDING_WAIT; return; } if (data->num_chal < 2) { wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " "authentication triplets for the peer"); goto failed; } identity_len = sm->identity_len; while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " "character from identity"); identity_len--; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", sm->identity, identity_len); os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, attr->selected_version, ver_list, sizeof(ver_list), data->num_chal, (const u8 *) data->kc, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); eap_sim_state(data, CHALLENGE); return; failed: data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_sim_state(data, NOTIFICATION); }