18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-IKEv2 common routines 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_defs.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2_common.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_ikev2_common.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *i_nonce, size_t i_nonce_len, 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *r_nonce, size_t r_nonce_len, 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *keymat) 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *nonces; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t nlen; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* KEYMAT = prf+(SK_d, Ni | Nr) */ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL) 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nlen = i_nonce_len + r_nonce_len; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nonces = os_malloc(nlen); 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nonces == NULL) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(nonces, i_nonce, i_nonce_len); 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len); 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen, 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) { 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(nonces); 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(nonces); 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT", 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keymat, EAP_MSK_LEN + EAP_EMSK_LEN); 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) { 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for fragment ack"); 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, 0); /* Flags */ 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CCNS_PL */ 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) { 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for fragment ack"); 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */ 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int initiator, const struct wpabuf *msg, 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, const u8 *end) 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t icv_len; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 icv[IKEV2_MAX_HASH_LEN]; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ = ikev2_get_integ(integ_alg); 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (integ == NULL) { 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "transform / cannot validate ICV"); 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt icv_len = integ->hash_len; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < (int) icv_len) { 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the " 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "message for Integrity Checksum Data"); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (SK_a == NULL) { 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation"); 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len, 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(msg), 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg) - icv_len, icv) < 0) { 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV"); 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(icv, end - icv_len, icv_len) != 0) { 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt icv, icv_len); 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV", 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end - icv_len, icv_len); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in " 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "the received message"); 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return icv_len; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 127