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 
eap_ikev2_derive_keymat(int prf,struct ikev2_keys * keys,const u8 * i_nonce,size_t i_nonce_len,const u8 * r_nonce,size_t r_nonce_len,u8 * keymat)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 
eap_ikev2_build_frag_ack(u8 id,u8 code)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 
eap_ikev2_validate_icv(int integ_alg,struct ikev2_keys * keys,int initiator,const struct wpabuf * msg,const u8 * pos,const u8 * end)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