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