Home | History | Annotate | Download | only in eap_common
      1 /*
      2  * EAP-IKEv2 common routines
      3  * Copyright (c) 2007, Jouni Malinen <j (at) 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 
     24 int 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 
     57 struct 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 
     84 int 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