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
18int 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
51struct 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
68int 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