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