hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / eap_common / eap_ikev2_common.c
1 /*
2  * EAP-IKEv2 common routines
3  * Copyright (c) 2007, Jouni Malinen <j@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 }