int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
			      size_t secret_len)
{
	const u8 *addr[4];
	size_t len[4];
	u8 zero[MD5_MAC_LEN];
	u8 hash[MD5_MAC_LEN];
	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
	u8 orig_authenticator[16];

	struct radius_attr_hdr *attr = NULL, *tmp;
	size_t i;

	os_memset(zero, 0, sizeof(zero));
	addr[0] = (u8 *) msg->hdr;
	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
	addr[1] = zero;
	len[1] = MD5_MAC_LEN;
	addr[2] = (u8 *) (msg->hdr + 1);
	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
	addr[3] = secret;
	len[3] = secret_len;
	md5_vector(4, addr, len, hash);
	if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
		return 1;

	for (i = 0; i < msg->attr_used; i++) {
		tmp = radius_get_attr_hdr(msg, i);
		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
			if (attr != NULL) {
				wpa_printf(MSG_WARNING, "Multiple "
					   "Message-Authenticator attributes "
					   "in RADIUS message");
				return 1;
			}
			attr = tmp;
		}
	}

	if (attr == NULL) {
		/* Message-Authenticator is MAY; not required */
		return 0;
	}

	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
	os_memset(attr + 1, 0, MD5_MAC_LEN);
	os_memcpy(orig_authenticator, msg->hdr->authenticator,
		  sizeof(orig_authenticator));
	os_memset(msg->hdr->authenticator, 0,
		  sizeof(msg->hdr->authenticator));
	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
		 wpabuf_len(msg->buf), auth);
	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
	os_memcpy(msg->hdr->authenticator, orig_authenticator,
		  sizeof(orig_authenticator));

	return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0;
}
static int eap_fast_validate_crypto_binding(
	struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
	size_t bind_len)
{
	u8 cmac[SHA1_MAC_LEN];

	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
		   "Version %d Received Version %d SubType %d",
		   b->version, b->received_version, b->subtype);
	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
		    b->nonce, sizeof(b->nonce));
	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
		    b->compound_mac, sizeof(b->compound_mac));

	if (b->version != EAP_FAST_VERSION ||
	    b->received_version != EAP_FAST_VERSION) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
			   "in Crypto-Binding: version %d "
			   "received_version %d", b->version,
			   b->received_version);
		return -1;
	}

	if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
			   "Crypto-Binding: %d", b->subtype);
		return -1;
	}

	if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
	    (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
			   "Crypto-Binding");
		return -1;
	}

	os_memcpy(cmac, b->compound_mac, sizeof(cmac));
	os_memset(b->compound_mac, 0, sizeof(cmac));
	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
		    "Compound MAC calculation",
		    (u8 *) b, bind_len);
	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
		  b->compound_mac);
	if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) {
		wpa_hexdump(MSG_MSGDUMP,
			    "EAP-FAST: Calculated Compound MAC",
			    b->compound_mac, sizeof(cmac));
		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
			   "match");
		return -1;
	}

	return 0;
}
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
		      size_t secret_len, struct radius_msg *sent_msg, int auth)
{
	const u8 *addr[4];
	size_t len[4];
	u8 hash[MD5_MAC_LEN];

	if (sent_msg == NULL) {
		wpa_printf(MSG_INFO, "No matching Access-Request message found");
		return 1;
	}

	if (auth &&
	    radius_msg_verify_msg_auth(msg, secret, secret_len,
				       sent_msg->hdr->authenticator)) {
		return 1;
	}

	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
	addr[0] = (u8 *) msg->hdr;
	len[0] = 1 + 1 + 2;
	addr[1] = sent_msg->hdr->authenticator;
	len[1] = MD5_MAC_LEN;
	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
	addr[3] = secret;
	len[3] = secret_len;
	md5_vector(4, addr, len, hash);
	if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
		wpa_printf(MSG_INFO, "Response Authenticator invalid!");
		return 1;
	}

	return 0;
}
int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
			      const u8 *key_wrap_auth)
{
	u8 hash[SHA256_MAC_LEN];
	const u8 *head;
	size_t len;

	if (key_wrap_auth == NULL) {
		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
		return -1;
	}

	head = wpabuf_head(msg);
	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
	if (head + len != key_wrap_auth - 4) {
		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
			   "decrypted attribute");
		return -1;
	}

	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
	if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
		return -1;
	}

	return 0;
}
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
			      const struct wpabuf *msg)
{
	u8 hash[SHA256_MAC_LEN];
	const u8 *addr[2];
	size_t len[2];

	if (authenticator == NULL) {
		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
			   "included");
		return -1;
	}

	if (wps->last_msg == NULL) {
		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
			   "validating authenticator");
		return -1;
	}

	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
	 * (M_curr* is M_curr without the Authenticator attribute)
	 */
	addr[0] = wpabuf_head(wps->last_msg);
	len[0] = wpabuf_len(wps->last_msg);
	addr[1] = wpabuf_head(msg);
	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);

	if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
		return -1;
	}

	return 0;
}
Exemple #6
0
static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
					  struct eap_peap_data *data,
					  const u8 *crypto_tlv,
					  size_t crypto_tlv_len)
{
	u8 buf[61], mac[SHA1_MAC_LEN];
	const u8 *pos;

	if (eap_peap_derive_cmk(sm, data) < 0) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
		return -1;
	}

	if (crypto_tlv_len != 4 + 56) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
			   "length %d", (int) crypto_tlv_len);
		return -1;
	}

	pos = crypto_tlv;
	pos += 4; /* TLV header */
	if (pos[1] != data->peap_version) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
			   "mismatch (was %d; expected %d)",
			   pos[1], data->peap_version);
		return -1;
	}

	if (pos[3] != 0) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
			   "SubType %d", pos[3]);
		return -1;
	}
	pos += 4;
	os_memcpy(data->binding_nonce, pos, 32);
	pos += 32; /* Nonce */

	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
	os_memcpy(buf, crypto_tlv, 60);
	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
	buf[60] = EAP_TYPE_PEAP;
	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
		    buf, sizeof(buf));
	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);

	if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
			   "cryptobinding TLV");
		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
			    pos, SHA1_MAC_LEN);
		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
			    mac, SHA1_MAC_LEN);
		return -1;
	}

	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");

	return 0;
}
Exemple #7
0
/**
 * milenage_generate - Generate AKA AUTN,IK,CK,RES
 * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
 * @k: K = 128-bit subscriber key
 * @sqn: SQN = 48-bit sequence number
 * @_rand: RAND = 128-bit random challenge
 * @autn: AUTN = 128-bit authentication token
 * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
 * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
 * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
 * @res_len: Variable that will be set to RES length
 * @auts: 112-bit buffer for AUTS
 * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
 */
int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
		   u8 *auts)
{
	int i;
	u8 mac_a[8], ak[6], rx_sqn[6];
	const u8 *amf;

	wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
	wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);

	if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
		return -1;

	*res_len = 8;
	wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
	wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
	wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
	wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);

	/* AUTN = (SQN ^ AK) || AMF || MAC */
	for (i = 0; i < 6; i++)
		rx_sqn[i] = autn[i] ^ ak[i];
	wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);

	if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
		u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
		if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
			return -1;
		wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
		for (i = 0; i < 6; i++)
			auts[i] = sqn[i] ^ ak[i];
		if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
			return -1;
		wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
		return -2;
	}

	amf = autn + 6;
	wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
	if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
		return -1;

	wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);

	if (os_memcmp_const(mac_a, autn + 8, 8) != 0) {
		wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
		wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
			    autn + 8, 8);
		return -1;
	}

	return 0;
}
Exemple #8
0
static int ikev2_process_auth_secret(struct ikev2_responder_data *data,
				     u8 method, const u8 *auth,
				     size_t auth_len)
{
	u8 auth_data[IKEV2_MAX_HASH_LEN];
	const struct ikev2_prf_alg *prf;

	if (method != AUTH_SHARED_KEY_MIC) {
		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
			   "method %d", method);
		return -1;
	}

	/* msg | Nr | prf(SK_pi,IDi') */
	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
				   data->IDi, data->IDi_len, data->IDi_type,
				   &data->keys, 1, data->shared_secret,
				   data->shared_secret_len,
				   data->r_nonce, data->r_nonce_len,
				   data->key_pad, data->key_pad_len,
				   auth_data) < 0) {
		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
		return -1;
	}

	wpabuf_free(data->i_sign_msg);
	data->i_sign_msg = NULL;

	prf = ikev2_get_prf(data->proposal.prf);
	if (prf == NULL)
		return -1;

	if (auth_len != prf->hash_len ||
	    os_memcmp_const(auth, auth_data, auth_len) != 0) {
		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
			    auth, auth_len);
		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
			    auth_data, prf->hash_len);
		data->error_type = AUTHENTICATION_FAILED;
		data->state = NOTIFY;
		return -1;
	}

	wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully "
		   "using shared keys");

	return 0;
}
Exemple #9
0
static int eap_aka_verify_checkcode(struct eap_aka_data *data,
				    const u8 *checkcode, size_t checkcode_len)
{
	const u8 *addr;
	size_t len;
	u8 hash[SHA256_MAC_LEN];
	size_t hash_len;

	if (checkcode == NULL)
		return -1;

	if (data->id_msgs == NULL) {
		if (checkcode_len != 0) {
			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
				   "indicates that AKA/Identity messages were "
				   "used, but they were not");
			return -1;
		}
		return 0;
	}

	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;

	if (checkcode_len != hash_len) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
			   "indicates that AKA/Identity message were not "
			   "used, but they were");
		return -1;
	}

	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
	addr = wpabuf_head(data->id_msgs);
	len = wpabuf_len(data->id_msgs);
#ifdef EAP_AKA_PRIME
	if (data->eap_method == EAP_TYPE_AKA_PRIME)
		sha256_vector(1, &addr, &len, hash);
	else
#endif /* EAP_AKA_PRIME */
		sha1_vector(1, &addr, &len, hash);

	if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
		return -1;
	}

	return 0;
}
int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
			       size_t secret_len, const u8 *req_auth)
{
	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
	u8 orig_authenticator[16];
	struct radius_attr_hdr *attr = NULL, *tmp;
	size_t i;

	for (i = 0; i < msg->attr_used; i++) {
		tmp = radius_get_attr_hdr(msg, i);
		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
			if (attr != NULL) {
				wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
				return 1;
			}
			attr = tmp;
		}
	}

	if (attr == NULL) {
		wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
		return 1;
	}

	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
	os_memset(attr + 1, 0, MD5_MAC_LEN);
	if (req_auth) {
		os_memcpy(orig_authenticator, msg->hdr->authenticator,
			  sizeof(orig_authenticator));
		os_memcpy(msg->hdr->authenticator, req_auth,
			  sizeof(msg->hdr->authenticator));
	}
	if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
		     wpabuf_len(msg->buf), auth) < 0)
		return 1;
	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
	if (req_auth) {
		os_memcpy(msg->hdr->authenticator, orig_authenticator,
			  sizeof(orig_authenticator));
	}

	if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) {
		wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
		return 1;
	}

	return 0;
}
Exemple #11
0
/**
 * milenage_auts - Milenage AUTS validation
 * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
 * @k: K = 128-bit subscriber key
 * @_rand: RAND = 128-bit random challenge
 * @auts: AUTS = 112-bit authentication token from client
 * @sqn: Buffer for SQN = 48-bit sequence number
 * Returns: 0 = success (sqn filled), -1 on failure
 */
int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
		  u8 *sqn)
{
	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
	u8 ak[6], mac_s[8];
	int i;

	if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
		return -1;
	for (i = 0; i < 6; i++)
		sqn[i] = auts[i] ^ ak[i];
	if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
	    os_memcmp_const(mac_s, auts + 6, 8) != 0)
		return -1;
	return 0;
}
int eap_eke_decrypt_prot(struct eap_eke_session *sess,
			 const u8 *prot, size_t prot_len,
			 u8 *data, size_t *data_len)
{
	size_t block_size, icv_len;
	u8 icv[EAP_EKE_MAX_HASH_LEN];

	if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
		block_size = AES_BLOCK_SIZE;
	else
		return -1;

	if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
		icv_len = SHA1_MAC_LEN;
	else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
		icv_len = SHA256_MAC_LEN;
	else
		return -1;

	if (prot_len < 2 * block_size + icv_len ||
	    (prot_len - icv_len) % block_size)
		return -1;

	if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
			prot_len - block_size - icv_len, icv) < 0)
		return -1;
	if (os_memcmp_const(icv, prot + prot_len - icv_len, icv_len) != 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
		return -1;
	}

	if (*data_len < prot_len - block_size - icv_len) {
		wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
		return -1;
	}

	*data_len = prot_len - block_size - icv_len;
	os_memcpy(data, prot + block_size, *data_len);
	if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
			data, *data_len);

	return 0;
}
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
			       size_t secret_len)
{
	const u8 *addr[4];
	size_t len[4];
	u8 zero[MD5_MAC_LEN];
	u8 hash[MD5_MAC_LEN];

	os_memset(zero, 0, sizeof(zero));
	addr[0] = (u8 *) msg->hdr;
	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
	addr[1] = zero;
	len[1] = MD5_MAC_LEN;
	addr[2] = (u8 *) (msg->hdr + 1);
	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
	addr[3] = secret;
	len[3] = secret_len;
	md5_vector(4, addr, len, hash);
	return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
}
Exemple #14
0
static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
{
	u8 hash[SHA256_MAC_LEN];
	const u8 *addr[4];
	size_t len[4];

	if (r_snonce2 == NULL) {
		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
		return -1;
	}

	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
			WPS_SECRET_NONCE_LEN);

	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
	addr[0] = r_snonce2;
	len[0] = WPS_SECRET_NONCE_LEN;
	addr[1] = wps->psk2;
	len[1] = WPS_PSK_LEN;
	addr[2] = wpabuf_head(wps->dh_pubkey_e);
	len[2] = wpabuf_len(wps->dh_pubkey_e);
	addr[3] = wpabuf_head(wps->dh_pubkey_r);
	len[3] = wpabuf_len(wps->dh_pubkey_r);
	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);

	if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
			   "not match with the pre-committed value");
		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
		wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr);
		return -1;
	}

	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
		   "half of the device password");

	return 0;
}
Exemple #15
0
/**
 * aes_gcm_ad - GCM-AD_K(IV, C, A, T)
 */
int aes_gcm_ad(
		   void *aes, // DHD20150614
		   const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
	       const u8 *crypt, size_t crypt_len,
	       const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
{
	u8 H[AES_BLOCK_SIZE];
	u8 J0[AES_BLOCK_SIZE];
	u8 S[16], T[16];
//	void *aes;

//	aes =
	aes_gcm_init_hash_subkey(
			aes, // DHD20150614
			key, key_len, H);
//	if (aes == NULL)
//		return -1;

	aes_gcm_prepare_j0(iv, iv_len, H, J0);

	/* P = GCTR_K(inc_32(J_0), C) */
	aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);

	aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);

	/* T' = MSB_t(GCTR_K(J_0, S)) */
	aes_gctr(aes, J0, S, sizeof(S), T);

	aes_encrypt_deinit(aes);

	if (os_memcmp_const(tag, T, 16) != 0) {
		/* printf("GCM: Tag mismatch\n"); */
		return -1;
	}

	return 0;
}
Exemple #16
0
static void eap_md5_process(struct eap_sm *sm, void *priv, struct wpabuf *respData)
{
	struct eap_md5_data *data = priv;
	const u8 *pos;
	size_t plen;
	u8 hash[CHAP_MD5_LEN], id;

	if (sm->user == NULL || sm->user->password == NULL || sm->user->password_hash) {
		wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " "configured");
		data->state = FAILURE;
		return;
	}

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen);
	if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) {
		return;    /* Should not happen - frame already validated */
	}

	pos++;						/* Skip response len */
	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);

	id = eap_get_id(respData);
	if (chap_md5(id, sm->user->password, sm->user->password_len, data->challenge, CHALLENGE_LEN, hash)) {
		wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
		data->state = FAILURE;
		return;
	}

	if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) {
		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
		data->state = SUCCESS;
	} else {
		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure");
		data->state = FAILURE;
	}
}
Exemple #17
0
static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
			      size_t pk_len)
{
	if (pk == NULL || pk_len == 0) {
		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
		return -1;
	}

	if (wps->peer_pubkey_hash_set) {
		u8 hash[WPS_HASH_LEN];
		sha256_vector(1, &pk, &pk_len, hash);
		if (os_memcmp_const(hash, wps->peer_pubkey_hash,
				    WPS_OOB_PUBKEY_HASH_LEN) != 0) {
			wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
			wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
				    pk, pk_len);
			wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
				    "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
			wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
				    wps->peer_pubkey_hash,
				    WPS_OOB_PUBKEY_HASH_LEN);
			wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
			return -1;
		}
	}

	wpabuf_free(wps->dh_pubkey_r);
	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
	if (wps->dh_pubkey_r == NULL)
		return -1;

	if (wps_derive_keys(wps) < 0)
		return -1;

	return 0;
}
Exemple #18
0
static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
				       struct eap_method_ret *ret,
				       const struct wpabuf *reqData)
{
	struct eap_pax_data *data = priv;
	const struct eap_pax_hdr *req;
	struct wpabuf *resp;
	u8 icvbuf[EAP_PAX_ICV_LEN], id;
	const u8 *icv, *pos;
	size_t len;
	u16 flen, mlen;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len);
	if (pos == NULL || len < sizeof(*req) + EAP_PAX_ICV_LEN) {
		ret->ignore = TRUE;
		return NULL;
	}
	id = eap_get_id(reqData);
	req = (const struct eap_pax_hdr *) pos;
	flen = len - EAP_PAX_ICV_LEN;
	mlen = wpabuf_len(reqData) - EAP_PAX_ICV_LEN;

	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
		   "public_key_id 0x%x",
		   req->op_code, req->flags, req->mac_id, req->dh_group_id,
		   req->public_key_id);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
		    pos, len - EAP_PAX_ICV_LEN);

	if (data->state != PAX_INIT && data->mac_id != req->mac_id) {
		wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
			   "authentication (was 0x%d, is 0x%d)",
			   data->mac_id, req->mac_id);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) {
		wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
			   "authentication (was 0x%d, is 0x%d)",
			   data->dh_group_id, req->dh_group_id);
		ret->ignore = TRUE;
		return NULL;
	}

	if (data->state != PAX_INIT &&
	    data->public_key_id != req->public_key_id) {
		wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
			   "authentication (was 0x%d, is 0x%d)",
			   data->public_key_id, req->public_key_id);
		ret->ignore = TRUE;
		return NULL;
	}

	/* TODO: add support EAP_PAX_HMAC_SHA256_128 */
	if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
			   req->mac_id);
		ret->ignore = TRUE;
		return NULL;
	}

	if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
			   req->dh_group_id);
		ret->ignore = TRUE;
		return NULL;
	}

	if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
			   req->public_key_id);
		ret->ignore = TRUE;
		return NULL;
	}

	if (req->flags & EAP_PAX_FLAGS_MF) {
		/* TODO: add support for reassembling fragments */
		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
			   "ignored packet");
		ret->ignore = TRUE;
		return NULL;
	}

	icv = pos + len - EAP_PAX_ICV_LEN;
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
	if (req->op_code == EAP_PAX_OP_STD_1) {
		eap_pax_mac(req->mac_id, (u8 *) "", 0,
			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
			    icvbuf);
	} else {
		eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
			    icvbuf);
	}
	if (os_memcmp_const(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
			   "message");
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
			    icvbuf, EAP_PAX_ICV_LEN);
		ret->ignore = TRUE;
		return NULL;
	}

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

	switch (req->op_code) {
	case EAP_PAX_OP_STD_1:
		resp = eap_pax_process_std_1(data, ret, id, req, flen);
		break;
	case EAP_PAX_OP_STD_3:
		resp = eap_pax_process_std_3(data, ret, id, req, flen);
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
			   "op_code %d", req->op_code);
		ret->ignore = TRUE;
		return NULL;
	}

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

	return resp;
}
Exemple #19
0
static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
					     struct eap_method_ret *ret, u8 id,
					     const struct eap_pax_hdr *req,
					     size_t req_plen)
{
	struct wpabuf *resp;
	u8 *rpos, mac[EAP_PAX_MAC_LEN];
	const u8 *pos;
	size_t left;

	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)");

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

	if (req->flags & EAP_PAX_FLAGS_CE) {
		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
			   "ignored");
		ret->ignore = TRUE;
		return NULL;
	}

	left = req_plen - sizeof(*req);

	if (left < 2 + EAP_PAX_MAC_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
			   "payload");
		ret->ignore = TRUE;
		return NULL;
	}

	pos = (const u8 *) (req + 1);
	if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
			   "MAC_CK length %d (expected %d)",
			   WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
		ret->ignore = TRUE;
		return NULL;
	}
	pos += 2;
	left -= 2;
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
		    pos, EAP_PAX_MAC_LEN);
	eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
		    data->rand.r.y, EAP_PAX_RAND_LEN,
		    (u8 *) data->cid, data->cid_len, NULL, 0, mac);
	if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
			   "received");
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
			    mac, EAP_PAX_MAC_LEN);
		ret->methodState = METHOD_DONE;
		ret->decision = DECISION_FAIL;
		return NULL;
	}

	pos += EAP_PAX_MAC_LEN;
	left -= EAP_PAX_MAC_LEN;

	if (left > 0) {
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
			    pos, left);
	}

	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)");

	resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_ACK, EAP_PAX_ICV_LEN);
	if (resp == NULL)
		return NULL;

	/* Optional ADE could be added here, if needed */

	rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN);
	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
		    wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
		    NULL, 0, NULL, 0, rpos);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);

	data->state = PAX_DONE;
	ret->methodState = METHOD_DONE;
	ret->decision = DECISION_UNCOND_SUCC;
	ret->allowNotifications = FALSE;

	return resp;
}
/**
 * pmksa_cache_add - Add a PMKSA cache entry
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 * @pmk: The new pairwise master key
 * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
 * @pmkid: Calculated PMKID
 * @kck: Key confirmation key or %NULL if not yet derived
 * @kck_len: KCK length in bytes
 * @aa: Authenticator address
 * @spa: Supplicant address
 * @network_ctx: Network configuration context for this PMK
 * @akmp: WPA_KEY_MGMT_* used in key derivation
 * Returns: Pointer to the added PMKSA cache entry or %NULL on error
 *
 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
 * cache. If an old entry is already in the cache for the same Authenticator,
 * this entry will be replaced with the new entry. PMKID will be calculated
 * based on the PMK and the driver interface is notified of the new PMKID.
 */
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
		const u8 *pmkid, const u8 *kck, size_t kck_len,
		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
	struct os_reltime now;

	if (pmk_len > PMK_LEN_MAX)
		return NULL;

	if (wpa_key_mgmt_suite_b(akmp) && !kck)
		return NULL;

	entry = os_zalloc(sizeof(*entry));
	if (entry == NULL)
		return NULL;
	os_memcpy(entry->pmk, pmk, pmk_len);
	entry->pmk_len = pmk_len;
	if (pmkid)
		os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
	else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
		rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
	else if (wpa_key_mgmt_suite_b(akmp))
		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
	else
		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
			  wpa_key_mgmt_sha256(akmp));
	os_get_reltime(&now);
	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
	entry->akmp = akmp;
	os_memcpy(entry->aa, aa, ETH_ALEN);
	entry->network_ctx = network_ctx;

	/* Replace an old entry for the same Authenticator (if found) with the
	 * new entry */
	pos = pmksa->pmksa;
	prev = NULL;
	while (pos) {
		if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
			if (pos->pmk_len == pmk_len &&
			    os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
			    os_memcmp_const(pos->pmkid, entry->pmkid,
					    PMKID_LEN) == 0) {
				wpa_printf(MSG_DEBUG, "WPA: reusing previous "
					   "PMKSA entry");
				os_free(entry);
				return pos;
			}
			if (prev == NULL)
				pmksa->pmksa = pos->next;
			else
				prev->next = pos->next;

			/*
			 * If OKC is used, there may be other PMKSA cache
			 * entries based on the same PMK. These needs to be
			 * flushed so that a new entry can be created based on
			 * the new PMK. Only clear other entries if they have a
			 * matching PMK and this PMK has been used successfully
			 * with the current AP, i.e., if opportunistic flag has
			 * been cleared in wpa_supplicant_key_neg_complete().
			 */
			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
				   "the current AP and any PMKSA cache entry "
				   "that was based on the old PMK");
			if (!pos->opportunistic)
				pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
						  pos->pmk_len);
			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
			break;
		}
		prev = pos;
		pos = pos->next;
	}

	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
		/* Remove the oldest entry to make room for the new entry */
		pos = pmksa->pmksa;

		if (pos == pmksa->sm->cur_pmksa) {
			/*
			 * Never remove the current PMKSA cache entry, since
			 * it's in use, and removing it triggers a needless
			 * deauthentication.
			 */
			pos = pos->next;
			pmksa->pmksa->next = pos ? pos->next : NULL;
		} else
			pmksa->pmksa = pos->next;

		if (pos) {
			wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
				   "PMKSA cache entry (for " MACSTR ") to "
				   "make room for new one",
				   MAC2STR(pos->aa));
			pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
		}
	}

	/* Add the new entry; order by expiration time */
	pos = pmksa->pmksa;
	prev = NULL;
	while (pos) {
		if (pos->expiration > entry->expiration)
			break;
		prev = pos;
		pos = pos->next;
	}
	if (prev == NULL) {
		entry->next = pmksa->pmksa;
		pmksa->pmksa = entry;
		pmksa_cache_set_expiration(pmksa);
	} else {
		entry->next = prev->next;
		prev->next = entry;
	}
	pmksa->pmksa_count++;
	wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
		   " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
	wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);

	return entry;
}
static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
				       const u8 *in_data, size_t *in_len)
{
	const u8 *pos, *end;
	size_t left, len, hlen;
	u8 verify_data[TLS_VERIFY_DATA_LEN];
	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];

	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
			   "received content type 0x%x", ct);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}

	pos = in_data;
	left = *in_len;

	if (left < 4) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
			   "Finished",
			   (unsigned long) left);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}

	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
			   "type 0x%x", pos[0]);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}

	len = WPA_GET_BE24(pos + 1);

	pos += 4;
	left -= 4;

	if (len > left) {
		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
			   "(len=%lu > left=%lu)",
			   (unsigned long) len, (unsigned long) left);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}
	end = pos + len;
	if (len != TLS_VERIFY_DATA_LEN) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
			   "in Finished: %lu (expected %d)",
			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECODE_ERROR);
		return -1;
	}
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
		    pos, TLS_VERIFY_DATA_LEN);

#ifdef CONFIG_TLSV12
	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
		hlen = SHA256_MAC_LEN;
		if (conn->verify.sha256_server == NULL ||
		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
		    < 0) {
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			conn->verify.sha256_server = NULL;
			return -1;
		}
		conn->verify.sha256_server = NULL;
	} else {
#endif /* CONFIG_TLSV12 */

	hlen = MD5_MAC_LEN;
	if (conn->verify.md5_server == NULL ||
	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		conn->verify.md5_server = NULL;
		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
		conn->verify.sha1_server = NULL;
		return -1;
	}
	conn->verify.md5_server = NULL;
	hlen = SHA1_MAC_LEN;
	if (conn->verify.sha1_server == NULL ||
	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
			       &hlen) < 0) {
		conn->verify.sha1_server = NULL;
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	conn->verify.sha1_server = NULL;
	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;

#ifdef CONFIG_TLSV12
	}
#endif /* CONFIG_TLSV12 */

	if (tls_prf(conn->rl.tls_version,
		    conn->master_secret, TLS_MASTER_SECRET_LEN,
		    "server finished", hash, hlen,
		    verify_data, TLS_VERIFY_DATA_LEN)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECRYPT_ERROR);
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
			verify_data, TLS_VERIFY_DATA_LEN);

	if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_DECRYPT_ERROR);
		return -1;
	}

	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");

	*in_len = end - in_data;

	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
		CHANGE_CIPHER_SPEC : ACK_FINISHED;

	return 0;
}
static void eap_eke_process_confirm(struct eap_sm *sm,
				    struct eap_eke_data *data,
				    const struct wpabuf *respData,
				    const u8 *payload, size_t payloadlen)
{
	size_t decrypt_len;
	u8 nonce[EAP_EKE_MAX_NONCE_LEN];
	u8 auth_p[EAP_EKE_MAX_HASH_LEN];

	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");

	if (data->state != CONFIRM) {
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");

	if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	decrypt_len = sizeof(nonce);
	if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
				 nonce, &decrypt_len) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}
	if (decrypt_len < (size_t) data->sess.nonce_len) {
		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}
	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
			nonce, data->sess.nonce_len);
	if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}

	if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}
	wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
	if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len,
			    data->sess.prf_len) != 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}

	if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
			       data->peerid, data->peerid_len,
			       data->nonce_s, data->nonce_p,
			       data->msk, data->emsk) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}

	os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
	os_memset(data->key, 0, sizeof(data->key));
	eap_eke_session_clean(&data->sess);

	eap_eke_state(data, SUCCESS);
}
static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
			     struct wpabuf *respData)
{
	struct eap_pax_data *data = priv;
	struct eap_pax_hdr *resp;
	const u8 *pos;
	size_t len, mlen;
	u8 icvbuf[EAP_PAX_ICV_LEN], *icv;

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
	if (pos == NULL || len < sizeof(*resp)) {
		wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
		return TRUE;
	}

	mlen = sizeof(struct eap_hdr) + 1 + len;
	resp = (struct eap_pax_hdr *) pos;

	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
		   "public_key_id 0x%x",
		   resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
		   resp->public_key_id);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
		    (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);

	if (data->state == PAX_STD_1 &&
	    resp->op_code != EAP_PAX_OP_STD_2) {
		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
			   "ignore op %d", resp->op_code);
		return TRUE;
	}

	if (data->state == PAX_STD_3 &&
	    resp->op_code != EAP_PAX_OP_ACK) {
		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
			   "ignore op %d", resp->op_code);
		return TRUE;
	}

	if (resp->op_code != EAP_PAX_OP_STD_2 &&
	    resp->op_code != EAP_PAX_OP_ACK) {
		wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
			   resp->op_code);
	}

	if (data->mac_id != resp->mac_id) {
		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
			   "received 0x%x", data->mac_id, resp->mac_id);
		return TRUE;
	}

	if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
		wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
			   "received 0x%x", EAP_PAX_DH_GROUP_NONE,
			   resp->dh_group_id);
		return TRUE;
	}

	if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
		wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
			   "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
			   resp->public_key_id);
		return TRUE;
	}

	if (resp->flags & EAP_PAX_FLAGS_MF) {
		/* TODO: add support for reassembling fragments */
		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
		return TRUE;
	}

	if (resp->flags & EAP_PAX_FLAGS_CE) {
		wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
		return TRUE;
	}

	if (data->keys_set) {
		if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
			wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
			return TRUE;
		}
		icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
		eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
			    wpabuf_mhead(respData),
			    wpabuf_len(respData) - EAP_PAX_ICV_LEN,
			    NULL, 0, NULL, 0, icvbuf);
		if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
			wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
			wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
				    icvbuf, EAP_PAX_ICV_LEN);
			return TRUE;
		}
	}

	return FALSE;
}
Exemple #24
0
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
			    int ft_action, const u8 *target_ap,
			    const u8 *ric_ies, size_t ric_ies_len)
{
	u8 *ft_ies;
	size_t ft_ies_len;
	struct wpa_ft_ies parse;
	struct rsn_mdie *mdie;
	struct rsn_ftie *ftie;
	u8 ptk_name[WPA_PMK_NAME_LEN];
	int ret;
	const u8 *bssid;

	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);

	if (ft_action) {
		if (!sm->over_the_ds_in_progress) {
			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
				   "- drop FT Action Response");
			return -1;
		}

		if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
				   "with this Target AP - drop FT Action "
				   "Response");
			return -1;
		}
	}

	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
			   "enabled for this connection");
		return -1;
	}

	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
		return -1;
	}

	mdie = (struct rsn_mdie *) parse.mdie;
	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
		      MOBILITY_DOMAIN_ID_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
		return -1;
	}

	ftie = (struct rsn_ftie *) parse.ftie;
	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
		return -1;
	}

	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
			    ftie->snonce, WPA_NONCE_LEN);
		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
			    sm->snonce, WPA_NONCE_LEN);
		return -1;
	}

	if (parse.r0kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
		return -1;
	}

	if (parse.r0kh_id_len != sm->r0kh_id_len ||
	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
	{
		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
			   "the current R0KH-ID");
		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
			    parse.r0kh_id, parse.r0kh_id_len);
		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
			    sm->r0kh_id, sm->r0kh_id_len);
		return -1;
	}

	if (parse.r1kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
		return -1;
	}

	if (parse.rsn_pmkid == NULL ||
	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
	{
		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
			   "RSNIE");
		return -1;
	}

	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);

	bssid = target_ap;
	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
			      sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
			      ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
		return -1;

	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
				    sm->pmk_r1_name,
				    sm->ptk.kck, sm->ptk.kck_len, bssid,
				    ric_ies, ric_ies_len,
				    parse.mdie ? parse.mdie - 2 : NULL);
	if (ft_ies) {
		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
				     ft_ies, ft_ies_len);
		os_free(ft_ies);
	}

	wpa_sm_mark_authenticated(sm, bssid);
	ret = wpa_ft_install_ptk(sm, bssid);
	if (ret) {
		/*
		 * Some drivers do not support key configuration when we are
		 * not associated with the target AP. Work around this by
		 * trying again after the following reassociation gets
		 * completed.
		 */
		wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
			   "association - try again after reassociation");
		sm->set_ptk_after_assoc = 1;
	} else
		sm->set_ptk_after_assoc = 0;

	sm->ft_completed = 1;
	if (ft_action) {
		/*
		 * The caller is expected trigger re-association with the
		 * Target AP.
		 */
		os_memcpy(sm->bssid, target_ap, ETH_ALEN);
	}

	return 0;
}
Exemple #25
0
static void
eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
			     const u8 *payload, size_t payload_len)
{
	BIGNUM *x = NULL, *y = NULL;
	struct crypto_hash *hash;
	u32 cs;
	u16 grp;
	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
	int offset;

	/* build up the ciphersuite: group | random_function | prf */
	grp = htons(data->group_num);
	ptr = (u8 *) &cs;
	os_memcpy(ptr, &grp, sizeof(u16));
	ptr += sizeof(u16);
	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
	ptr += sizeof(u8);
	*ptr = EAP_PWD_DEFAULT_PRF;

	/* each component of the cruft will be at most as big as the prime */
	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
		wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
		goto fin;
	}

	/*
	 * commit is H(k | peer_element | peer_scalar | server_element |
	 *	       server_scalar | ciphersuite)
	 */
	hash = eap_pwd_h_init();
	if (hash == NULL)
		goto fin;

	/* k */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
	BN_bn2bin(data->k, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* peer element: x, y */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->peer_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
			   "assignment fail");
		goto fin;
	}
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* peer scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->peer_scalar);
	BN_bn2bin(data->peer_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* server element: x, y */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->my_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
			   "assignment fail");
		goto fin;
	}

	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* server scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->my_scalar);
	BN_bn2bin(data->my_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* ciphersuite */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));

	/* all done */
	eap_pwd_h_final(hash, conf);

	ptr = (u8 *) payload;
	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
			   "verify");
		goto fin;
	}

	wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
	if (compute_keys(data->grp, data->bnctx, data->k,
			 data->peer_scalar, data->my_scalar, conf,
			 data->my_confirm, &cs, data->msk, data->emsk,
			 data->session_id) < 0)
		eap_pwd_state(data, FAILURE);
	else
		eap_pwd_state(data, SUCCESS);

fin:
	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
	BN_clear_free(x);
	BN_clear_free(y);
}
static void
eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
				 struct eap_method_ret *ret,
				 const struct wpabuf *reqData,
				 const u8 *payload, size_t payload_len)
{
	BIGNUM *x = NULL, *y = NULL;
	struct crypto_hash *hash;
	u32 cs;
	u16 grp;
	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
	int offset;

	if (data->state != PWD_Confirm_Req) {
		ret->ignore = TRUE;
		goto fin;
	}

	if (payload_len != SHA256_MAC_LEN) {
		wpa_printf(MSG_INFO,
			   "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
			   (unsigned int) payload_len, SHA256_MAC_LEN);
		goto fin;
	}

	/*
	 * first build up the ciphersuite which is group | random_function |
	 *	prf
	 */
	grp = htons(data->group_num);
	ptr = (u8 *) &cs;
	os_memcpy(ptr, &grp, sizeof(u16));
	ptr += sizeof(u16);
	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
	ptr += sizeof(u8);
	*ptr = EAP_PWD_DEFAULT_PRF;

	/* each component of the cruft will be at most as big as the prime */
	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
			   "fail");
		goto fin;
	}

	/*
	 * server's commit is H(k | server_element | server_scalar |
	 *			peer_element | peer_scalar | ciphersuite)
	 */
	hash = eap_pwd_h_init();
	if (hash == NULL)
		goto fin;

	/*
	 * zero the memory each time because this is mod prime math and some
	 * value may start with a few zeros and the previous one did not.
	 */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
	BN_bn2bin(data->k, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* server element: x, y */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->server_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
			   "assignment fail");
		goto fin;
	}
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* server scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->server_scalar);
	BN_bn2bin(data->server_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* my element: x, y */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->my_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
			   "assignment fail");
		goto fin;
	}

	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* my scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->my_scalar);
	BN_bn2bin(data->my_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* the ciphersuite */
	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));

	/* random function fin */
	eap_pwd_h_final(hash, conf);

	ptr = (u8 *) payload;
	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
		goto fin;
	}

	wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");

	/*
	 * compute confirm:
	 *  H(k | peer_element | peer_scalar | server_element | server_scalar |
	 *    ciphersuite)
	 */
	hash = eap_pwd_h_init();
	if (hash == NULL)
		goto fin;

	/* k */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
	BN_bn2bin(data->k, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* my element */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->my_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
			   "assignment fail");
		goto fin;
	}
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* my scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->my_scalar);
	BN_bn2bin(data->my_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* server element: x, y */
	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
						 data->server_element, x, y,
						 data->bnctx)) {
		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
			   "assignment fail");
		goto fin;
	}
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
	BN_bn2bin(x, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
	BN_bn2bin(y, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));

	/* server scalar */
	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
	offset = BN_num_bytes(data->grp->order) -
		BN_num_bytes(data->server_scalar);
	BN_bn2bin(data->server_scalar, cruft + offset);
	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));

	/* the ciphersuite */
	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));

	/* all done */
	eap_pwd_h_final(hash, conf);

	if (compute_keys(data->grp, data->bnctx, data->k,
			 data->my_scalar, data->server_scalar, conf, ptr,
			 &cs, data->msk, data->emsk, data->session_id) < 0) {
		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
			   "EMSK");
		goto fin;
	}

	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
	if (data->outbuf == NULL)
		goto fin;

	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);

fin:
	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
	BN_clear_free(x);
	BN_clear_free(y);
	if (data->outbuf == NULL) {
		ret->methodState = METHOD_DONE;
		ret->decision = DECISION_FAIL;
		eap_pwd_state(data, FAILURE);
	} else {
		eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
	}
}
static void eap_pax_process_std_2(struct eap_sm *sm,
				  struct eap_pax_data *data,
				  struct wpabuf *respData)
{
	struct eap_pax_hdr *resp;
	u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
	const u8 *pos;
	size_t len, left;
	int i;

	if (data->state != PAX_STD_1)
		return;

	wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");

	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
	if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
		return;

	resp = (struct eap_pax_hdr *) pos;
	pos = (u8 *) (resp + 1);
	left = len - sizeof(*resp);

	if (left < 2 + EAP_PAX_RAND_LEN ||
	    WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
		return;
	}
	pos += 2;
	left -= 2;
	os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
		    data->rand.r.y, EAP_PAX_RAND_LEN);
	pos += EAP_PAX_RAND_LEN;
	left -= EAP_PAX_RAND_LEN;

	if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
		return;
	}
	data->cid_len = WPA_GET_BE16(pos);
	os_free(data->cid);
	data->cid = os_malloc(data->cid_len);
	if (data->cid == NULL) {
		wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
			   "CID");
		return;
	}
	os_memcpy(data->cid, pos + 2, data->cid_len);
	pos += 2 + data->cid_len;
	left -= 2 + data->cid_len;
	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
			  (u8 *) data->cid, data->cid_len);

	if (left < 2 + EAP_PAX_MAC_LEN ||
	    WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
		return;
	}
	pos += 2;
	left -= 2;
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
		    pos, EAP_PAX_MAC_LEN);

	if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
				  (u8 *) data->cid, data->cid_len);
		data->state = FAILURE;
		return;
	}

	for (i = 0;
	     i < EAP_MAX_METHODS &&
		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
		      sm->user->methods[i].method != EAP_TYPE_NONE);
	     i++) {
		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
		    sm->user->methods[i].method == EAP_TYPE_PAX)
			break;
	}

	if (i >= EAP_MAX_METHODS ||
	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
	    sm->user->methods[i].method != EAP_TYPE_PAX) {
		wpa_hexdump_ascii(MSG_DEBUG,
				  "EAP-PAX: EAP-PAX not enabled for CID",
				  (u8 *) data->cid, data->cid_len);
		data->state = FAILURE;
		return;
	}

	if (sm->user->password == NULL ||
	    sm->user->password_len != EAP_PAX_AK_LEN) {
		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
				  "user database for CID",
				  (u8 *) data->cid, data->cid_len);
		data->state = FAILURE;
		return;
	}
	os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);

	if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
					   data->rand.e, data->mk, data->ck,
					   data->ick) < 0) {
		wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
			   "key derivation");
		data->state = FAILURE;
		return;
	}
	data->keys_set = 1;

	eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
		    data->rand.r.x, EAP_PAX_RAND_LEN,
		    data->rand.r.y, EAP_PAX_RAND_LEN,
		    (u8 *) data->cid, data->cid_len, mac);
	if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) {
		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
			   "PAX_STD-2");
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
			    mac, EAP_PAX_MAC_LEN);
		data->state = FAILURE;
		return;
	}

	pos += EAP_PAX_MAC_LEN;
	left -= EAP_PAX_MAC_LEN;

	if (left < EAP_PAX_ICV_LEN) {
		wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
			   "PAX_STD-2", (unsigned long) left);
		return;
	}
	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
		    wpabuf_head(respData),
		    wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
		    icvbuf);
	if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
		wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
			    icvbuf, EAP_PAX_ICV_LEN);
		return;
	}
	pos += EAP_PAX_ICV_LEN;
	left -= EAP_PAX_ICV_LEN;

	if (left > 0) {
		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
			    pos, left);
	}

	data->state = PAX_STD_3;
}
Exemple #28
0
static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
				    struct eap_gpsk_data *data,
				    const u8 *payload, size_t payloadlen)
{
	const u8 *pos, *end;
	u16 alen;
	const struct eap_gpsk_csuite *csuite;
	size_t i, miclen;
	u8 mic[EAP_GPSK_MAX_MIC_LEN];

	if (data->state != GPSK_1)
		return;

	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");

	pos = payload;
	end = payload + payloadlen;

	if (end - pos < 2) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "ID_Peer length");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	alen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < alen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "ID_Peer");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	os_free(data->id_peer);
	data->id_peer = os_malloc(alen);
	if (data->id_peer == NULL) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
			   "%d-octet ID_Peer", alen);
		return;
	}
	os_memcpy(data->id_peer, pos, alen);
	data->id_peer_len = alen;
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
			  data->id_peer, data->id_peer_len);
	pos += alen;

	if (end - pos < 2) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "ID_Server length");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	alen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < alen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "ID_Server");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (alen != sm->server_id_len ||
	    os_memcmp(pos, sm->server_id, alen) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
			   "GPSK-2 did not match");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	pos += alen;

	if (end - pos < EAP_GPSK_RAND_LEN) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "RAND_Peer");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
		    data->rand_peer, EAP_GPSK_RAND_LEN);
	pos += EAP_GPSK_RAND_LEN;

	if (end - pos < EAP_GPSK_RAND_LEN) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "RAND_Server");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
			   "GPSK-2 did not match");
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
			    data->rand_server, EAP_GPSK_RAND_LEN);
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
			    pos, EAP_GPSK_RAND_LEN);
		eap_gpsk_state(data, FAILURE);
		return;
	}
	pos += EAP_GPSK_RAND_LEN;

	if (end - pos < 2) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "CSuite_List length");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	alen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < alen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "CSuite_List");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
	    os_memcmp(pos, data->csuite_list, alen) != 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
			   "GPSK-2 did not match");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	pos += alen;

	if (end - pos < (int) sizeof(*csuite)) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "CSuite_Sel");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	csuite = (const struct eap_gpsk_csuite *) pos;
	for (i = 0; i < data->csuite_count; i++) {
		if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
		    == 0)
			break;
	}
	if (i == data->csuite_count) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
			   "ciphersuite %d:%d",
			   WPA_GET_BE32(csuite->vendor),
			   WPA_GET_BE16(csuite->specifier));
		eap_gpsk_state(data, FAILURE);
		return;
	}
	data->vendor = WPA_GET_BE32(csuite->vendor);
	data->specifier = WPA_GET_BE16(csuite->specifier);
	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
		   data->vendor, data->specifier);
	pos += sizeof(*csuite);	

	if (end - pos < 2) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "PD_Payload_1 length");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	alen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < alen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "PD_Payload_1");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
	pos += alen;

	if (sm->user == NULL || sm->user->password == NULL) {
		wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
			   "for the user");
		eap_gpsk_state(data, FAILURE);
		return;
	}

	if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
				 data->vendor, data->specifier,
				 data->rand_peer, data->rand_server,
				 data->id_peer, data->id_peer_len,
				 sm->server_id, sm->server_id_len,
				 data->msk, data->emsk,
				 data->sk, &data->sk_len,
				 data->pk, &data->pk_len) < 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
		eap_gpsk_state(data, FAILURE);
		return;
	}

	if (eap_gpsk_derive_session_id(sm->user->password,
				       sm->user->password_len,
				       data->vendor, data->specifier,
				       data->rand_peer, data->rand_server,
				       data->id_peer, data->id_peer_len,
				       sm->server_id, sm->server_id_len,
				       EAP_TYPE_GPSK,
				       data->session_id, &data->id_len) < 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
		    data->session_id, data->id_len);

	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
	if (end - pos < (int) miclen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
			   "(left=%lu miclen=%lu)",
			   (unsigned long) (end - pos),
			   (unsigned long) miclen);
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
				 data->specifier, payload, pos - payload, mic)
	    < 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (os_memcmp_const(mic, pos, miclen) != 0) {
		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
		eap_gpsk_state(data, FAILURE);
		return;
	}
	pos += miclen;

	if (pos != end) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
			   "data in the end of GPSK-2",
			   (unsigned long) (end - pos));
	}

	eap_gpsk_state(data, GPSK_3);
}
Exemple #29
0
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
				 size_t ies_len, const u8 *src_addr)
{
	struct wpa_ft_ies parse;
	struct rsn_mdie *mdie;
	struct rsn_ftie *ftie;
	unsigned int count;
	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];

	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);

	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
			   "enabled for this connection");
		return -1;
	}

	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
		return -1;
	}

	mdie = (struct rsn_mdie *) parse.mdie;
	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
		      MOBILITY_DOMAIN_ID_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
		return -1;
	}

	ftie = (struct rsn_ftie *) parse.ftie;
	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
		return -1;
	}

	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
			    ftie->snonce, WPA_NONCE_LEN);
		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
			    sm->snonce, WPA_NONCE_LEN);
		return -1;
	}

	if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
			    ftie->anonce, WPA_NONCE_LEN);
		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
			    sm->anonce, WPA_NONCE_LEN);
		return -1;
	}

	if (parse.r0kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
		return -1;
	}

	if (parse.r0kh_id_len != sm->r0kh_id_len ||
	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
	{
		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
			   "the current R0KH-ID");
		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
			    parse.r0kh_id, parse.r0kh_id_len);
		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
			    sm->r0kh_id, sm->r0kh_id_len);
		return -1;
	}

	if (parse.r1kh_id == NULL) {
		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
		return -1;
	}

	if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
			   "ReassocResp");
		return -1;
	}

	if (parse.rsn_pmkid == NULL ||
	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
	{
		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
		return -1;
	}

	count = 3;
	if (parse.ric)
		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
	if (ftie->mic_control[1] != count) {
		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
			   "Control: received %u expected %u",
			   ftie->mic_control[1], count);
		return -1;
	}

	if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
		       parse.mdie - 2, parse.mdie_len + 2,
		       parse.ftie - 2, parse.ftie_len + 2,
		       parse.rsn - 2, parse.rsn_len + 2,
		       parse.ric, parse.ric_len,
		       mic) < 0) {
		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
		return -1;
	}

	if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
		return -1;
	}

	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
		return -1;

#ifdef CONFIG_IEEE80211W
	if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
		return -1;
#endif /* CONFIG_IEEE80211W */

	if (sm->set_ptk_after_assoc) {
		wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
			   "are associated");
		if (wpa_ft_install_ptk(sm, src_addr) < 0)
			return -1;
		sm->set_ptk_after_assoc = 0;
	}

	if (parse.ric) {
		wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
			    parse.ric, parse.ric_len);
		/* TODO: parse response and inform driver about results when
		 * using wpa_supplicant SME */
	}

	wpa_printf(MSG_DEBUG, "FT: Completed successfully");

	return 0;
}
Exemple #30
0
static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
				    struct eap_gpsk_data *data,
				    const u8 *payload, size_t payloadlen)
{
	const u8 *pos, *end;
	u16 alen;
	size_t miclen;
	u8 mic[EAP_GPSK_MAX_MIC_LEN];

	if (data->state != GPSK_3)
		return;

	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");

	pos = payload;
	end = payload + payloadlen;

	if (end - pos < 2) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "PD_Payload_1 length");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	alen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < alen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
			   "PD_Payload_1");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
	pos += alen;

	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
	if (end - pos < (int) miclen) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
			   "(left=%lu miclen=%lu)",
			   (unsigned long) (end - pos),
			   (unsigned long) miclen);
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
				 data->specifier, payload, pos - payload, mic)
	    < 0) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
		eap_gpsk_state(data, FAILURE);
		return;
	}
	if (os_memcmp_const(mic, pos, miclen) != 0) {
		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
		eap_gpsk_state(data, FAILURE);
		return;
	}
	pos += miclen;

	if (pos != end) {
		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
			   "data in the end of GPSK-4",
			   (unsigned long) (end - pos));
	}

	eap_gpsk_state(data, SUCCESS);
}