wlantest: Add support for protecting injected broadcast frames
[mech_eap.git] / wlantest / inject.c
1 /*
2  * wlantest frame injection
3  * Copyright (c) 2010, 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 "common/defs.h"
19 #include "common/ieee802_11_defs.h"
20 #include "crypto/aes_wrap.h"
21 #include "wlantest.h"
22
23
24 static int inject_frame(int s, const void *data, size_t len)
25 {
26 #define IEEE80211_RADIOTAP_F_FRAG       0x08
27         unsigned char rtap_hdr[] = {
28                 0x00, 0x00, /* radiotap version */
29                 0x0e, 0x00, /* radiotap length */
30                 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
31                 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
32                 0x00,       /* padding */
33                 0x00, 0x00, /* RX and TX flags to indicate that */
34                 0x00, 0x00, /* this is the injected frame directly */
35         };
36         struct iovec iov[2] = {
37                 {
38                         .iov_base = &rtap_hdr,
39                         .iov_len = sizeof(rtap_hdr),
40                 },
41                 {
42                         .iov_base = (void *) data,
43                         .iov_len = len,
44                 }
45         };
46         struct msghdr msg = {
47                 .msg_name = NULL,
48                 .msg_namelen = 0,
49                 .msg_iov = iov,
50                 .msg_iovlen = 2,
51                 .msg_control = NULL,
52                 .msg_controllen = 0,
53                 .msg_flags = 0,
54         };
55         int ret;
56
57         ret = sendmsg(s, &msg, 0);
58         if (ret < 0)
59                 perror("sendmsg");
60         return ret;
61 }
62
63
64 static int is_robust_mgmt(u8 *frame, size_t len)
65 {
66         struct ieee80211_mgmt *mgmt;
67         u16 fc, stype;
68         if (len < 24)
69                 return 0;
70         mgmt = (struct ieee80211_mgmt *) frame;
71         fc = le_to_host16(mgmt->frame_control);
72         if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
73                 return 0;
74         stype = WLAN_FC_GET_STYPE(fc);
75         if (stype == WLAN_FC_STYPE_DEAUTH || stype == WLAN_FC_STYPE_DISASSOC)
76                 return 1;
77         if (stype == WLAN_FC_STYPE_ACTION) {
78                 if (len < 25)
79                         return 0;
80                 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
81                         return 1;
82         }
83         return 0;
84 }
85
86
87 static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss,
88                                u8 *frame, size_t len, int incorrect_key)
89 {
90         u8 *prot, *pos, *buf;
91         u8 mic[16];
92         u8 dummy[16];
93         int ret;
94         u16 fc;
95         struct ieee80211_hdr *hdr;
96         size_t plen;
97
98         if (!bss->igtk_set[bss->igtk_idx])
99                 return -1;
100
101         plen = len + 18;
102         prot = os_malloc(plen);
103         if (prot == NULL)
104                 return -1;
105         os_memcpy(prot, frame, len);
106         pos = prot + len;
107         *pos++ = WLAN_EID_MMIE;
108         *pos++ = 16;
109         WPA_PUT_LE16(pos, bss->igtk_idx);
110         pos += 2;
111         inc_byte_array(bss->ipn[bss->igtk_idx], 6);
112         os_memcpy(pos, bss->ipn[bss->igtk_idx], 6);
113         pos += 6;
114         os_memset(pos, 0, 8); /* MIC */
115
116         buf = os_malloc(plen + 20 - 24);
117         if (buf == NULL) {
118                 os_free(prot);
119                 return -1;
120         }
121
122         /* BIP AAD: FC(masked) A1 A2 A3 */
123         hdr = (struct ieee80211_hdr *) frame;
124         fc = le_to_host16(hdr->frame_control);
125         fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
126         WPA_PUT_LE16(buf, fc);
127         os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
128         os_memcpy(buf + 20, prot + 24, plen - 24);
129         wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
130         /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
131         os_memset(dummy, 0x11, sizeof(dummy));
132         if (omac1_aes_128(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
133                           buf, plen + 20 - 24, mic) < 0) {
134                 os_free(prot);
135                 os_free(buf);
136                 return -1;
137         }
138         os_free(buf);
139
140         os_memcpy(pos, mic, 8);
141         wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
142
143         ret = inject_frame(wt->monitor_sock, prot, plen);
144         os_free(prot);
145
146         return (ret < 0) ? -1 : 0;
147 }
148
149
150 static int wlantest_inject_prot_bc(struct wlantest *wt,
151                                    struct wlantest_bss *bss,
152                                    u8 *frame, size_t len, int incorrect_key)
153 {
154         u8 *crypt;
155         size_t crypt_len;
156         int ret;
157         u8 dummy[64];
158         u8 *pn;
159         struct ieee80211_hdr *hdr;
160         u16 fc;
161         int hdrlen;
162
163         hdr = (struct ieee80211_hdr *) frame;
164         hdrlen = 24;
165         fc = le_to_host16(hdr->frame_control);
166
167         if (!bss->gtk_len[bss->gtk_idx])
168                 return -1;
169
170         if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
171             (WLAN_FC_TODS | WLAN_FC_FROMDS))
172                 hdrlen += ETH_ALEN;
173         pn = bss->rsc[bss->gtk_idx];
174         inc_byte_array(pn, 6);
175
176         os_memset(dummy, 0x11, sizeof(dummy));
177         if (bss->group_cipher == WPA_CIPHER_TKIP)
178                 crypt = tkip_encrypt(incorrect_key ? dummy :
179                                      bss->gtk[bss->gtk_idx],
180                                      frame, len, hdrlen, NULL, pn,
181                                      bss->gtk_idx, &crypt_len);
182         else
183                 crypt = ccmp_encrypt(incorrect_key ? dummy :
184                                      bss->gtk[bss->gtk_idx],
185                                      frame, len, hdrlen, NULL, pn,
186                                      bss->gtk_idx, &crypt_len);
187
188         if (crypt == NULL)
189                 return -1;
190
191         ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
192         os_free(crypt);
193
194         return (ret < 0) ? -1 : 0;
195 }
196
197
198 static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
199                                 struct wlantest_sta *sta, u8 *frame,
200                                 size_t len, int incorrect_key)
201 {
202         u8 *crypt;
203         size_t crypt_len;
204         int ret;
205         u8 dummy[64];
206         u8 *pn;
207         struct ieee80211_hdr *hdr;
208         u16 fc;
209         int tid = 0;
210         u8 *qos = NULL;
211         int hdrlen;
212
213         hdr = (struct ieee80211_hdr *) frame;
214         hdrlen = 24;
215         fc = le_to_host16(hdr->frame_control);
216
217         if (sta == NULL) {
218                 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
219                         return wlantest_inject_bip(wt, bss, frame, len,
220                                                    incorrect_key);
221                 return wlantest_inject_prot_bc(wt, bss, frame, len,
222                                                incorrect_key);
223         }
224
225         if (!sta->ptk_set)
226                 return -1;
227
228         if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
229                 tid = 16;
230         else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
231                 if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
232                     (WLAN_FC_TODS | WLAN_FC_FROMDS))
233                         hdrlen += ETH_ALEN;
234                 if (WLAN_FC_GET_STYPE(fc) & 0x08) {
235                         qos = frame + hdrlen;
236                         hdrlen += 2;
237                         tid = qos[0] & 0x0f;
238                 }
239         }
240         if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
241                 pn = sta->rsc_fromds[tid];
242         else
243                 pn = sta->rsc_tods[tid];
244         inc_byte_array(pn, 6);
245
246         os_memset(dummy, 0x11, sizeof(dummy));
247         if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
248                 crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
249                                      frame, len, hdrlen, qos, pn, 0,
250                                      &crypt_len);
251         else
252                 crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
253                                      frame, len, hdrlen, qos, pn, 0,
254                                      &crypt_len);
255
256         if (crypt == NULL)
257                 return -1;
258
259         ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
260         os_free(crypt);
261
262         return (ret < 0) ? -1 : 0;
263 }
264
265
266 int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
267                     struct wlantest_sta *sta, u8 *frame, size_t len,
268                     enum wlantest_inject_protection prot)
269 {
270         int ret;
271         struct ieee80211_hdr *hdr;
272         u16 fc;
273         int protectable, protect = 0;
274
275         wpa_hexdump(MSG_DEBUG, "Inject frame", frame, len);
276         if (wt->monitor_sock < 0) {
277                 wpa_printf(MSG_INFO, "Cannot inject frames when monitor "
278                            "interface is not in use");
279                 return -1;
280         }
281
282         hdr = (struct ieee80211_hdr *) frame;
283         fc = le_to_host16(hdr->frame_control);
284         protectable = WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ||
285                 is_robust_mgmt(frame, len);
286
287         if (prot == WLANTEST_INJECT_PROTECTED ||
288             prot == WLANTEST_INJECT_INCORRECT_KEY) {
289                 if (!sta &&
290                     ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
291                       !bss->igtk_set[bss->igtk_idx]) ||
292                      (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
293                       !bss->gtk_len[bss->gtk_idx]))) {
294                         wpa_printf(MSG_INFO, "No GTK/IGTK known for "
295                                    MACSTR " to protect the injected "
296                                    "frame", MAC2STR(bss->bssid));
297                         return -1;
298                 }
299                 if (sta && !sta->ptk_set) {
300                         wpa_printf(MSG_INFO, "No PTK known for the STA " MACSTR
301                                    " to encrypt the injected frame",
302                                    MAC2STR(sta->addr));
303                         return -1;
304                 }
305                 protect = 1;
306         } else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED) {
307                 if (sta && sta->ptk_set)
308                         protect = 1;
309                 else if (!sta) {
310                         if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
311                             bss->gtk_len[bss->gtk_idx])
312                                 protect = 1;
313                         if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
314                             bss->igtk_set[bss->igtk_idx])
315                                 protect = 1;
316                 }
317         }
318
319         if ((prot == WLANTEST_INJECT_PROTECTED ||
320              prot == WLANTEST_INJECT_INCORRECT_KEY) && !protect) {
321                 wpa_printf(MSG_INFO, "Cannot protect injected frame");
322                 return -1;
323         }
324
325         if (protect)
326                 return wlantest_inject_prot(
327                         wt, bss, sta, frame, len,
328                         prot == WLANTEST_INJECT_INCORRECT_KEY);
329
330         ret = inject_frame(wt->monitor_sock, frame, len);
331         return (ret < 0) ? -1 : 0;
332 }