1189251Ssam/* 2189251Ssam * EAP-IKEv2 common routines 3189251Ssam * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18189251Ssam#include "eap_defs.h" 19189251Ssam#include "eap_common.h" 20189251Ssam#include "ikev2_common.h" 21189251Ssam#include "eap_ikev2_common.h" 22189251Ssam 23189251Ssam 24189251Ssamint eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, 25189251Ssam const u8 *i_nonce, size_t i_nonce_len, 26189251Ssam const u8 *r_nonce, size_t r_nonce_len, 27189251Ssam u8 *keymat) 28189251Ssam{ 29189251Ssam u8 *nonces; 30189251Ssam size_t nlen; 31189251Ssam 32189251Ssam /* KEYMAT = prf+(SK_d, Ni | Nr) */ 33189251Ssam if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL) 34189251Ssam return -1; 35189251Ssam 36189251Ssam nlen = i_nonce_len + r_nonce_len; 37189251Ssam nonces = os_malloc(nlen); 38189251Ssam if (nonces == NULL) 39189251Ssam return -1; 40189251Ssam os_memcpy(nonces, i_nonce, i_nonce_len); 41189251Ssam os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len); 42189251Ssam 43189251Ssam if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen, 44189251Ssam keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) { 45189251Ssam os_free(nonces); 46189251Ssam return -1; 47189251Ssam } 48189251Ssam os_free(nonces); 49189251Ssam 50189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT", 51189251Ssam keymat, EAP_MSK_LEN + EAP_EMSK_LEN); 52189251Ssam 53189251Ssam return 0; 54189251Ssam} 55189251Ssam 56189251Ssam 57189251Ssamstruct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) 58189251Ssam{ 59189251Ssam struct wpabuf *msg; 60189251Ssam 61189251Ssam#ifdef CCNS_PL 62189251Ssam msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); 63189251Ssam if (msg == NULL) { 64189251Ssam wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 65189251Ssam "for fragment ack"); 66189251Ssam return NULL; 67189251Ssam } 68189251Ssam wpabuf_put_u8(msg, 0); /* Flags */ 69189251Ssam#else /* CCNS_PL */ 70189251Ssam msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); 71189251Ssam if (msg == NULL) { 72189251Ssam wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 73189251Ssam "for fragment ack"); 74189251Ssam return NULL; 75189251Ssam } 76189251Ssam#endif /* CCNS_PL */ 77189251Ssam 78189251Ssam wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); 79189251Ssam 80189251Ssam return msg; 81189251Ssam} 82189251Ssam 83189251Ssam 84189251Ssamint eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, 85189251Ssam int initiator, const struct wpabuf *msg, 86189251Ssam const u8 *pos, const u8 *end) 87189251Ssam{ 88189251Ssam const struct ikev2_integ_alg *integ; 89189251Ssam size_t icv_len; 90189251Ssam u8 icv[IKEV2_MAX_HASH_LEN]; 91189251Ssam const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 92189251Ssam 93189251Ssam integ = ikev2_get_integ(integ_alg); 94189251Ssam if (integ == NULL) { 95189251Ssam wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 96189251Ssam "transform / cannot validate ICV"); 97189251Ssam return -1; 98189251Ssam } 99189251Ssam icv_len = integ->hash_len; 100189251Ssam 101189251Ssam if (end - pos < (int) icv_len) { 102189251Ssam wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the " 103189251Ssam "message for Integrity Checksum Data"); 104189251Ssam return -1; 105189251Ssam } 106189251Ssam 107189251Ssam if (SK_a == NULL) { 108189251Ssam wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation"); 109189251Ssam return -1; 110189251Ssam } 111189251Ssam 112189251Ssam if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len, 113189251Ssam wpabuf_head(msg), 114189251Ssam wpabuf_len(msg) - icv_len, icv) < 0) { 115189251Ssam wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV"); 116189251Ssam return -1; 117189251Ssam } 118189251Ssam 119189251Ssam if (os_memcmp(icv, end - icv_len, icv_len) != 0) { 120189251Ssam wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); 121189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", 122189251Ssam icv, icv_len); 123189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV", 124189251Ssam end - icv_len, icv_len); 125189251Ssam return -1; 126189251Ssam } 127189251Ssam 128189251Ssam wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in " 129189251Ssam "the received message"); 130189251Ssam 131189251Ssam return icv_len; 132189251Ssam} 133