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 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 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
     56 	if (msg == NULL) {
     57 		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
     58 			   "for fragment ack");
     59 		return NULL;
     60 	}
     61 
     62 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
     63 
     64 	return msg;
     65 }
     66 
     67 
     68 int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
     69 			   int initiator, const struct wpabuf *msg,
     70 			   const u8 *pos, const u8 *end)
     71 {
     72 	const struct ikev2_integ_alg *integ;
     73 	size_t icv_len;
     74 	u8 icv[IKEV2_MAX_HASH_LEN];
     75 	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
     76 
     77 	integ = ikev2_get_integ(integ_alg);
     78 	if (integ == NULL) {
     79 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
     80 			   "transform / cannot validate ICV");
     81 		return -1;
     82 	}
     83 	icv_len = integ->hash_len;
     84 
     85 	if (end - pos < (int) icv_len) {
     86 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
     87 			   "message for Integrity Checksum Data");
     88 		return -1;
     89 	}
     90 
     91 	if (SK_a == NULL) {
     92 		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
     93 		return -1;
     94 	}
     95 
     96 	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
     97 			     wpabuf_head(msg),
     98 			     wpabuf_len(msg) - icv_len, icv) < 0) {
     99 		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
    100 		return -1;
    101 	}
    102 
    103 	if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) {
    104 		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
    105 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
    106 			    icv, icv_len);
    107 		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
    108 			    end - icv_len, icv_len);
    109 		return -1;
    110 	}
    111 
    112 	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
    113 		   "the received message");
    114 
    115 	return icv_len;
    116 }
    117