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