1  /*
2   * EAP-IKEv2 common routines
3   * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4   *
5   * This software may be distributed under the terms of the BSD license.
6   * See README for more details.
7   */
8  
9  #include "includes.h"
10  
11  #include "common.h"
12  #include "eap_defs.h"
13  #include "eap_common.h"
14  #include "ikev2_common.h"
15  #include "eap_ikev2_common.h"
16  
17  
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)18  int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
19  			    const u8 *i_nonce, size_t i_nonce_len,
20  			    const u8 *r_nonce, size_t r_nonce_len,
21  			    u8 *keymat)
22  {
23  	u8 *nonces;
24  	size_t nlen;
25  
26  	/* KEYMAT = prf+(SK_d, Ni | Nr) */
27  	if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
28  		return -1;
29  
30  	nlen = i_nonce_len + r_nonce_len;
31  	nonces = os_malloc(nlen);
32  	if (nonces == NULL)
33  		return -1;
34  	os_memcpy(nonces, i_nonce, i_nonce_len);
35  	os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
36  
37  	if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
38  			   keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
39  		os_free(nonces);
40  		return -1;
41  	}
42  	os_free(nonces);
43  
44  	wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
45  			keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
46  
47  	return 0;
48  }
49  
50  
eap_ikev2_build_frag_ack(u8 id,u8 code)51  struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
52  {
53  	struct wpabuf *msg;
54  
55  	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
56  	if (msg == NULL) {
57  		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
58  			   "for fragment ack");
59  		return NULL;
60  	}
61  
62  	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
63  
64  	return msg;
65  }
66  
67  
eap_ikev2_validate_icv(int integ_alg,struct ikev2_keys * keys,int initiator,const struct wpabuf * msg,const u8 * pos,const u8 * end)68  int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
69  			   int initiator, const struct wpabuf *msg,
70  			   const u8 *pos, const u8 *end)
71  {
72  	const struct ikev2_integ_alg *integ;
73  	size_t icv_len;
74  	u8 icv[IKEV2_MAX_HASH_LEN];
75  	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
76  
77  	integ = ikev2_get_integ(integ_alg);
78  	if (integ == NULL) {
79  		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
80  			   "transform / cannot validate ICV");
81  		return -1;
82  	}
83  	icv_len = integ->hash_len;
84  
85  	if (end - pos < (int) icv_len) {
86  		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
87  			   "message for Integrity Checksum Data");
88  		return -1;
89  	}
90  
91  	if (SK_a == NULL) {
92  		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
93  		return -1;
94  	}
95  
96  	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
97  			     wpabuf_head(msg),
98  			     wpabuf_len(msg) - icv_len, icv) < 0) {
99  		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
100  		return -1;
101  	}
102  
103  	if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) {
104  		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
105  		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
106  			    icv, icv_len);
107  		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
108  			    end - icv_len, icv_len);
109  		return -1;
110  	}
111  
112  	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
113  		   "the received message");
114  
115  	return icv_len;
116  }
117