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 
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 
51 struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
52 {
53 	struct wpabuf *msg;
54 
55 #ifdef CCNS_PL
56 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
57 	if (msg == NULL) {
58 		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
59 			   "for fragment ack");
60 		return NULL;
61 	}
62 	wpabuf_put_u8(msg, 0); /* Flags */
63 #else /* CCNS_PL */
64 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
65 	if (msg == NULL) {
66 		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
67 			   "for fragment ack");
68 		return NULL;
69 	}
70 #endif /* CCNS_PL */
71 
72 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
73 
74 	return msg;
75 }
76 
77 
78 int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
79 			   int initiator, const struct wpabuf *msg,
80 			   const u8 *pos, const u8 *end)
81 {
82 	const struct ikev2_integ_alg *integ;
83 	size_t icv_len;
84 	u8 icv[IKEV2_MAX_HASH_LEN];
85 	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
86 
87 	integ = ikev2_get_integ(integ_alg);
88 	if (integ == NULL) {
89 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
90 			   "transform / cannot validate ICV");
91 		return -1;
92 	}
93 	icv_len = integ->hash_len;
94 
95 	if (end - pos < (int) icv_len) {
96 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
97 			   "message for Integrity Checksum Data");
98 		return -1;
99 	}
100 
101 	if (SK_a == NULL) {
102 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
103 		return -1;
104 	}
105 
106 	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
107 			     wpabuf_head(msg),
108 			     wpabuf_len(msg) - icv_len, icv) < 0) {
109 		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
110 		return -1;
111 	}
112 
113 	if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
114 		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
115 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
116 			    icv, icv_len);
117 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
118 			    end - icv_len, icv_len);
119 		return -1;
120 	}
121 
122 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
123 		   "the received message");
124 
125 	return icv_len;
126 }
127