1/* 2 * EAP-IKEv2 common routines 3 * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "eap_defs.h" 19#include "eap_common.h" 20#include "ikev2_common.h" 21#include "eap_ikev2_common.h" 22 23 24int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, 25 const u8 *i_nonce, size_t i_nonce_len, 26 const u8 *r_nonce, size_t r_nonce_len, 27 u8 *keymat) 28{ 29 u8 *nonces; 30 size_t nlen; 31 32 /* KEYMAT = prf+(SK_d, Ni | Nr) */ 33 if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL) 34 return -1; 35 36 nlen = i_nonce_len + r_nonce_len; 37 nonces = os_malloc(nlen); 38 if (nonces == NULL) 39 return -1; 40 os_memcpy(nonces, i_nonce, i_nonce_len); 41 os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len); 42 43 if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen, 44 keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) { 45 os_free(nonces); 46 return -1; 47 } 48 os_free(nonces); 49 50 wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT", 51 keymat, EAP_MSK_LEN + EAP_EMSK_LEN); 52 53 return 0; 54} 55 56 57struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) 58{ 59 struct wpabuf *msg; 60 61#ifdef CCNS_PL 62 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); 63 if (msg == NULL) { 64 wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 65 "for fragment ack"); 66 return NULL; 67 } 68 wpabuf_put_u8(msg, 0); /* Flags */ 69#else /* CCNS_PL */ 70 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); 71 if (msg == NULL) { 72 wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 73 "for fragment ack"); 74 return NULL; 75 } 76#endif /* CCNS_PL */ 77 78 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); 79 80 return msg; 81} 82 83 84int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, 85 int initiator, const struct wpabuf *msg, 86 const u8 *pos, const u8 *end) 87{ 88 const struct ikev2_integ_alg *integ; 89 size_t icv_len; 90 u8 icv[IKEV2_MAX_HASH_LEN]; 91 const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 92 93 integ = ikev2_get_integ(integ_alg); 94 if (integ == NULL) { 95 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 96 "transform / cannot validate ICV"); 97 return -1; 98 } 99 icv_len = integ->hash_len; 100 101 if (end - pos < (int) icv_len) { 102 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the " 103 "message for Integrity Checksum Data"); 104 return -1; 105 } 106 107 if (SK_a == NULL) { 108 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation"); 109 return -1; 110 } 111 112 if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len, 113 wpabuf_head(msg), 114 wpabuf_len(msg) - icv_len, icv) < 0) { 115 wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV"); 116 return -1; 117 } 118 119 if (os_memcmp(icv, end - icv_len, icv_len) != 0) { 120 wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); 121 wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", 122 icv, icv_len); 123 wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV", 124 end - icv_len, icv_len); 125 return -1; 126 } 127 128 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in " 129 "the received message"); 130 131 return icv_len; 132} 133