eap_ikev2_common.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-IKEv2 common routines
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2_common.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_ikev2_common.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *i_nonce, size_t i_nonce_len,
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *r_nonce, size_t r_nonce_len,
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    u8 *keymat)
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *nonces;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t nlen;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* KEYMAT = prf+(SK_d, Ni | Nr) */
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlen = i_nonce_len + r_nonce_len;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nonces = os_malloc(nlen);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nonces == NULL)
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(nonces, i_nonce, i_nonce_len);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(nonces);
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(nonces);
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for fragment ack");
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, 0); /* Flags */
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CCNS_PL */
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for fragment ack");
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int initiator, const struct wpabuf *msg,
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *pos, const u8 *end)
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t icv_len;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 icv[IKEV2_MAX_HASH_LEN];
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ = ikev2_get_integ(integ_alg);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ == NULL) {
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "transform / cannot validate ICV");
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	icv_len = integ->hash_len;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (end - pos < (int) icv_len) {
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "message for Integrity Checksum Data");
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     wpabuf_head(msg),
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     wpabuf_len(msg) - icv_len, icv) < 0) {
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    icv, icv_len);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    end - icv_len, icv_len);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "the received message");
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return icv_len;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
133