Merge branch 'vendor/LIBEDIT'
[dragonfly.git] / contrib / hostapd / hostapd / peerkey.c
1 /*
2  * hostapd - PeerKey for Direct Link Setup (DLS)
3  * Copyright (c) 2006-2008, 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 "eloop.h"
19 #include "sha1.h"
20 #include "sha256.h"
21 #include "wpa.h"
22 #include "defs.h"
23 #include "wpa_auth_i.h"
24 #include "wpa_auth_ie.h"
25
26 #ifdef CONFIG_PEERKEY
27
28 static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
29 {
30 #if 0
31         struct wpa_authenticator *wpa_auth = eloop_ctx;
32         struct wpa_stsl_negotiation *neg = timeout_ctx;
33 #endif
34
35         /* TODO: ? */
36 }
37
38
39 struct wpa_stsl_search {
40         const u8 *addr;
41         struct wpa_state_machine *sm;
42 };
43
44
45 static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
46 {
47         struct wpa_stsl_search *search = ctx;
48         if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
49                 search->sm = sm;
50                 return 1;
51         }
52         return 0;
53 }
54
55
56 static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
57                                struct wpa_state_machine *sm, const u8 *peer,
58                                u16 mui, u16 error_type)
59 {
60         u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
61                2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
62         u8 *pos;
63         struct rsn_error_kde error;
64
65         wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
66                         "Sending SMK Error");
67
68         pos = kde;
69
70         if (peer) {
71                 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
72                                   NULL, 0);
73         }
74
75         error.mui = host_to_be16(mui);
76         error.error_type = host_to_be16(error_type);
77         pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
78                           (u8 *) &error, sizeof(error), NULL, 0);
79
80         __wpa_send_eapol(wpa_auth, sm,
81                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
82                          WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
83                          NULL, NULL, kde, pos - kde, 0, 0, 0);
84 }
85
86
87 void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
88                 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
89 {
90         struct wpa_eapol_ie_parse kde;
91         struct wpa_stsl_search search;
92         u8 *buf, *pos;
93         size_t buf_len;
94
95         if (wpa_parse_kde_ies((const u8 *) (key + 1),
96                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
97                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
98                 return;
99         }
100
101         if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
102             kde.mac_addr_len < ETH_ALEN) {
103                 wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
104                            "SMK M1");
105                 return;
106         }
107
108         /* Initiator = sm->addr; Peer = kde.mac_addr */
109
110         search.addr = kde.mac_addr;
111         search.sm = NULL;
112         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
113             0 || search.sm == NULL) {
114                 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
115                            " aborted - STA not associated anymore",
116                            MAC2STR(kde.mac_addr));
117                 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
118                                    STK_ERR_STA_NR);
119                 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
120                 return;
121         }
122
123         buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
124         buf = os_malloc(buf_len);
125         if (buf == NULL)
126                 return;
127         /* Initiator RSN IE */
128         os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
129         pos = buf + kde.rsn_ie_len;
130         /* Initiator MAC Address */
131         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
132                           NULL, 0);
133
134         /* SMK M2:
135          * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
136          *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
137          */
138
139         wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
140                         "Sending SMK M2");
141
142         __wpa_send_eapol(wpa_auth, search.sm,
143                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
144                          WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
145                          NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
146
147         os_free(buf);
148 }
149
150
151 static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
152                             struct wpa_state_machine *sm,
153                             struct wpa_eapol_key *key,
154                             struct wpa_eapol_ie_parse *kde,
155                             const u8 *smk)
156 {
157         u8 *buf, *pos;
158         size_t buf_len;
159         u32 lifetime;
160
161         /* SMK M4:
162          * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
163          *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
164          *           Lifetime KDE)
165          */
166
167         buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
168                 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
169                 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
170                 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
171         pos = buf = os_malloc(buf_len);
172         if (buf == NULL)
173                 return;
174
175         /* Initiator MAC Address */
176         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
177                           NULL, 0);
178
179         /* Initiator Nonce */
180         pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
181                           NULL, 0);
182
183         /* SMK with PNonce */
184         pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
185                           key->key_nonce, WPA_NONCE_LEN);
186
187         /* Lifetime */
188         lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
189         pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
190                           (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
191
192         wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
193                         "Sending SMK M4");
194
195         __wpa_send_eapol(wpa_auth, sm,
196                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
197                          WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
198                          NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
199
200         os_free(buf);
201 }
202
203
204 static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
205                             struct wpa_state_machine *sm,
206                             struct wpa_eapol_key *key,
207                             struct wpa_eapol_ie_parse *kde,
208                             const u8 *smk, const u8 *peer)
209 {
210         u8 *buf, *pos;
211         size_t buf_len;
212         u32 lifetime;
213
214         /* SMK M5:
215          * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
216          *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
217          *                             Lifetime KDE))
218          */
219
220         buf_len = kde->rsn_ie_len +
221                 2 + RSN_SELECTOR_LEN + ETH_ALEN +
222                 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
223                 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
224                 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
225         pos = buf = os_malloc(buf_len);
226         if (buf == NULL)
227                 return;
228
229         /* Peer RSN IE */
230         os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
231         pos = buf + kde->rsn_ie_len;
232
233         /* Peer MAC Address */
234         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
235
236         /* PNonce */
237         pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
238                           WPA_NONCE_LEN, NULL, 0);
239
240         /* SMK and INonce */
241         pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
242                           kde->nonce, WPA_NONCE_LEN);
243
244         /* Lifetime */
245         lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
246         pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
247                           (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
248
249         wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
250                         "Sending SMK M5");
251
252         __wpa_send_eapol(wpa_auth, sm,
253                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
254                          WPA_KEY_INFO_SMK_MESSAGE,
255                          NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
256
257         os_free(buf);
258 }
259
260
261 void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
262                 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
263 {
264         struct wpa_eapol_ie_parse kde;
265         struct wpa_stsl_search search;
266         u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
267
268         if (wpa_parse_kde_ies((const u8 *) (key + 1),
269                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
270                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
271                 return;
272         }
273
274         if (kde.rsn_ie == NULL ||
275             kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
276             kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
277                 wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
278                            "Nonce KDE in SMK M3");
279                 return;
280         }
281
282         /* Peer = sm->addr; Initiator = kde.mac_addr;
283          * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
284
285         search.addr = kde.mac_addr;
286         search.sm = NULL;
287         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
288             0 || search.sm == NULL) {
289                 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
290                            " aborted - STA not associated anymore",
291                            MAC2STR(kde.mac_addr));
292                 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
293                                    STK_ERR_STA_NR);
294                 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
295                 return;
296         }
297
298         if (os_get_random(smk, PMK_LEN)) {
299                 wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
300                 return;
301         }
302
303         /* SMK = PRF-256(Random number, "SMK Derivation",
304          *               AA || Time || INonce || PNonce)
305          */
306         os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
307         pos = buf + ETH_ALEN;
308         wpa_get_ntp_timestamp(pos);
309         pos += 8;
310         os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
311         pos += WPA_NONCE_LEN;
312         os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
313 #ifdef CONFIG_IEEE80211W
314         sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
315                    smk, PMK_LEN);
316 #else /* CONFIG_IEEE80211W */
317         sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
318                  smk, PMK_LEN);
319 #endif /* CONFIG_IEEE80211W */
320
321         wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
322
323         wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
324         wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
325
326         /* Authenticator does not need SMK anymore and it is required to forget
327          * it. */
328         os_memset(smk, 0, sizeof(*smk));
329 }
330
331
332 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
333                    struct wpa_state_machine *sm, struct wpa_eapol_key *key)
334 {
335         struct wpa_eapol_ie_parse kde;
336         struct wpa_stsl_search search;
337         struct rsn_error_kde error;
338         u16 mui, error_type;
339
340         if (wpa_parse_kde_ies((const u8 *) (key + 1),
341                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
342                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
343                 return;
344         }
345
346         if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
347             kde.error == NULL || kde.error_len < sizeof(error)) {
348                 wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
349                            "SMK Error");
350                 return;
351         }
352
353         search.addr = kde.mac_addr;
354         search.sm = NULL;
355         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
356             0 || search.sm == NULL) {
357                 wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
358                            "associated for SMK Error message from " MACSTR,
359                            MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
360                 return;
361         }
362
363         os_memcpy(&error, kde.error, sizeof(error));
364         mui = be_to_host16(error.mui);
365         error_type = be_to_host16(error.error_type);
366         wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
367                          "STA reported SMK Error: Peer " MACSTR
368                          " MUI %d Error Type %d",
369                          MAC2STR(kde.mac_addr), mui, error_type);
370
371         wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
372 }
373
374
375 int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
376                     struct wpa_stsl_negotiation *neg)
377 {
378         struct wpa_stsl_negotiation *pos, *prev;
379
380         if (wpa_auth == NULL)
381                 return -1;
382         pos = wpa_auth->stsl_negotiations;
383         prev = NULL;
384         while (pos) {
385                 if (pos == neg) {
386                         if (prev)
387                                 prev->next = pos->next;
388                         else
389                                 wpa_auth->stsl_negotiations = pos->next;
390
391                         eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
392                         os_free(pos);
393                         return 0;
394                 }
395                 prev = pos;
396                 pos = pos->next;
397         }
398
399         return -1;
400 }
401
402 #endif /* CONFIG_PEERKEY */