xref: /dragonfly/contrib/wpa_supplicant/src/ap/wpa_auth_kay.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * IEEE 802.1X-2010 KaY Interface
3  * Copyright (c) 2019, The Linux Foundation
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 
11 #include "utils/common.h"
12 #include "pae/ieee802_1x_key.h"
13 #include "pae/ieee802_1x_kay.h"
14 #include "hostapd.h"
15 #include "sta_info.h"
16 #include "wpa_auth_kay.h"
17 #include "ieee802_1x.h"
18 
19 
20 #define DEFAULT_KEY_LEN                 16
21 /* secure Connectivity Association Key Name (CKN) */
22 #define DEFAULT_CKN_LEN                 16
23 
24 
hapd_macsec_init(void * priv,struct macsec_init_params * params)25 static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
26 {
27           struct hostapd_data *hapd = priv;
28 
29           if (!hapd->driver->macsec_init)
30                     return -1;
31           return hapd->driver->macsec_init(hapd->drv_priv, params);
32 }
33 
34 
hapd_macsec_deinit(void * priv)35 static int hapd_macsec_deinit(void *priv)
36 {
37           struct hostapd_data *hapd = priv;
38 
39           if (!hapd->driver->macsec_deinit)
40                     return -1;
41           return hapd->driver->macsec_deinit(hapd->drv_priv);
42 }
43 
44 
hapd_macsec_get_capability(void * priv,enum macsec_cap * cap)45 static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
46 {
47           struct hostapd_data *hapd = priv;
48 
49           if (!hapd->driver->macsec_get_capability)
50                     return -1;
51           return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
52 }
53 
54 
hapd_enable_protect_frames(void * priv,Boolean enabled)55 static int hapd_enable_protect_frames(void *priv, Boolean enabled)
56 {
57           struct hostapd_data *hapd = priv;
58 
59           if (!hapd->driver->enable_protect_frames)
60                     return -1;
61           return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
62 }
63 
64 
hapd_enable_encrypt(void * priv,Boolean enabled)65 static int hapd_enable_encrypt(void *priv, Boolean enabled)
66 {
67           struct hostapd_data *hapd = priv;
68 
69           if (!hapd->driver->enable_encrypt)
70                     return -1;
71           return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
72 }
73 
74 
hapd_set_replay_protect(void * priv,Boolean enabled,u32 window)75 static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
76 {
77           struct hostapd_data *hapd = priv;
78 
79           if (!hapd->driver->set_replay_protect)
80                     return -1;
81           return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
82                                                              window);
83 }
84 
85 
hapd_set_current_cipher_suite(void * priv,u64 cs)86 static int hapd_set_current_cipher_suite(void *priv, u64 cs)
87 {
88           struct hostapd_data *hapd = priv;
89 
90           if (!hapd->driver->set_current_cipher_suite)
91                     return -1;
92           return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
93 }
94 
95 
hapd_enable_controlled_port(void * priv,Boolean enabled)96 static int hapd_enable_controlled_port(void *priv, Boolean enabled)
97 {
98           struct hostapd_data *hapd = priv;
99 
100           if (!hapd->driver->enable_controlled_port)
101                     return -1;
102           return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
103 }
104 
105 
hapd_get_receive_lowest_pn(void * priv,struct receive_sa * sa)106 static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
107 {
108           struct hostapd_data *hapd = priv;
109 
110           if (!hapd->driver->get_receive_lowest_pn)
111                     return -1;
112           return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
113 }
114 
115 
hapd_get_transmit_next_pn(void * priv,struct transmit_sa * sa)116 static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
117 {
118           struct hostapd_data *hapd = priv;
119 
120           if (!hapd->driver->get_transmit_next_pn)
121                     return -1;
122           return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
123 }
124 
125 
hapd_set_transmit_next_pn(void * priv,struct transmit_sa * sa)126 static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
127 {
128           struct hostapd_data *hapd = priv;
129 
130           if (!hapd->driver->set_transmit_next_pn)
131                     return -1;
132           return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
133 }
134 
135 
conf_offset_val(enum confidentiality_offset co)136 static unsigned int conf_offset_val(enum confidentiality_offset co)
137 {
138           switch (co) {
139           case CONFIDENTIALITY_OFFSET_30:
140                     return 30;
141                     break;
142           case CONFIDENTIALITY_OFFSET_50:
143                     return 50;
144           default:
145                     return 0;
146           }
147 }
148 
149 
hapd_create_receive_sc(void * priv,struct receive_sc * sc,enum validate_frames vf,enum confidentiality_offset co)150 static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
151                                           enum validate_frames vf,
152                                           enum confidentiality_offset co)
153 {
154           struct hostapd_data *hapd = priv;
155 
156           if (!hapd->driver->create_receive_sc)
157                     return -1;
158           return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
159                                                          conf_offset_val(co), vf);
160 }
161 
162 
hapd_delete_receive_sc(void * priv,struct receive_sc * sc)163 static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
164 {
165           struct hostapd_data *hapd = priv;
166 
167           if (!hapd->driver->delete_receive_sc)
168                     return -1;
169           return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
170 }
171 
172 
hapd_create_receive_sa(void * priv,struct receive_sa * sa)173 static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
174 {
175           struct hostapd_data *hapd = priv;
176 
177           if (!hapd->driver->create_receive_sa)
178                     return -1;
179           return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
180 }
181 
182 
hapd_delete_receive_sa(void * priv,struct receive_sa * sa)183 static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
184 {
185           struct hostapd_data *hapd = priv;
186 
187           if (!hapd->driver->delete_receive_sa)
188                     return -1;
189           return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
190 }
191 
192 
hapd_enable_receive_sa(void * priv,struct receive_sa * sa)193 static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
194 {
195           struct hostapd_data *hapd = priv;
196 
197           if (!hapd->driver->enable_receive_sa)
198                     return -1;
199           return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
200 }
201 
202 
hapd_disable_receive_sa(void * priv,struct receive_sa * sa)203 static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
204 {
205           struct hostapd_data *hapd = priv;
206 
207           if (!hapd->driver->disable_receive_sa)
208                     return -1;
209           return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
210 }
211 
212 
213 static int
hapd_create_transmit_sc(void * priv,struct transmit_sc * sc,enum confidentiality_offset co)214 hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
215                               enum confidentiality_offset co)
216 {
217           struct hostapd_data *hapd = priv;
218 
219           if (!hapd->driver->create_transmit_sc)
220                     return -1;
221           return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
222                                                             conf_offset_val(co));
223 }
224 
225 
hapd_delete_transmit_sc(void * priv,struct transmit_sc * sc)226 static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
227 {
228           struct hostapd_data *hapd = priv;
229 
230           if (!hapd->driver->delete_transmit_sc)
231                     return -1;
232           return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
233 }
234 
235 
hapd_create_transmit_sa(void * priv,struct transmit_sa * sa)236 static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
237 {
238           struct hostapd_data *hapd = priv;
239 
240           if (!hapd->driver->create_transmit_sa)
241                     return -1;
242           return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
243 }
244 
245 
hapd_delete_transmit_sa(void * priv,struct transmit_sa * sa)246 static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
247 {
248           struct hostapd_data *hapd = priv;
249 
250           if (!hapd->driver->delete_transmit_sa)
251                     return -1;
252           return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
253 }
254 
255 
hapd_enable_transmit_sa(void * priv,struct transmit_sa * sa)256 static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
257 {
258           struct hostapd_data *hapd = priv;
259 
260           if (!hapd->driver->enable_transmit_sa)
261                     return -1;
262           return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
263 }
264 
265 
hapd_disable_transmit_sa(void * priv,struct transmit_sa * sa)266 static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
267 {
268           struct hostapd_data *hapd = priv;
269 
270           if (!hapd->driver->disable_transmit_sa)
271                     return -1;
272           return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
273 }
274 
275 
ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data * hapd,struct sta_info * sta)276 int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
277                                          struct sta_info *sta)
278 {
279           struct ieee802_1x_kay_ctx *kay_ctx;
280           struct ieee802_1x_kay *res = NULL;
281           enum macsec_policy policy;
282 
283           ieee802_1x_dealloc_kay_sm_hapd(hapd);
284 
285           if (!hapd->conf || hapd->conf->macsec_policy == 0)
286                     return 0;
287 
288           if (hapd->conf->macsec_policy == 1) {
289                     if (hapd->conf->macsec_integ_only == 1)
290                               policy = SHOULD_SECURE;
291                     else
292                               policy = SHOULD_ENCRYPT;
293           } else {
294                     policy = DO_NOT_SECURE;
295           }
296 
297           wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
298           kay_ctx = os_zalloc(sizeof(*kay_ctx));
299           if (!kay_ctx)
300                     return -1;
301 
302           kay_ctx->ctx = hapd;
303 
304           kay_ctx->macsec_init = hapd_macsec_init;
305           kay_ctx->macsec_deinit = hapd_macsec_deinit;
306           kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
307           kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
308           kay_ctx->enable_encrypt = hapd_enable_encrypt;
309           kay_ctx->set_replay_protect = hapd_set_replay_protect;
310           kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
311           kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
312           kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
313           kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
314           kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
315           kay_ctx->create_receive_sc = hapd_create_receive_sc;
316           kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
317           kay_ctx->create_receive_sa = hapd_create_receive_sa;
318           kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
319           kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
320           kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
321           kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
322           kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
323           kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
324           kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
325           kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
326           kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
327 
328           res = ieee802_1x_kay_init(kay_ctx, policy,
329                                           hapd->conf->macsec_replay_protect,
330                                           hapd->conf->macsec_replay_window,
331                                           hapd->conf->macsec_port,
332                                           hapd->conf->mka_priority, hapd->conf->iface,
333                                           hapd->own_addr);
334           /* ieee802_1x_kay_init() frees kay_ctx on failure */
335           if (!res)
336                     return -1;
337 
338           hapd->kay = res;
339 
340           return 0;
341 }
342 
343 
ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data * hapd)344 void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
345 {
346           if (!hapd->kay)
347                     return;
348 
349           ieee802_1x_kay_deinit(hapd->kay);
350           hapd->kay = NULL;
351 }
352 
353 
ieee802_1x_auth_get_session_id(struct hostapd_data * hapd,struct sta_info * sta,u8 * sid,size_t * len)354 static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
355                                                     struct sta_info *sta, u8 *sid,
356                                                     size_t *len)
357 {
358           const u8 *session_id;
359           size_t id_len, need_len;
360 
361           session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
362           if (!session_id) {
363                     wpa_printf(MSG_DEBUG,
364                                  "MACsec: Failed to get SessionID from EAPOL state machines");
365                     return -1;
366           }
367 
368           need_len = 1 + 2 * 32 /* random size */;
369           if (need_len > id_len) {
370                     wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
371                     return -1;
372           }
373 
374           os_memcpy(sid, session_id, need_len);
375           *len = need_len;
376 
377           return 0;
378 }
379 
380 
ieee802_1x_auth_get_msk(struct hostapd_data * hapd,struct sta_info * sta,u8 * msk,size_t * len)381 static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
382                                            struct sta_info *sta, u8 *msk, size_t *len)
383 {
384           const u8 *key;
385           size_t keylen;
386 
387           if (!sta->eapol_sm)
388                     return -1;
389 
390           key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
391           if (key == NULL) {
392                     wpa_printf(MSG_DEBUG,
393                                  "MACsec: Failed to get MSK from EAPOL state machines");
394                     return -1;
395           }
396           wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
397                        (unsigned long) keylen);
398           wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
399 
400           if (keylen > *len)
401                     keylen = *len;
402           os_memcpy(msk, key, keylen);
403           *len = keylen;
404 
405           return 0;
406 }
407 
408 
ieee802_1x_notify_create_actor_hapd(struct hostapd_data * hapd,struct sta_info * sta)409 void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
410                                                      struct sta_info *sta)
411 {
412           u8 *sid;
413           size_t sid_len = 128;
414           struct mka_key_name *ckn;
415           struct mka_key *cak;
416           struct mka_key *msk;
417           void *res = NULL;
418 
419           if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
420                     return NULL;
421 
422           wpa_printf(MSG_DEBUG,
423                        "IEEE 802.1X: External notification - Create MKA for "
424                        MACSTR, MAC2STR(sta->addr));
425 
426           msk = os_zalloc(sizeof(*msk));
427           sid = os_zalloc(sid_len);
428           ckn = os_zalloc(sizeof(*ckn));
429           cak = os_zalloc(sizeof(*cak));
430           if (!msk || !sid || !ckn || !cak)
431                     goto fail;
432 
433           msk->len = DEFAULT_KEY_LEN;
434           if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
435                     wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
436                     goto fail;
437           }
438 
439           if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
440           {
441                     wpa_printf(MSG_ERROR,
442                                  "IEEE 802.1X: Could not get EAP Session Id");
443                     goto fail;
444           }
445 
446           wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
447           wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
448 
449           /* Derive CAK from MSK */
450           cak->len = DEFAULT_KEY_LEN;
451           if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
452                                             sta->addr, cak->key, cak->len)) {
453                     wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
454                     goto fail;
455           }
456           wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
457 
458           /* Derive CKN from MSK */
459           ckn->len = DEFAULT_CKN_LEN;
460           if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
461                                             sta->addr, sid, sid_len, ckn->name)) {
462                     wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
463                     goto fail;
464           }
465           wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
466 
467           res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
468                                                   TRUE);
469 
470 fail:
471           bin_clear_free(msk, sizeof(*msk));
472           os_free(sid);
473           os_free(ckn);
474           bin_clear_free(cak, sizeof(*cak));
475 
476           return res;
477 }
478 
479 
ieee802_1x_create_preshared_mka_hapd(struct hostapd_data * hapd,struct sta_info * sta)480 void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
481                                                       struct sta_info *sta)
482 {
483           struct mka_key *cak;
484           struct mka_key_name *ckn;
485           void *res = NULL;
486 
487           if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
488                     goto end;
489 
490           ckn = os_zalloc(sizeof(*ckn));
491           if (!ckn)
492                     goto end;
493 
494           cak = os_zalloc(sizeof(*cak));
495           if (!cak)
496                     goto free_ckn;
497 
498           if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
499                     goto free_cak;
500 
501           if (hapd->kay->policy == DO_NOT_SECURE)
502                     goto dealloc;
503 
504           cak->len = hapd->conf->mka_cak_len;
505           os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
506 
507           ckn->len = hapd->conf->mka_ckn_len;;
508           os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
509 
510           res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
511           if (res)
512                     goto free_cak;
513 
514 dealloc:
515           /* Failed to create MKA */
516           ieee802_1x_dealloc_kay_sm_hapd(hapd);
517 free_cak:
518           os_free(cak);
519 free_ckn:
520           os_free(ckn);
521 end:
522           return res;
523 }
524