blob: 0b876008d5822abbe91bf397a9a1db67e561496f [file] [log] [blame]
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001/*
2 * IEEE 802.1X-2010 KaY Interface
3 * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8#include <openssl/ssl.h>
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "eap_peer/eap.h"
13#include "eap_peer/eap_i.h"
14#include "eapol_supp/eapol_supp_sm.h"
15#include "pae/ieee802_1x_key.h"
16#include "pae/ieee802_1x_kay.h"
17#include "wpa_supplicant_i.h"
18#include "config.h"
19#include "config_ssid.h"
20#include "driver_i.h"
21#include "wpas_kay.h"
22
23
24#define DEFAULT_KEY_LEN 16
25/* secure Connectivity Association Key Name (CKN) */
26#define DEFAULT_CKN_LEN 16
27
28
29static int wpas_macsec_init(void *priv, struct macsec_init_params *params)
30{
31 return wpa_drv_macsec_init(priv, params);
32}
33
34
35static int wpas_macsec_deinit(void *priv)
36{
37 return wpa_drv_macsec_deinit(priv);
38}
39
40
41static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
42{
43 return wpa_drv_enable_protect_frames(wpa_s, enabled);
44}
45
46
47static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
48{
49 return wpa_drv_set_replay_protect(wpa_s, enabled, window);
50}
51
52
53static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs,
54 size_t cs_len)
55{
56 return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
57}
58
59
60static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
61{
62 return wpa_drv_enable_controlled_port(wpa_s, enabled);
63}
64
65
66static int wpas_get_receive_lowest_pn(void *wpa_s, u32 channel,
67 u8 an, u32 *lowest_pn)
68{
69 return wpa_drv_get_receive_lowest_pn(wpa_s, channel, an, lowest_pn);
70}
71
72
73static int wpas_get_transmit_next_pn(void *wpa_s, u32 channel,
74 u8 an, u32 *next_pn)
75{
76 return wpa_drv_get_transmit_next_pn(wpa_s, channel, an, next_pn);
77}
78
79
80static int wpas_set_transmit_next_pn(void *wpa_s, u32 channel,
81 u8 an, u32 next_pn)
82{
83 return wpa_drv_set_transmit_next_pn(wpa_s, channel, an, next_pn);
84}
85
86
87static int wpas_get_available_receive_sc(void *wpa_s, u32 *channel)
88{
89 return wpa_drv_get_available_receive_sc(wpa_s, channel);
90}
91
92
93static unsigned int conf_offset_val(enum confidentiality_offset co)
94{
95 switch (co) {
96 case CONFIDENTIALITY_OFFSET_30:
97 return 30;
98 break;
99 case CONFIDENTIALITY_OFFSET_50:
100 return 50;
101 default:
102 return 0;
103 }
104}
105
106
107static int wpas_create_receive_sc(void *wpa_s, u32 channel,
108 struct ieee802_1x_mka_sci *sci,
109 enum validate_frames vf,
110 enum confidentiality_offset co)
111{
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -0700112 return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr,
113 be_to_host16(sci->port),
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -0700114 conf_offset_val(co), vf);
115}
116
117
118static int wpas_delete_receive_sc(void *wpa_s, u32 channel)
119{
120 return wpa_drv_delete_receive_sc(wpa_s, channel);
121}
122
123
124static int wpas_create_receive_sa(void *wpa_s, u32 channel, u8 an,
125 u32 lowest_pn, const u8 *sak)
126{
127 return wpa_drv_create_receive_sa(wpa_s, channel, an, lowest_pn, sak);
128}
129
130
131static int wpas_enable_receive_sa(void *wpa_s, u32 channel, u8 an)
132{
133 return wpa_drv_enable_receive_sa(wpa_s, channel, an);
134}
135
136
137static int wpas_disable_receive_sa(void *wpa_s, u32 channel, u8 an)
138{
139 return wpa_drv_disable_receive_sa(wpa_s, channel, an);
140}
141
142
143static int wpas_get_available_transmit_sc(void *wpa_s, u32 *channel)
144{
145 return wpa_drv_get_available_transmit_sc(wpa_s, channel);
146}
147
148
149static int
150wpas_create_transmit_sc(void *wpa_s, u32 channel,
151 const struct ieee802_1x_mka_sci *sci,
152 enum confidentiality_offset co)
153{
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -0700154 return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr,
155 be_to_host16(sci->port),
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -0700156 conf_offset_val(co));
157}
158
159
160static int wpas_delete_transmit_sc(void *wpa_s, u32 channel)
161{
162 return wpa_drv_delete_transmit_sc(wpa_s, channel);
163}
164
165
166static int wpas_create_transmit_sa(void *wpa_s, u32 channel, u8 an,
167 u32 next_pn, Boolean confidentiality,
168 const u8 *sak)
169{
170 return wpa_drv_create_transmit_sa(wpa_s, channel, an, next_pn,
171 confidentiality, sak);
172}
173
174
175static int wpas_enable_transmit_sa(void *wpa_s, u32 channel, u8 an)
176{
177 return wpa_drv_enable_transmit_sa(wpa_s, channel, an);
178}
179
180
181static int wpas_disable_transmit_sa(void *wpa_s, u32 channel, u8 an)
182{
183 return wpa_drv_disable_transmit_sa(wpa_s, channel, an);
184}
185
186
187int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
188{
189 struct ieee802_1x_kay_ctx *kay_ctx;
190 struct ieee802_1x_kay *res = NULL;
191 enum macsec_policy policy;
192
193 ieee802_1x_dealloc_kay_sm(wpa_s);
194
195 if (!ssid || ssid->macsec_policy == 0)
196 return 0;
197
198 policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
199
200 kay_ctx = os_zalloc(sizeof(*kay_ctx));
201 if (!kay_ctx)
202 return -1;
203
204 kay_ctx->ctx = wpa_s;
205
206 kay_ctx->macsec_init = wpas_macsec_init;
207 kay_ctx->macsec_deinit = wpas_macsec_deinit;
208 kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
209 kay_ctx->set_replay_protect = wpas_set_replay_protect;
210 kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
211 kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
212 kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn;
213 kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn;
214 kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn;
215 kay_ctx->get_available_receive_sc = wpas_get_available_receive_sc;
216 kay_ctx->create_receive_sc = wpas_create_receive_sc;
217 kay_ctx->delete_receive_sc = wpas_delete_receive_sc;
218 kay_ctx->create_receive_sa = wpas_create_receive_sa;
219 kay_ctx->enable_receive_sa = wpas_enable_receive_sa;
220 kay_ctx->disable_receive_sa = wpas_disable_receive_sa;
221 kay_ctx->get_available_transmit_sc = wpas_get_available_transmit_sc;
222 kay_ctx->create_transmit_sc = wpas_create_transmit_sc;
223 kay_ctx->delete_transmit_sc = wpas_delete_transmit_sc;
224 kay_ctx->create_transmit_sa = wpas_create_transmit_sa;
225 kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
226 kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
227
228 res = ieee802_1x_kay_init(kay_ctx, policy, wpa_s->ifname,
229 wpa_s->own_addr);
230 if (res == NULL) {
231 os_free(kay_ctx);
232 return -1;
233 }
234
235 wpa_s->kay = res;
236
237 return 0;
238}
239
240
241void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
242{
243 if (!wpa_s->kay)
244 return;
245
246 ieee802_1x_kay_deinit(wpa_s->kay);
247 wpa_s->kay = NULL;
248}
249
250
251static int ieee802_1x_auth_get_session_id(struct wpa_supplicant *wpa_s,
252 const u8 *addr, u8 *sid, size_t *len)
253{
254 const u8 *session_id;
255 size_t id_len, need_len;
256
257 session_id = eapol_sm_get_session_id(wpa_s->eapol, &id_len);
258 if (session_id == NULL) {
259 wpa_printf(MSG_DEBUG,
260 "Failed to get SessionID from EAPOL state machines");
261 return -1;
262 }
263
264 need_len = 1 + 2 * SSL3_RANDOM_SIZE;
265 if (need_len > id_len) {
266 wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
267 return -1;
268 }
269
270 os_memcpy(sid, session_id, need_len);
271 *len = need_len;
272
273 return 0;
274}
275
276
277static int ieee802_1x_auth_get_msk(struct wpa_supplicant *wpa_s, const u8 *addr,
278 u8 *msk, size_t *len)
279{
280 u8 key[EAP_MSK_LEN];
281 size_t keylen;
282 struct eapol_sm *sm;
283 int res;
284
285 sm = wpa_s->eapol;
286 if (sm == NULL)
287 return -1;
288
289 keylen = EAP_MSK_LEN;
290 res = eapol_sm_get_key(sm, key, keylen);
291 if (res) {
292 wpa_printf(MSG_DEBUG,
293 "Failed to get MSK from EAPOL state machines");
294 return -1;
295 }
296
297 if (keylen > *len)
298 keylen = *len;
299 os_memcpy(msk, key, keylen);
300 *len = keylen;
301
302 return 0;
303}
304
305
306void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
307 const u8 *peer_addr)
308{
309 u8 *sid;
310 size_t sid_len = 128;
311 struct mka_key_name *ckn;
312 struct mka_key *cak;
313 struct mka_key *msk;
314 void *res = NULL;
315
316 if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
317 return NULL;
318
319 wpa_printf(MSG_DEBUG,
320 "IEEE 802.1X: External notification - Create MKA for "
321 MACSTR, MAC2STR(peer_addr));
322
323 msk = os_zalloc(sizeof(*msk));
324 sid = os_zalloc(sid_len);
325 ckn = os_zalloc(sizeof(*ckn));
326 cak = os_zalloc(sizeof(*cak));
327 if (!msk || !sid || !ckn || !cak)
328 goto fail;
329
330 msk->len = DEFAULT_KEY_LEN;
331 if (ieee802_1x_auth_get_msk(wpa_s, wpa_s->bssid, msk->key, &msk->len)) {
332 wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
333 goto fail;
334 }
335
336 if (ieee802_1x_auth_get_session_id(wpa_s, wpa_s->bssid, sid, &sid_len))
337 {
338 wpa_printf(MSG_ERROR,
339 "IEEE 802.1X: Could not get EAP Session Id");
340 goto fail;
341 }
342
343 /* Derive CAK from MSK */
344 cak->len = DEFAULT_KEY_LEN;
345 if (ieee802_1x_cak_128bits_aes_cmac(msk->key, wpa_s->own_addr,
346 peer_addr, cak->key)) {
347 wpa_printf(MSG_ERROR,
348 "IEEE 802.1X: Deriving CAK failed");
349 goto fail;
350 }
351 wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
352
353 /* Derive CKN from MSK */
354 ckn->len = DEFAULT_CKN_LEN;
355 if (ieee802_1x_ckn_128bits_aes_cmac(msk->key, wpa_s->own_addr,
356 peer_addr, sid, sid_len,
357 ckn->name)) {
358 wpa_printf(MSG_ERROR,
359 "IEEE 802.1X: Deriving CKN failed");
360 goto fail;
361 }
362 wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
363
364 res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
365 EAP_EXCHANGE, FALSE);
366
367fail:
368 if (msk) {
369 os_memset(msk, 0, sizeof(*msk));
370 os_free(msk);
371 }
372 os_free(sid);
373 os_free(ckn);
374 if (cak) {
375 os_memset(cak, 0, sizeof(*cak));
376 os_free(cak);
377 }
378
379 return res;
380}