132 lines
3.3 KiB
C
132 lines
3.3 KiB
C
/*
|
|
* EAP-IKEv2 common routines
|
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of BSD
|
|
* license.
|
|
*
|
|
* See README and COPYING for more details.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#include "common.h"
|
|
#include "eap_defs.h"
|
|
#include "eap_common.h"
|
|
#include "ikev2_common.h"
|
|
#include "eap_ikev2_common.h"
|
|
|
|
|
|
int 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)
|
|
{
|
|
u8 *nonces;
|
|
size_t nlen;
|
|
|
|
/* KEYMAT = prf+(SK_d, Ni | Nr) */
|
|
if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
|
|
return -1;
|
|
|
|
nlen = i_nonce_len + r_nonce_len;
|
|
nonces = os_malloc(nlen);
|
|
if (nonces == NULL)
|
|
return -1;
|
|
os_memcpy(nonces, i_nonce, i_nonce_len);
|
|
os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
|
|
|
|
if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
|
|
keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
|
|
os_free(nonces);
|
|
return -1;
|
|
}
|
|
os_free(nonces);
|
|
|
|
wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
|
|
keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
|
|
{
|
|
struct wpabuf *msg;
|
|
|
|
#ifdef CCNS_PL
|
|
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
|
|
if (msg == NULL) {
|
|
wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
|
|
"for fragment ack");
|
|
return NULL;
|
|
}
|
|
wpabuf_put_u8(msg, 0); /* Flags */
|
|
#else /* CCNS_PL */
|
|
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
|
|
if (msg == NULL) {
|
|
wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
|
|
"for fragment ack");
|
|
return NULL;
|
|
}
|
|
#endif /* CCNS_PL */
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
|
|
int initiator, const struct wpabuf *msg,
|
|
const u8 *pos, const u8 *end)
|
|
{
|
|
const struct ikev2_integ_alg *integ;
|
|
size_t icv_len;
|
|
u8 icv[IKEV2_MAX_HASH_LEN];
|
|
const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
|
|
|
|
integ = ikev2_get_integ(integ_alg);
|
|
if (integ == NULL) {
|
|
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
|
|
"transform / cannot validate ICV");
|
|
return -1;
|
|
}
|
|
icv_len = integ->hash_len;
|
|
|
|
if (end - pos < (int) icv_len) {
|
|
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
|
|
"message for Integrity Checksum Data");
|
|
return -1;
|
|
}
|
|
|
|
if (SK_a == NULL) {
|
|
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
|
|
return -1;
|
|
}
|
|
|
|
if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
|
|
wpabuf_head(msg),
|
|
wpabuf_len(msg) - icv_len, icv) < 0) {
|
|
wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
|
|
return -1;
|
|
}
|
|
|
|
if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
|
|
wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
|
|
wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
|
|
icv, icv_len);
|
|
wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
|
|
end - icv_len, icv_len);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
|
|
"the received message");
|
|
|
|
return icv_len;
|
|
}
|