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