xref: /freebsd/contrib/wpa/src/eap_common/eap_ikev2_common.c (revision 416ba5c74546f32a993436a99516d35008e9f384)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP-IKEv2 common routines
339beb93cSSam Leffler  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
1239beb93cSSam Leffler #include "eap_defs.h"
1339beb93cSSam Leffler #include "eap_common.h"
1439beb93cSSam Leffler #include "ikev2_common.h"
1539beb93cSSam Leffler #include "eap_ikev2_common.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler 
eap_ikev2_derive_keymat(int prf,struct ikev2_keys * keys,const u8 * i_nonce,size_t i_nonce_len,const u8 * r_nonce,size_t r_nonce_len,u8 * keymat)1839beb93cSSam Leffler int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
1939beb93cSSam Leffler 			    const u8 *i_nonce, size_t i_nonce_len,
2039beb93cSSam Leffler 			    const u8 *r_nonce, size_t r_nonce_len,
2139beb93cSSam Leffler 			    u8 *keymat)
2239beb93cSSam Leffler {
2339beb93cSSam Leffler 	u8 *nonces;
2439beb93cSSam Leffler 	size_t nlen;
2539beb93cSSam Leffler 
2639beb93cSSam Leffler 	/* KEYMAT = prf+(SK_d, Ni | Nr) */
2739beb93cSSam Leffler 	if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
2839beb93cSSam Leffler 		return -1;
2939beb93cSSam Leffler 
3039beb93cSSam Leffler 	nlen = i_nonce_len + r_nonce_len;
3139beb93cSSam Leffler 	nonces = os_malloc(nlen);
3239beb93cSSam Leffler 	if (nonces == NULL)
3339beb93cSSam Leffler 		return -1;
3439beb93cSSam Leffler 	os_memcpy(nonces, i_nonce, i_nonce_len);
3539beb93cSSam Leffler 	os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
3639beb93cSSam Leffler 
3739beb93cSSam Leffler 	if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
3839beb93cSSam Leffler 			   keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
3939beb93cSSam Leffler 		os_free(nonces);
4039beb93cSSam Leffler 		return -1;
4139beb93cSSam Leffler 	}
4239beb93cSSam Leffler 	os_free(nonces);
4339beb93cSSam Leffler 
4439beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
4539beb93cSSam Leffler 			keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
4639beb93cSSam Leffler 
4739beb93cSSam Leffler 	return 0;
4839beb93cSSam Leffler }
4939beb93cSSam Leffler 
5039beb93cSSam Leffler 
eap_ikev2_build_frag_ack(u8 id,u8 code)5139beb93cSSam Leffler struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
5239beb93cSSam Leffler {
5339beb93cSSam Leffler 	struct wpabuf *msg;
5439beb93cSSam Leffler 
5539beb93cSSam Leffler 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
5639beb93cSSam Leffler 	if (msg == NULL) {
5739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
5839beb93cSSam Leffler 			   "for fragment ack");
5939beb93cSSam Leffler 		return NULL;
6039beb93cSSam Leffler 	}
6139beb93cSSam Leffler 
6239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
6339beb93cSSam Leffler 
6439beb93cSSam Leffler 	return msg;
6539beb93cSSam Leffler }
6639beb93cSSam Leffler 
6739beb93cSSam Leffler 
eap_ikev2_validate_icv(int integ_alg,struct ikev2_keys * keys,int initiator,const struct wpabuf * msg,const u8 * pos,const u8 * end)6839beb93cSSam Leffler int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
6939beb93cSSam Leffler 			   int initiator, const struct wpabuf *msg,
7039beb93cSSam Leffler 			   const u8 *pos, const u8 *end)
7139beb93cSSam Leffler {
7239beb93cSSam Leffler 	const struct ikev2_integ_alg *integ;
7339beb93cSSam Leffler 	size_t icv_len;
7439beb93cSSam Leffler 	u8 icv[IKEV2_MAX_HASH_LEN];
7539beb93cSSam Leffler 	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	integ = ikev2_get_integ(integ_alg);
7839beb93cSSam Leffler 	if (integ == NULL) {
7939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
8039beb93cSSam Leffler 			   "transform / cannot validate ICV");
8139beb93cSSam Leffler 		return -1;
8239beb93cSSam Leffler 	}
8339beb93cSSam Leffler 	icv_len = integ->hash_len;
8439beb93cSSam Leffler 
8539beb93cSSam Leffler 	if (end - pos < (int) icv_len) {
8639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
8739beb93cSSam Leffler 			   "message for Integrity Checksum Data");
8839beb93cSSam Leffler 		return -1;
8939beb93cSSam Leffler 	}
9039beb93cSSam Leffler 
9139beb93cSSam Leffler 	if (SK_a == NULL) {
9239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
9339beb93cSSam Leffler 		return -1;
9439beb93cSSam Leffler 	}
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
9739beb93cSSam Leffler 			     wpabuf_head(msg),
9839beb93cSSam Leffler 			     wpabuf_len(msg) - icv_len, icv) < 0) {
9939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
10039beb93cSSam Leffler 		return -1;
10139beb93cSSam Leffler 	}
10239beb93cSSam Leffler 
103*5b9c547cSRui Paulo 	if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) {
10439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
10539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
10639beb93cSSam Leffler 			    icv, icv_len);
10739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
10839beb93cSSam Leffler 			    end - icv_len, icv_len);
10939beb93cSSam Leffler 		return -1;
11039beb93cSSam Leffler 	}
11139beb93cSSam Leffler 
11239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
11339beb93cSSam Leffler 		   "the received message");
11439beb93cSSam Leffler 
11539beb93cSSam Leffler 	return icv_len;
11639beb93cSSam Leffler }
117