Esempio n. 1
0
static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
                             struct eap_sim_attrs *attr)
{
    if (attr->next_pseudonym) {
        const u8 *identity = NULL;
        size_t identity_len = 0;
        const u8 *realm = NULL;
        size_t realm_len = 0;

        wpa_hexdump_ascii(MSG_DEBUG,
                          "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
                          attr->next_pseudonym,
                          attr->next_pseudonym_len);
        os_free(data->pseudonym);
        /* Look for the realm of the permanent identity */
        identity = eap_get_config_identity(sm, &identity_len);
        if (identity) {
            for (realm = identity, realm_len = identity_len;
                    realm_len > 0; realm_len--, realm++) {
                if (*realm == '@')
                    break;
            }
        }
        data->pseudonym = os_malloc(attr->next_pseudonym_len +
                                    realm_len);
        if (data->pseudonym == NULL) {
            wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
                       "next pseudonym");
            data->pseudonym_len = 0;
            return -1;
        }
        os_memcpy(data->pseudonym, attr->next_pseudonym,
                  attr->next_pseudonym_len);
        if (realm_len) {
            os_memcpy(data->pseudonym + attr->next_pseudonym_len,
                      realm, realm_len);
        }
        data->pseudonym_len = attr->next_pseudonym_len + realm_len;
    }

    if (attr->next_reauth_id) {
        os_free(data->reauth_id);
        data->reauth_id = os_malloc(attr->next_reauth_id_len);
        if (data->reauth_id == NULL) {
            wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
                       "next reauth_id");
            data->reauth_id_len = 0;
            return -1;
        }
        os_memcpy(data->reauth_id, attr->next_reauth_id,
                  attr->next_reauth_id_len);
        data->reauth_id_len = attr->next_reauth_id_len;
        wpa_hexdump_ascii(MSG_DEBUG,
                          "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
                          data->reauth_id,
                          data->reauth_id_len);
    }

    return 0;
}
static void * eap_pwd_init(struct eap_sm *sm)
{
	struct eap_pwd_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;

	password = eap_get_config_password(sm, &password_len);
	if (password == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
		return NULL;
	}

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
		return NULL;
	}

	if ((data = os_zalloc(sizeof(*data))) == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
		return NULL;
	}

	if ((data->bnctx = BN_CTX_new()) == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
		os_free(data);
		return NULL;
	}

	if ((data->id_peer = os_malloc(identity_len)) == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
		BN_CTX_free(data->bnctx);
		os_free(data);
		return NULL;
	}

	os_memcpy(data->id_peer, identity, identity_len);
	data->id_peer_len = identity_len;

	if ((data->password = os_malloc(password_len)) == NULL) {
		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
		BN_CTX_free(data->bnctx);
		os_free(data->id_peer);
		os_free(data);
		return NULL;
	}
	os_memcpy(data->password, password, password_len);
	data->password_len = password_len;

	data->out_frag_pos = data->in_frag_pos = 0;
	data->inbuf = data->outbuf = NULL;
	data->mtu = 1020; /* default from RFC 5931, make it configurable! */

	data->state = PWD_ID_Req;

	return data;
}
Esempio n. 3
0
/**
 * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 * @data: Pointer to private EAP method data from eap_mschapv2_init()
 * @ret: Return values from EAP request validation and processing
 * @req: Pointer to EAP-MSCHAPv2 header from the request
 * @req_len: Length of the EAP-MSCHAPv2 data
 * @id: EAP identifier used in the request
 * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
 * no reply available
 */
static struct wpabuf * eap_mschapv2_challenge(
	struct eap_sm *sm, struct eap_mschapv2_data *data,
	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
	size_t req_len, u8 id)
{
	size_t len, challenge_len;
	const u8 *pos, *challenge;

	if (eap_get_config_identity(sm, &len) == NULL ||
	    eap_get_config_password(sm, &len) == NULL)
		return NULL;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
	if (req_len < sizeof(*req) + 1) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
			   "(len %lu)", (unsigned long) req_len);
		ret->ignore = TRUE;
		return NULL;
	}
	pos = (const u8 *) (req + 1);
	challenge_len = *pos++;
	len = req_len - sizeof(*req) - 1;
	if (challenge_len != MSCHAPV2_CHAL_LEN) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
			   "%lu", (unsigned long) challenge_len);
		ret->ignore = TRUE;
		return NULL;
	}

	if (len < challenge_len) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
			   " packet: len=%lu challenge_len=%lu",
			   (unsigned long) len, (unsigned long) challenge_len);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->passwd_change_challenge_valid) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
			   "failure message");
		challenge = data->passwd_change_challenge;
	} else
		challenge = pos;
	pos += challenge_len;
	len -= challenge_len;
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
		    pos, len);

	ret->ignore = FALSE;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = TRUE;

	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
					    challenge);
}
Esempio n. 4
0
static u8 * eap_sim_response_start(struct eap_sm *sm,
				   struct eap_sim_data *data,
				   const struct eap_hdr *req,
				   size_t *respDataLen,
				   enum eap_sim_id_req id_req)
{
	const u8 *identity = NULL;
	size_t identity_len = 0;
	struct eap_sim_msg *msg;

	data->reauth = 0;
	if (id_req == ANY_ID && data->reauth_id) {
		identity = data->reauth_id;
		identity_len = data->reauth_id_len;
		data->reauth = 1;
	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
		   data->pseudonym) {
		identity = data->pseudonym;
		identity_len = data->pseudonym_len;
		eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
	} else if (id_req != NO_ID_REQ) {
		identity = eap_get_config_identity(sm, &identity_len);
		if (identity) {
			eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
						 CLEAR_REAUTH_ID);
		}
	}
	if (id_req != NO_ID_REQ)
		eap_sim_clear_identities(data, CLEAR_EAP_ID);

	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)",
		   req->identifier);
	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
	if (!data->reauth) {
		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
			   data->selected_version);
		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
				data->selected_version, NULL, 0);
	}

	if (identity) {
		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
				  identity, identity_len);
		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
				identity, identity_len);
	}

	return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
}
static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
				     struct eap_method_ret *ret,
				     const u8 *reqData, size_t *respDataLen)
{
	struct eap_leap_data *data = priv;
	const struct eap_hdr *req;
	struct eap_hdr *resp;
	u8 *pos;
	const u8 *identity;
	size_t identity_len;

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity == NULL)
		return NULL;

	if (data->state != LEAP_WAIT_SUCCESS) {
		wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
			   "unexpected state (%d) - ignored", data->state);
		ret->ignore = TRUE;
		return NULL;
	}

	req = (const struct eap_hdr *) reqData;

	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, respDataLen,
			     3 + LEAP_CHALLENGE_LEN + identity_len,
			     EAP_CODE_REQUEST, req->identifier, &pos);
	if (resp == NULL)
		return NULL;
	*pos++ = LEAP_VERSION;
	*pos++ = 0; /* unused */
	*pos++ = LEAP_CHALLENGE_LEN;
	if (hostapd_get_rand(pos, LEAP_CHALLENGE_LEN)) {
		wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
			   "for challenge");
		os_free(resp);
		ret->ignore = TRUE;
		return NULL;
	}
	os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
		    LEAP_CHALLENGE_LEN);
	pos += LEAP_CHALLENGE_LEN;
	os_memcpy(pos, identity, identity_len);

	data->state = LEAP_WAIT_RESPONSE;

	return (u8 *) resp;
}
Esempio n. 6
0
static void * eap_gpsk_init(struct eap_sm *sm)
{
	struct eap_gpsk_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;
	const char *phase1;

	password = eap_get_config_password(sm, &password_len);
	if (password == NULL) {
		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = GPSK_1;

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity) {
		data->id_peer = os_malloc(identity_len);
		if (data->id_peer == NULL) {
			eap_gpsk_deinit(sm, data);
			return NULL;
		}
		os_memcpy(data->id_peer, identity, identity_len);
		data->id_peer_len = identity_len;
	}

	phase1 = eap_get_config_phase1(sm);
	if (phase1) {
		const char *pos;

		pos = os_strstr(phase1, "cipher=");
		if (pos) {
			data->forced_cipher = atoi(pos + 7);
			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
				   data->forced_cipher);
		}
	}

	data->psk = os_malloc(password_len);
	if (data->psk == NULL) {
		eap_gpsk_deinit(sm, data);
		return NULL;
	}
	os_memcpy(data->psk, password, password_len);
	data->psk_len = password_len;

	return data;
}
static void * eap_ikev2_init(struct eap_sm *sm)
{
	struct eap_ikev2_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;
	int fragment_size;

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity == NULL) {
		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = WAIT_START;
	fragment_size = eap_get_config_fragment_size(sm);
	if (fragment_size <= 0)
		data->fragment_size = IKEV2_FRAGMENT_SIZE;
	else
		data->fragment_size = fragment_size;
	data->ikev2.state = SA_INIT;
	data->ikev2.peer_auth = PEER_AUTH_SECRET;
	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
	if (data->ikev2.key_pad == NULL)
		goto failed;
	data->ikev2.key_pad_len = 21;
	data->ikev2.IDr = os_malloc(identity_len);
	if (data->ikev2.IDr == NULL)
		goto failed;
	os_memcpy(data->ikev2.IDr, identity, identity_len);
	data->ikev2.IDr_len = identity_len;

	password = eap_get_config_password(sm, &password_len);
	if (password) {
		data->ikev2.shared_secret = os_malloc(password_len);
		if (data->ikev2.shared_secret == NULL)
			goto failed;
		os_memcpy(data->ikev2.shared_secret, password, password_len);
		data->ikev2.shared_secret_len = password_len;
	}

	return data;

failed:
	ikev2_responder_deinit(&data->ikev2);
	os_free(data);
	return NULL;
}
Esempio n. 8
0
static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
						struct eap_method_ret *ret,
						const struct wpabuf *reqData)
{
	struct eap_leap_data *data = priv;
	struct wpabuf *resp;
	u8 *pos;
	const u8 *identity;
	size_t identity_len;

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity == NULL)
		return NULL;

	if (data->state != LEAP_WAIT_SUCCESS) {
		wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
			   "unexpected state (%d) - ignored", data->state);
		ret->ignore = TRUE;
		return NULL;
	}

	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
			     3 + LEAP_CHALLENGE_LEN + identity_len,
			     EAP_CODE_REQUEST, eap_get_id(reqData));
	if (resp == NULL)
		return NULL;
	wpabuf_put_u8(resp, LEAP_VERSION);
	wpabuf_put_u8(resp, 0); /* unused */
	wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
	pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
	if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) {
		wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
			   "for challenge");
		wpabuf_free(resp);
		ret->ignore = TRUE;
		return NULL;
	}
	os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
		    LEAP_CHALLENGE_LEN);
	wpabuf_put_data(resp, identity, identity_len);

	data->state = LEAP_WAIT_RESPONSE;

	return resp;
}
Esempio n. 9
0
static struct wpabuf * 
eap_mschapv2_challenge(
	struct eap_sm *sm, struct eap_mschapv2_data *data,
	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
	size_t req_len, u8 id)
{
	size_t len, challenge_len;
	const u8 *pos, *challenge;

	if (eap_get_config_identity(sm, &len) == NULL ||
	    eap_get_config_password(sm, &len) == NULL)
		return NULL;

	if (req_len < sizeof(*req) + 1) {
		ret->ignore = true;
		return NULL;
	}
	pos = (const u8 *)(req + 1);
	challenge_len = *pos++;
	len = req_len - sizeof(*req) - 1;
	if (challenge_len != MSCHAPV2_CHAL_LEN) {
		ret->ignore = true;
		return NULL;
	}

	if (len < challenge_len) {
		ret->ignore = true;
		return NULL;
	}

	if (data->passwd_change_challenge_valid)
		challenge = data->passwd_change_challenge;
	else
		challenge = pos;
	pos += challenge_len;
	len -= challenge_len;

	ret->ignore = false;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = true;

	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
					    challenge);
}
Esempio n. 10
0
static int eap_mschapv2_check_config(struct eap_sm *sm)
{
	size_t len;

	if (eap_get_config_identity(sm, &len) == NULL) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
		eap_sm_request_identity(sm);
		return -1;
	}

	if (eap_get_config_password(sm, &len) == NULL) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
		eap_sm_request_password(sm);
		return -1;
	}

	return 0;
}
Esempio n. 11
0
static u8 * eap_aka_response_identity(struct eap_sm *sm,
				      struct eap_aka_data *data,
				      const struct eap_hdr *req,
				      size_t *respDataLen,
				      enum eap_sim_id_req id_req)
{
	const u8 *identity = NULL;
	size_t identity_len = 0;
	struct eap_sim_msg *msg;

	data->reauth = 0;
	if (id_req == ANY_ID && data->reauth_id) {
		identity = data->reauth_id;
		identity_len = data->reauth_id_len;
		data->reauth = 1;
	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
		   data->pseudonym) {
		identity = data->pseudonym;
		identity_len = data->pseudonym_len;
		eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
	} else if (id_req != NO_ID_REQ) {
		identity = eap_get_config_identity(sm, &identity_len);
		if (identity) {
			eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
						 CLEAR_REAUTH_ID);
		}
	}
	if (id_req != NO_ID_REQ)
		eap_aka_clear_identities(data, CLEAR_EAP_ID);

	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)",
		   req->identifier);
	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
			       EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY);

	if (identity) {
		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
				  identity, identity_len);
		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
				identity, identity_len);
	}

	return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
}
Esempio n. 12
0
static void * eap_psk_init(struct eap_sm *sm)
{
	struct eap_psk_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;

	password = eap_get_config_password(sm, &password_len);
	if (!password || password_len != 16) {
		wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
			   "configured");
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	if (eap_psk_key_setup(password, data->ak, data->kdk)) {
		os_free(data);
		return NULL;
	}
	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
	data->state = PSK_INIT;

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity) {
		data->id_p = os_malloc(identity_len);
		if (data->id_p)
			os_memcpy(data->id_p, identity, identity_len);
		data->id_p_len = identity_len;
	}
	if (data->id_p == NULL) {
		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
		os_free(data);
		return NULL;
	}

	return data;
}
Esempio n. 13
0
static void * eap_gpsk_init(struct eap_sm *sm)
{
    struct eap_gpsk_data *data;
    const u8 *identity, *password;
    size_t identity_len, password_len;

    password = eap_get_config_password(sm, &password_len);
    if (password == NULL) {
        wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
        return NULL;
    }

    data = os_zalloc(sizeof(*data));
    if (data == NULL)
        return NULL;
    data->state = GPSK_1;

    identity = eap_get_config_identity(sm, &identity_len);
    if (identity) {
        data->id_peer = os_malloc(identity_len);
        if (data->id_peer == NULL) {
            eap_gpsk_deinit(sm, data);
            return NULL;
        }
        os_memcpy(data->id_peer, identity, identity_len);
        data->id_peer_len = identity_len;
    }

    data->psk = os_malloc(password_len);
    if (data->psk == NULL) {
        eap_gpsk_deinit(sm, data);
        return NULL;
    }
    os_memcpy(data->psk, password, password_len);
    data->psk_len = password_len;

    return data;
}
Esempio n. 14
0
static void * eap_sake_init(struct eap_sm *sm)
{
	struct eap_sake_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;

	password = eap_get_config_password(sm, &password_len);
	if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
		wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
			   "configured");
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = IDENTITY;

	identity = eap_get_config_identity(sm, &identity_len);
	if (identity) {
		data->peerid = os_malloc(identity_len);
		if (data->peerid == NULL) {
			eap_sake_deinit(sm, data);
			return NULL;
		}
		os_memcpy(data->peerid, identity, identity_len);
		data->peerid_len = identity_len;
	}

	os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
	os_memcpy(data->root_secret_b,
		  password + EAP_SAKE_ROOT_SECRET_LEN,
		  EAP_SAKE_ROOT_SECRET_LEN);

	return data;
}
Esempio n. 15
0
static void * eap_pax_init(struct eap_sm *sm)
{
	struct eap_pax_data *data;
	const u8 *identity, *password;
	size_t identity_len, password_len;

	identity = eap_get_config_identity(sm, &identity_len);
	password = eap_get_config_password(sm, &password_len);
	if (!identity || !password) {
		wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) "
			   "not configured");
		return NULL;
	}

	if (password_len != EAP_PAX_AK_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length");
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = PAX_INIT;

	data->cid = os_malloc(identity_len);
	if (data->cid == NULL) {
		eap_pax_deinit(sm, data);
		return NULL;
	}
	os_memcpy(data->cid, identity, identity_len);
	data->cid_len = identity_len;

	os_memcpy(data->ak, password, EAP_PAX_AK_LEN);

	return data;
}
Esempio n. 16
0
static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
			    struct eap_method_ret *ret,
			    const u8 *reqData, size_t reqDataLen,
			    size_t *respDataLen)
{
	struct eap_sim_data *data = priv;
	const struct eap_hdr *req;
	u8 subtype, *res;
	const u8 *pos;
	struct eap_sim_attrs attr;
	size_t len;

	wpa_hexdump(MSG_DEBUG, "EAP-SIM: EAP data", reqData, reqDataLen);
	if (eap_get_config_identity(sm, &len) == NULL) {
		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
		eap_sm_request_identity(sm);
		ret->ignore = TRUE;
		return NULL;
	}

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM,
			       reqData, reqDataLen, &len);
	if (pos == NULL || len < 1) {
		ret->ignore = TRUE;
		return NULL;
	}
	req = (const struct eap_hdr *) reqData;
	len = be_to_host16(req->length);

	ret->ignore = FALSE;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = TRUE;

	subtype = *pos++;
	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
	pos += 2; /* Reserved */

	if (eap_sim_parse_attr(pos, reqData + len, &attr, 0, 0)) {
		res = eap_sim_client_error(data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		goto done;
	}

	switch (subtype) {
	case EAP_SIM_SUBTYPE_START:
		res = eap_sim_process_start(sm, data, req,
					    respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_CHALLENGE:
		res = eap_sim_process_challenge(sm, data, req, len,
						respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_NOTIFICATION:
		res = eap_sim_process_notification(sm, data, req, len,
						   respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
		res = eap_sim_process_reauthentication(sm, data, req, len,
						       respDataLen, &attr);
		break;
	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
		res = eap_sim_client_error(data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
		res = eap_sim_client_error(data, req, respDataLen,
					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
		break;
	}

done:
	if (data->state == FAILURE) {
		ret->decision = DECISION_FAIL;
		ret->methodState = METHOD_DONE;
	} else if (data->state == SUCCESS) {
		ret->decision = DECISION_COND_SUCC;
		ret->methodState = METHOD_DONE;
	}

	if (ret->methodState == METHOD_DONE) {
		ret->allowNotifications = FALSE;
	}

	return res;
}
Esempio n. 17
0
static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
                                       struct eap_method_ret *ret,
                                       const struct wpabuf *reqData)
{
    struct eap_aka_data *data = priv;
    const struct eap_hdr *req;
    u8 subtype, id;
    struct wpabuf *res;
    const u8 *pos;
    struct eap_sim_attrs attr;
    size_t len;

    wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
    if (eap_get_config_identity(sm, &len) == NULL) {
        wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
        eap_sm_request_identity(sm);
        ret->ignore = TRUE;
        return NULL;
    }

    pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
                           &len);
    if (pos == NULL || len < 1) {
        ret->ignore = TRUE;
        return NULL;
    }
    req = wpabuf_head(reqData);
    id = req->identifier;
    len = be_to_host16(req->length);

    ret->ignore = FALSE;
    ret->methodState = METHOD_MAY_CONT;
    ret->decision = DECISION_FAIL;
    ret->allowNotifications = TRUE;

    subtype = *pos++;
    wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
    pos += 2; /* Reserved */

    if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
                           data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
                           0)) {
        res = eap_aka_client_error(data, id,
                                   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
        goto done;
    }

    switch (subtype) {
    case EAP_AKA_SUBTYPE_IDENTITY:
        res = eap_aka_process_identity(sm, data, id, reqData, &attr);
        break;
    case EAP_AKA_SUBTYPE_CHALLENGE:
        res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
        break;
    case EAP_AKA_SUBTYPE_NOTIFICATION:
        res = eap_aka_process_notification(sm, data, id, reqData,
                                           &attr);
        break;
    case EAP_AKA_SUBTYPE_REAUTHENTICATION:
        res = eap_aka_process_reauthentication(sm, data, id, reqData,
                                               &attr);
        break;
    case EAP_AKA_SUBTYPE_CLIENT_ERROR:
        wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
        res = eap_aka_client_error(data, id,
                                   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
        break;
    default:
        wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
        res = eap_aka_client_error(data, id,
                                   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
        break;
    }

done:
    if (data->state == FAILURE) {
        ret->decision = DECISION_FAIL;
        ret->methodState = METHOD_DONE;
    } else if (data->state == SUCCESS) {
        ret->decision = data->use_result_ind ?
                        DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
        /*
         * It is possible for the server to reply with AKA
         * Notification, so we must allow the method to continue and
         * not only accept EAP-Success at this point.
         */
        ret->methodState = data->use_result_ind ?
                           METHOD_DONE : METHOD_MAY_CONT;
    } else if (data->state == RESULT_FAILURE)
        ret->methodState = METHOD_CONT;
    else if (data->state == RESULT_SUCCESS)
        ret->methodState = METHOD_CONT;

    if (ret->methodState == METHOD_DONE) {
        ret->allowNotifications = FALSE;
    }

    return res;
}
Esempio n. 18
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);
}
Esempio n. 19
0
static void * eap_wsc_init(struct eap_sm *sm)
{
	struct eap_wsc_data *data;
	const u8 *identity;
	size_t identity_len;
	int registrar;
	struct wps_config cfg;
	const char *pos;
	const char *phase1;
	struct wps_context *wps;
	struct wps_credential new_ap_settings;
	int res;

	wps = sm->wps;
	if (wps == NULL) {
		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
		return NULL;
	}

	identity = eap_get_config_identity(sm, &identity_len);

	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
		registrar = 1; /* Supplicant is Registrar */
	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
		registrar = 0; /* Supplicant is Enrollee */
	else {
		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
				  identity, identity_len);
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = registrar ? MESG : WAIT_START;
	data->registrar = registrar;
	data->wps_ctx = wps;

	os_memset(&cfg, 0, sizeof(cfg));
	cfg.wps = wps;
	cfg.registrar = registrar;

	phase1 = eap_get_config_phase1(sm);
	if (phase1 == NULL) {
		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
			   "set");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, "pin=");
	if (pos) {
		pos += 4;
		cfg.pin = (const u8 *) pos;
		while (*pos != '\0' && *pos != ' ')
			pos++;
		cfg.pin_len = pos - (const char *) cfg.pin;
	} else {
		pos = os_strstr(phase1, "pbc=1");
		if (pos)
			cfg.pbc = 1;
	}

	if (cfg.pin == NULL && !cfg.pbc) {
		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
			   "configuration data");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, "dev_pw_id=");
	if (pos && cfg.pin)
		cfg.dev_pw_id = atoi(pos + 10);

	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
	if (res < 0) {
		os_free(data);
		return NULL;
	}
	if (res == 1) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
			   "WPS");
		cfg.new_ap_settings = &new_ap_settings;
	}

	data->wps = wps_init(&cfg);
	if (data->wps == NULL) {
		os_free(data);
		return NULL;
	}

	res = eap_get_config_fragment_size(sm);
	if (res > 0)
		data->fragment_size = res;
	else
	data->fragment_size = WSC_FRAGMENT_SIZE;
	wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
		   (unsigned int) data->fragment_size);

	if (registrar && cfg.pin) {
		wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
				      cfg.pin, cfg.pin_len, 0);
	}

	return data;
}
Esempio n. 20
0
static u8 * eap_aka_process_challenge(struct eap_sm *sm,
				      struct eap_aka_data *data,
				      const struct eap_hdr *req,
				      size_t reqDataLen,
				      size_t *respDataLen,
				      struct eap_sim_attrs *attr)
{
	const u8 *identity;
	size_t identity_len;
	int res;
	struct eap_sim_attrs eattr;

	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
	data->reauth = 0;
	if (!attr->mac || !attr->rand || !attr->autn) {
		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
			   "did not include%s%s%s",
			   !attr->mac ? " AT_MAC" : "",
			   !attr->rand ? " AT_RAND" : "",
			   !attr->autn ? " AT_AUTN" : "");
		return eap_aka_client_error(data, req, respDataLen,
					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
	}
	os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
	os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);

	res = eap_aka_umts_auth(sm, data);
	if (res == -1) {
		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
			   "failed (AUTN)");
		return eap_aka_authentication_reject(data, req, respDataLen);
	} else if (res == -2) {
		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
			   "failed (AUTN seq# -> AUTS)");
		return eap_aka_synchronization_failure(data, req, respDataLen);
	} else if (res) {
		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
		return eap_aka_client_error(data, req, respDataLen,
					    EAP_AKA_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-AKA: Selected identity for MK "
			  "derivation", identity, identity_len);
	eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
			  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, (const u8 *) req, reqDataLen,
			       attr->mac, (u8 *) "", 0)) {
		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
			   "used invalid AT_MAC");
		return eap_aka_client_error(data, req, respDataLen,
					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
	}

	/* Old reauthentication and pseudonym identities must not be used
	 * anymore. In other words, if no new identities are received, full
	 * authentication will be used on next reauthentication. */
	eap_aka_clear_identities(data, CLEAR_PSEUDONYM | 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_aka_client_error(
				data, req, respDataLen,
				EAP_AKA_UNABLE_TO_PROCESS_PACKET);
		}
		eap_aka_learn_ids(data, &eattr);
		os_free(decrypted);
	}

	if (data->state != FAILURE)
		data->state = SUCCESS;

	data->num_id_req = 0;
	data->num_notification = 0;
	/* RFC 4187 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_aka_response_challenge(data, req, respDataLen);
}
static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
                                       struct eap_method_ret *ret,
                                       const struct wpabuf *reqData)
{
        struct eap_gtc_data *data = priv;
        struct wpabuf *resp;
        const u8 *pos, *password, *identity;
        size_t password_len, identity_len, len, plen;
        int otp;
        u8 id;

        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
        if (pos == NULL) {
                ret->ignore = TRUE;
                return NULL;
        }
        id = eap_get_id(reqData);

        wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
        if (data->prefix &&
            (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) {
                wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
                           "expected prefix");
                wpa_printf(MSG_DEBUG, "Unrecoverable error - Restarting\n");

                /* Send an empty response in order to allow tunneled
                 * acknowledgement of the failure. This will also cover the
                 * error case which seems to use EAP-MSCHAPv2 like error
                 * reporting with EAP-GTC inside EAP-FAST tunnel. */
                resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC,
                                     0, EAP_CODE_RESPONSE, id);
                return resp;
        }

        password = eap_get_config_otp(sm, &password_len);
        if (password)
                otp = 1;
        else {
                password = eap_get_config_password(sm, &password_len);
                otp = 0;
        }

        if (password == NULL) {
                wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
                eap_sm_request_otp(sm, (const char *) pos, len);
                ret->ignore = TRUE;
                return NULL;
        }

        ret->ignore = FALSE;

        ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
        ret->decision = DECISION_COND_SUCC;
        ret->allowNotifications = FALSE;

        plen = password_len;
        identity = eap_get_config_identity(sm, &identity_len);
        if (identity == NULL)
                return NULL;
        if (data->prefix)
                plen += 9 + identity_len + 1;
        resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen,
                             EAP_CODE_RESPONSE, id);
        if (resp == NULL)
                return NULL;
        if (data->prefix) {
                wpabuf_put_data(resp, "RESPONSE=", 9);
                wpabuf_put_data(resp, identity, identity_len);
                wpabuf_put_u8(resp, '\0');
        }
        wpabuf_put_data(resp, password, password_len);
        wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
                              wpabuf_head_u8(resp) + sizeof(struct eap_hdr) +
                              1, plen);

        if (otp) {
                wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
                eap_clear_config_otp(sm);
        }

        return resp;
}
Esempio n. 22
0
static void * eap_wsc_init(struct eap_sm *sm)
{
	struct eap_wsc_data *data;
	const u8 *identity;
	size_t identity_len;
	int registrar;
	struct wps_config cfg;
	const char *pos, *end;
	const char *phase1;
	struct wps_context *wps;
	struct wps_credential new_ap_settings;
	int res;
	int nfc = 0;
	u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN];

	wps = sm->wps;
	if (wps == NULL) {
		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
		return NULL;
	}

	identity = eap_get_config_identity(sm, &identity_len);

	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
		registrar = 1; /* Supplicant is Registrar */
	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
		registrar = 0; /* Supplicant is Enrollee */
	else {
		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
				  identity, identity_len);
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = registrar ? MESG : WAIT_START;
	data->registrar = registrar;
	data->wps_ctx = wps;

	os_memset(&cfg, 0, sizeof(cfg));
	cfg.wps = wps;
	cfg.registrar = registrar;

	phase1 = eap_get_config_phase1(sm);
	if (phase1 == NULL) {
		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
			   "set");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, "pin=");
	if (pos) {
		pos += 4;
		cfg.pin = (const u8 *) pos;
		while (*pos != '\0' && *pos != ' ')
			pos++;
		cfg.pin_len = pos - (const char *) cfg.pin;
		if (cfg.pin_len == 6 &&
		    os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
			cfg.pin = NULL;
			cfg.pin_len = 0;
			nfc = 1;
		}
	} else {
		pos = os_strstr(phase1, "pbc=1");
		if (pos)
			cfg.pbc = 1;
	}

	pos = os_strstr(phase1, "dev_pw_id=");
	if (pos) {
		u16 id = atoi(pos + 10);
		if (id == DEV_PW_NFC_CONNECTION_HANDOVER)
			nfc = 1;
		if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER)
			cfg.dev_pw_id = id;
	}

	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
			   "configuration data");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, " pkhash=");
	if (pos) {
		size_t len;
		pos += 8;
		end = os_strchr(pos, ' ');
		if (end)
			len = end - pos;
		else
			len = os_strlen(pos);
		if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN ||
		    hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) {
			wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash");
			os_free(data);
			return NULL;
		}
		cfg.peer_pubkey_hash = pkhash;
	}

	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
	if (res < 0) {
		os_free(data);
		wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
			   "settings");
		return NULL;
	}
	if (res == 1) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
			   "WPS");
		cfg.new_ap_settings = &new_ap_settings;
	}

	data->wps = wps_init(&cfg);
	if (data->wps == NULL) {
		os_free(data);
		wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
		return NULL;
	}
	res = eap_get_config_fragment_size(sm);
	if (res > 0)
		data->fragment_size = res;
	else
		data->fragment_size = WSC_FRAGMENT_SIZE;
	wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
		   (unsigned int) data->fragment_size);

	if (registrar && cfg.pin) {
		wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
				      cfg.pin, cfg.pin_len, 0);
	}

	/* Use reduced client timeout for WPS to avoid long wait */
	if (sm->ClientTimeout > 30)
		sm->ClientTimeout = 30;

	return data;
}
Esempio n. 23
0
static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
						struct eap_method_ret *ret,
						const struct wpabuf *reqData)
{
	struct eap_leap_data *data = priv;
	struct wpabuf *resp;
	const u8 *pos, *challenge, *identity, *password;
	u8 challenge_len, *rpos;
	size_t identity_len, password_len, len;
	int pwhash;

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");

	identity = eap_get_config_identity(sm, &identity_len);
	password = eap_get_config_password2(sm, &password_len, &pwhash);
	if (identity == NULL || password == NULL)
		return NULL;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
	if (pos == NULL || len < 3) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
		ret->ignore = TRUE;
		return NULL;
	}

	if (*pos != LEAP_VERSION) {
		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
			   "%d", *pos);
		ret->ignore = TRUE;
		return NULL;
	}
	pos++;

	pos++; /* skip unused byte */

	challenge_len = *pos++;
	if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
			   "(challenge_len=%d reqDataLen=%lu)",
			   challenge_len, (unsigned long) wpabuf_len(reqData));
		ret->ignore = TRUE;
		return NULL;
	}
	challenge = pos;
	os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
		    challenge, LEAP_CHALLENGE_LEN);

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");

	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
			     3 + LEAP_RESPONSE_LEN + identity_len,
			     EAP_CODE_RESPONSE, eap_get_id(reqData));
	if (resp == NULL)
		return NULL;
	wpabuf_put_u8(resp, LEAP_VERSION);
	wpabuf_put_u8(resp, 0); /* unused */
	wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
	rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
	if (pwhash)
		challenge_response(challenge, password, rpos);
	else
		nt_challenge_response(challenge, password, password_len, rpos);
	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
		    rpos, LEAP_RESPONSE_LEN);
	wpabuf_put_data(resp, identity, identity_len);

	data->state = LEAP_WAIT_SUCCESS;

	return resp;
}
Esempio n. 24
0
static void * eap_wsc_init(struct eap_sm *sm)
{
	struct eap_wsc_data *data;
	const u8 *identity;
	size_t identity_len;
	int registrar;
	struct wps_config cfg;
	const char *pos;
	const char *phase1;
	struct wps_context *wps;
	struct wps_credential new_ap_settings;
	int res;
	u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
	int nfc = 0;

	wps = sm->wps;
	if (wps == NULL) {
		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
		return NULL;
	}

	identity = eap_get_config_identity(sm, &identity_len);

	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
		registrar = 1; /* Supplicant is Registrar */
	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
		registrar = 0; /* Supplicant is Enrollee */
	else {
		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
				  identity, identity_len);
		return NULL;
	}

	data = os_zalloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	data->state = registrar ? MESG : WAIT_START;
	data->registrar = registrar;
	data->wps_ctx = wps;

	os_memset(&cfg, 0, sizeof(cfg));
	cfg.wps = wps;
	cfg.registrar = registrar;

	phase1 = eap_get_config_phase1(sm);
	if (phase1 == NULL) {
		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
			   "set");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, "pin=");
	if (pos) {
		pos += 4;
		cfg.pin = (const u8 *) pos;
		while (*pos != '\0' && *pos != ' ')
			pos++;
		cfg.pin_len = pos - (const char *) cfg.pin;
		if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
		    cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
		    hexstr2bin((const char *) cfg.pin, dev_pw,
			       cfg.pin_len / 2) == 0) {
			/* Convert OOB Device Password to binary */
			cfg.pin = dev_pw;
			cfg.pin_len /= 2;
		}
		if (cfg.pin_len == 6 &&
		    os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
			cfg.pin = NULL;
			cfg.pin_len = 0;
			nfc = 1;
		}
	} else {
		pos = os_strstr(phase1, "pbc=1");
		if (pos)
			cfg.pbc = 1;
	}

	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
			   "configuration data");
		os_free(data);
		return NULL;
	}

	pos = os_strstr(phase1, "dev_pw_id=");
	if (pos && cfg.pin)
		cfg.dev_pw_id = atoi(pos + 10);

	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
	if (res < 0) {
		os_free(data);
		return NULL;
	}
	if (res == 1) {
		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
			   "WPS");
		cfg.new_ap_settings = &new_ap_settings;
	}

	data->wps = wps_init(&cfg);
	if (data->wps == NULL) {
		os_free(data);
		return NULL;
	}
	res = eap_get_config_fragment_size(sm);
	if (res > 0)
		data->fragment_size = res;
	else
		data->fragment_size = WSC_FRAGMENT_SIZE;
	wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
		   (unsigned int) data->fragment_size);

	if (registrar && cfg.pin) {
		wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
				      cfg.pin, cfg.pin_len, 0);
	}

	/* Use reduced client timeout for WPS to avoid long wait */
	if (sm->ClientTimeout > 30)
		sm->ClientTimeout = 30;

	return data;
}
Esempio n. 25
0
static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
        struct eap_aka_data *data,
        u8 id,
        const struct wpabuf *reqData,
        struct eap_sim_attrs *attr)
{
    const u8 *identity;
    size_t identity_len;
    int res;
    struct eap_sim_attrs eattr;

    wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");

    if (attr->checkcode &&
            eap_aka_verify_checkcode(data, attr->checkcode,
                                     attr->checkcode_len)) {
        wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
                   "message");
        return eap_aka_client_error(data, id,
                                    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
    }

#ifdef EAP_AKA_PRIME
    if (data->eap_method == EAP_TYPE_AKA_PRIME) {
        if (!attr->kdf_input || attr->kdf_input_len == 0) {
            wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
                       "did not include non-empty AT_KDF_INPUT");
            /* Fail authentication as if AUTN had been incorrect */
            return eap_aka_authentication_reject(data, id);
        }
        os_free(data->network_name);
        data->network_name = os_malloc(attr->kdf_input_len);
        if (data->network_name == NULL) {
            wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
                       "storing Network Name");
            return eap_aka_authentication_reject(data, id);
        }
        os_memcpy(data->network_name, attr->kdf_input,
                  attr->kdf_input_len);
        data->network_name_len = attr->kdf_input_len;
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
                          "(AT_KDF_INPUT)",
                          data->network_name, data->network_name_len);
        /* TODO: check Network Name per 3GPP.33.402 */

        if (!eap_aka_prime_kdf_valid(data, attr))
            return eap_aka_authentication_reject(data, id);

        if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
            return eap_aka_prime_kdf_neg(data, id, attr);

        data->kdf = EAP_AKA_PRIME_KDF;
        wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
    }

    if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
        u16 flags = WPA_GET_BE16(attr->bidding);
        if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
                eap_allowed_method(sm, EAP_VENDOR_IETF,
                                   EAP_TYPE_AKA_PRIME)) {
            wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
                       "AKA' to AKA detected");
            /* Fail authentication as if AUTN had been incorrect */
            return eap_aka_authentication_reject(data, id);
        }
    }
#endif /* EAP_AKA_PRIME */

    data->reauth = 0;
    if (!attr->mac || !attr->rand || !attr->autn) {
        wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
                   "did not include%s%s%s",
                   !attr->mac ? " AT_MAC" : "",
                   !attr->rand ? " AT_RAND" : "",
                   !attr->autn ? " AT_AUTN" : "");
        return eap_aka_client_error(data, id,
                                    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
    }
    os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
    os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);

    res = eap_aka_umts_auth(sm, data);
    if(res != 0) {
        wpa_printf(MSG_ERROR, "EAP-AKA: No more data send to APDU server");
        //SCardDisconnect(0,0);
    }
    if (res == -1) {
        wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
                   "failed (AUTN)");
        return eap_aka_authentication_reject(data, id);
    } else if (res == -2) {
        wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
                   "failed (AUTN seq# -> AUTS)");
        return eap_aka_synchronization_failure(data, id);
    } else if (res) {
        wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
        return eap_aka_client_error(data, id,
                                    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
    }
#ifdef EAP_AKA_PRIME
    if (data->eap_method == EAP_TYPE_AKA_PRIME) {
        /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
         * needed 6-octet SQN ^ AK for CK',IK' derivation */
        u16 amf = WPA_GET_BE16(data->autn + 6);
        if (!(amf & 0x8000)) {
            wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
                       "not set (AMF=0x%4x)", amf);
            return eap_aka_authentication_reject(data, id);
        }
        eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
                                         data->autn,
                                         data->network_name,
                                         data->network_name_len);
    }
#endif /* EAP_AKA_PRIME */
    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-AKA: Selected identity for MK "
                      "derivation", identity, identity_len);
    if (data->eap_method == EAP_TYPE_AKA_PRIME) {
        eap_aka_prime_derive_keys(identity, identity_len, data->ik,
                                  data->ck, data->k_encr, data->k_aut,
                                  data->k_re, data->msk, data->emsk);
    } else {
        eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
                          data->mk);
        eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
                            data->msk, data->emsk);
    }
    if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
        wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
                   "used invalid AT_MAC");
        return eap_aka_client_error(data, id,
                                    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
    }

    /* Old reauthentication identity must not be used anymore. In
     * other words, if no new identities are received, full
     * authentication will be used on next reauthentication (using
     * pseudonym identity or permanent identity). */
    eap_aka_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_aka_client_error(
                       data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
        }
        eap_aka_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_aka_state(data, data->use_result_ind ?
                      RESULT_SUCCESS : SUCCESS);
    }

    data->num_id_req = 0;
    data->num_notification = 0;
    /* RFC 4187 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_aka_response_challenge(data, id);
}
Esempio n. 26
0
static struct wpabuf * 
eap_mschapv2_challenge_reply(
	struct eap_sm *sm, struct eap_mschapv2_data *data,
	u8 id, u8 mschapv2_id, const u8 *auth_challenge)
{
	struct wpabuf *resp;
	struct eap_mschapv2_hdr *ms;
	u8 *peer_challenge;
	int ms_len;
	struct ms_response *r;
	size_t identity_len, password_len;
	const u8 *identity, *password;
	int pwhash;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generate Challenge Response\n");

	identity = eap_get_config_identity(sm, &identity_len);
	password = eap_get_config_password2(sm, &password_len, &pwhash);
	if (identity == NULL || password == NULL)
		return NULL;

	ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
			     ms_len, EAP_CODE_RESPONSE, id);
	if (resp == NULL)
		return NULL;

	ms = wpabuf_put(resp, sizeof(*ms));
	ms->op_code = MSCHAPV2_OP_RESPONSE;
	ms->mschapv2_id = mschapv2_id;
	if (data->prev_error)
		ms->mschapv2_id++;
	WPA_PUT_BE16(ms->ms_length, ms_len);
	wpabuf_put_u8(resp, sizeof(*r));

	/* Response */
	r = wpabuf_put(resp, sizeof(*r));
	peer_challenge = r->peer_challenge;
	if (data->peer_challenge) {
		peer_challenge = data->peer_challenge;
	os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
	} else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
		wpabuf_free(resp);
		return NULL;
	}
	os_memset(r->reserved, 0, 8);
	if (data->auth_challenge)
		auth_challenge = data->auth_challenge;
	if (mschapv2_derive_response(identity, identity_len, password,
				     password_len, pwhash, auth_challenge,
				     peer_challenge, r->nt_response,
				     data->auth_response, data->master_key)) {
		wpabuf_free(resp);
		return NULL;
	}
	data->auth_response_valid = 1;
	data->master_key_valid = 1;

	r->flags = 0;

	wpabuf_put_data(resp, identity, identity_len);
	return resp;
}
static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
				     struct eap_method_ret *ret,
				     const u8 *reqData, size_t reqDataLen,
				     size_t *respDataLen)
{
	struct eap_leap_data *data = priv;
	const struct eap_hdr *req;
	struct eap_hdr *resp;
	const u8 *pos, *challenge, *identity, *password;
	u8 challenge_len, *rpos;
	size_t identity_len, password_len;

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");

	identity = eap_get_config_identity(sm, &identity_len);
	password = eap_get_config_password(sm, &password_len);
	if (identity == NULL || password == NULL)
		return NULL;

	req = (const struct eap_hdr *) reqData;
	pos = (const u8 *) (req + 1);
	if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
		ret->ignore = TRUE;
		return NULL;
	}
	pos++;

	if (*pos != LEAP_VERSION) {
		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
			   "%d", *pos);
		ret->ignore = TRUE;
		return NULL;
	}
	pos++;

	pos++; /* skip unused byte */

	challenge_len = *pos++;
	if (challenge_len != LEAP_CHALLENGE_LEN ||
	    challenge_len > reqDataLen - sizeof(*req) - 4) {
		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
			   "(challenge_len=%d reqDataLen=%lu)",
			   challenge_len, (unsigned long) reqDataLen);
		ret->ignore = TRUE;
		return NULL;
	}
	challenge = pos;
	os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
		    challenge, LEAP_CHALLENGE_LEN);

	wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");

	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, respDataLen,
			     3 + LEAP_RESPONSE_LEN + identity_len,
			     EAP_CODE_RESPONSE, req->identifier, &rpos);
	if (resp == NULL)
		return NULL;
	*rpos++ = LEAP_VERSION;
	*rpos++ = 0; /* unused */
	*rpos++ = LEAP_RESPONSE_LEN;
	nt_challenge_response(challenge, password, password_len, rpos);
	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
		    rpos, LEAP_RESPONSE_LEN);
	rpos += LEAP_RESPONSE_LEN;
	os_memcpy(rpos, identity, identity_len);

	data->state = LEAP_WAIT_SUCCESS;

	return (u8 *) resp;
}
static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
				   struct eap_mschapv2_data *data,
				   struct eap_method_ret *ret,
				   const struct eap_mschapv2_hdr *req,
				   size_t *respDataLen)
{
	u8 *challenge, *peer_challenge, *pos;
	int ms_len;
	size_t i, len, challenge_len, username_len, identity_len, password_len;
	struct eap_mschapv2_hdr *resp;
	u8 password_hash[16], password_hash_hash[16];
	const u8 *username, *identity, *password;

	identity = eap_get_config_identity(sm, &identity_len);
	password = eap_get_config_password(sm, &password_len);
	if (identity == NULL || password == NULL)
		return NULL;

	/* MSCHAPv2 does not include optional domain name in the
	 * challenge-response calculation, so remove domain prefix
	 * (if present). */
	username = identity;
	username_len = identity_len;
	for (i = 0; i < username_len; i++) {
		if (username[i] == '\\') {
			username_len -= i + 1;
			username += i + 1;
			break;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
	len = be_to_host16(req->length);
	pos = (u8 *) (req + 1);
	challenge_len = *pos++;
	if (challenge_len != 16) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
			   "%lu", (unsigned long) challenge_len);
		ret->ignore = TRUE;
		return NULL;
	}

	if (len < 10 || len - 10 < challenge_len) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
			   " packet: len=%lu challenge_len=%lu",
			   (unsigned long) len, (unsigned long) challenge_len);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->passwd_change_challenge_valid) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
			   "failure message");
		challenge = data->passwd_change_challenge;
	} else
		challenge = pos;
	pos += challenge_len;
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
		    pos, len - challenge_len - 10);

	ret->ignore = FALSE;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_FAIL;
	ret->allowNotifications = TRUE;

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");

	*respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN + identity_len;
	resp = wpa_zalloc(*respDataLen);
	if (resp == NULL)
		return NULL;
	resp->code = EAP_CODE_RESPONSE;
	resp->identifier = req->identifier;
	resp->length = host_to_be16(*respDataLen);
	resp->type = EAP_TYPE_MSCHAPV2;
	resp->op_code = MSCHAPV2_OP_RESPONSE;
	resp->mschapv2_id = req->mschapv2_id;
	if (data->prev_error) {
		/*
		 * TODO: this does not seem to be enough when processing two
		 * or more failure messages. IAS did not increment mschapv2_id
		 * in its own packets, but it seemed to expect the peer to
		 * increment this for all packets(?).
		 */
		resp->mschapv2_id++;
	}
	ms_len = *respDataLen - 5;
	WPA_PUT_BE16(resp->ms_length, ms_len);
	pos = (u8 *) (resp + 1);
	*pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */

	/* Response */
	peer_challenge = pos;
	if (data->peer_challenge) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
			   "in Phase 1");
		peer_challenge = data->peer_challenge;
	} else if (hostapd_get_rand(peer_challenge, 16)) {
		free(resp);
		return NULL;
	}
	pos += 16;
	pos += 8; /* Reserved, must be zero */
	if (data->auth_challenge) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
			   "in Phase 1");
		challenge = data->auth_challenge;
	}
	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16);
	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
		    peer_challenge, 16);
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
			  username, username_len);
	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
			      password, password_len);
	generate_nt_response(challenge, peer_challenge, username, username_len,
			     password, password_len, pos);
	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24);
	/* Authenticator response is not really needed yet, but calculate it
	 * here so that challenges need not be saved. */
	generate_authenticator_response(password, password_len,
					peer_challenge, challenge,
					username, username_len, pos,
					data->auth_response);
	data->auth_response_valid = 1;

	/* Likewise, generate master_key here since we have the needed data
	 * available. */
	nt_password_hash(password, password_len, password_hash);
	hash_nt_password_hash(password_hash, password_hash_hash);
	get_master_key(password_hash_hash, pos /* nt_response */,
		       data->master_key);
	data->master_key_valid = 1;

	pos += 24;
	pos++; /* Flag / reserved, must be zero */

	memcpy(pos, identity, identity_len);
	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
		   "(response)", resp->identifier, resp->mschapv2_id);
	return (u8 *) resp;
}
static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
				 struct eap_method_ret *ret,
				 const u8 *reqData, size_t reqDataLen,
				 size_t *respDataLen)
{
	struct eap_mschapv2_data *data = priv;
	struct wpa_ssid *config = eap_get_config(sm);
	const struct eap_mschapv2_hdr *req;
	int using_prev_challenge = 0;
	const u8 *pos;
	size_t ms_len, len;

	if (eap_get_config_identity(sm, &len) == NULL) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
		eap_sm_request_identity(sm);
		ret->ignore = TRUE;
		return NULL;
	}

	if (eap_get_config_password(sm, &len) == NULL) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
		eap_sm_request_password(sm);
		ret->ignore = TRUE;
		return NULL;
	}

	if (config->mschapv2_retry && data->prev_challenge &&
	    data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
			   "with the previous challenge");

		reqData = data->prev_challenge;
		reqDataLen = data->prev_challenge_len;
		using_prev_challenge = 1;
		config->mschapv2_retry = 0;
	}

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
			       reqData, reqDataLen, &len);
	if (pos == NULL || len < 5) {
		ret->ignore = TRUE;
		return NULL;
	}
	req = (const struct eap_mschapv2_hdr *) reqData;
	len = be_to_host16(req->length);
	ms_len = WPA_GET_BE16(req->ms_length);
	if (ms_len != len - 5) {
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
			   "ms_len=%lu", (unsigned long) len,
			   (unsigned long) ms_len);
		if (sm->workaround) {
			/* Some authentication servers use invalid ms_len,
			 * ignore it for interoperability. */
			wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
				   " invalid ms_len");
		} else {
			ret->ignore = TRUE;
			return NULL;
		}
	}

	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
		   req->identifier, req->mschapv2_id);

	switch (req->op_code) {
	case MSCHAPV2_OP_CHALLENGE:
		if (!using_prev_challenge) {
			free(data->prev_challenge);
			data->prev_challenge = malloc(len);
			if (data->prev_challenge) {
				data->prev_challenge_len = len;
				memcpy(data->prev_challenge, reqData, len);
			}
		}
		return eap_mschapv2_challenge(sm, data, ret, req, respDataLen);
	case MSCHAPV2_OP_SUCCESS:
		return eap_mschapv2_success(sm, data, ret, req, respDataLen);
	case MSCHAPV2_OP_FAILURE:
		return eap_mschapv2_failure(sm, data, ret, req, respDataLen);
	default:
		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
			   req->op_code);
		ret->ignore = TRUE;
		return NULL;
	}
}
Esempio n. 30
0
static struct wpabuf * 
eap_mschapv2_change_password(
	struct eap_sm *sm, struct eap_mschapv2_data *data,
	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
{
	struct wpabuf *resp;
	int ms_len;
	const u8 *username, *password, *new_password;
	size_t username_len, password_len, new_password_len;
	struct eap_mschapv2_hdr *ms;
	struct ms_change_password *cp;
	u8 password_hash[16], password_hash_hash[16];
	int pwhash;

	username = eap_get_config_identity(sm, &username_len);
	password = eap_get_config_password2(sm, &password_len, &pwhash);
	new_password = eap_get_config_new_password(sm, &new_password_len);
	if (username == NULL || password == NULL || new_password == NULL)
		return NULL;

	username = mschapv2_remove_domain(username, &username_len);

	ret->ignore = false;
	ret->methodState = METHOD_MAY_CONT;
	ret->decision = DECISION_COND_SUCC;
	ret->allowNotifications = TRUE;

	ms_len = sizeof(*ms) + sizeof(*cp);
	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
			     EAP_CODE_RESPONSE, id);
	if (resp == NULL)
		return NULL;
	ms = wpabuf_put(resp, sizeof(*ms));
	ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
	ms->mschapv2_id = req->mschapv2_id + 1;
	WPA_PUT_BE16(ms->ms_length, ms_len);
	cp = wpabuf_put(resp, sizeof(*cp));

	if (pwhash) {
		if (encrypt_pw_block_with_password_hash(
			new_password, new_password_len,
			password, cp->encr_password))
			goto fail;
	} else {
		if (new_password_encrypted_with_old_nt_password_hash(
			new_password, new_password_len,
			password, password_len, cp->encr_password))
			goto fail;
	}

	if (pwhash) {
		u8 new_password_hash[16];
		nt_password_hash(new_password, new_password_len,
				 new_password_hash);
		nt_password_hash_encrypted_with_block(password,
						      new_password_hash,
						      cp->encr_hash);
	} else {
		old_nt_password_hash_encrypted_with_new_nt_password_hash(
				new_password, new_password_len,
				password, password_len, cp->encr_hash);
	}

	if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
		goto fail;

	os_memset(cp->reserved, 0, 8);

	generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
			     username, username_len, new_password,
			     new_password_len, cp->nt_response);

	generate_authenticator_response(new_password, new_password_len,
					cp->peer_challenge,
					data->passwd_change_challenge,
					username, username_len,
					cp->nt_response, data->auth_response);
	data->auth_response_valid = 1;

	nt_password_hash(new_password, new_password_len, password_hash);
	hash_nt_password_hash(password_hash, password_hash_hash);
	get_master_key(password_hash_hash, cp->nt_response, data->master_key);
	data->master_key_valid = 1;

	os_memset(cp->flags, 0, 2);

	return resp;

fail:
	wpabuf_free(resp);
	return NULL;
}