Commit | Line | Data |
---|---|---|
91980990 GKH |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | ||
27 | Module Name: | |
28 | wpa.c | |
29 | ||
30 | Abstract: | |
31 | ||
32 | Revision History: | |
33 | Who When What | |
34 | -------- ---------- ---------------------------------------------- | |
35 | Jan Lee 03-07-22 Initial | |
36 | Paul Lin 03-11-28 Modify for supplicant | |
37 | */ | |
38 | #include "../rt_config.h" | |
39 | // WPA OUI | |
40 | UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; | |
41 | UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; | |
ed291e80 | 42 | UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; |
91980990 GKH |
43 | UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; |
44 | UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; | |
ed291e80 | 45 | UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; |
91980990 GKH |
46 | UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; |
47 | UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; | |
48 | // WPA2 OUI | |
49 | UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; | |
50 | UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; | |
51 | UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; | |
52 | UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; | |
53 | UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; | |
ed291e80 | 54 | UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; |
91980990 GKH |
55 | // MSA OUI |
56 | UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 | |
57 | UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 | |
58 | ||
59 | /* | |
60 | ======================================================================== | |
61 | ||
62 | Routine Description: | |
63 | The pseudo-random function(PRF) that hashes various inputs to | |
64 | derive a pseudo-random value. To add liveness to the pseudo-random | |
65 | value, a nonce should be one of the inputs. | |
66 | ||
67 | It is used to generate PTK, GTK or some specific random value. | |
68 | ||
69 | Arguments: | |
70 | UCHAR *key, - the key material for HMAC_SHA1 use | |
71 | INT key_len - the length of key | |
72 | UCHAR *prefix - a prefix label | |
73 | INT prefix_len - the length of the label | |
74 | UCHAR *data - a specific data with variable length | |
75 | INT data_len - the length of a specific data | |
76 | INT len - the output lenght | |
77 | ||
78 | Return Value: | |
79 | UCHAR *output - the calculated result | |
80 | ||
81 | Note: | |
82 | 802.11i-2004 Annex H.3 | |
83 | ||
84 | ======================================================================== | |
85 | */ | |
86 | VOID PRF( | |
87 | IN UCHAR *key, | |
88 | IN INT key_len, | |
89 | IN UCHAR *prefix, | |
90 | IN INT prefix_len, | |
91 | IN UCHAR *data, | |
92 | IN INT data_len, | |
93 | OUT UCHAR *output, | |
94 | IN INT len) | |
95 | { | |
96 | INT i; | |
97 | UCHAR *input; | |
98 | INT currentindex = 0; | |
99 | INT total_len; | |
100 | ||
101 | // Allocate memory for input | |
102 | os_alloc_mem(NULL, (PUCHAR *)&input, 1024); | |
103 | ||
104 | if (input == NULL) | |
105 | { | |
106 | DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); | |
107 | return; | |
108 | } | |
109 | ||
110 | // Generate concatenation input | |
111 | NdisMoveMemory(input, prefix, prefix_len); | |
112 | ||
113 | // Concatenate a single octet containing 0 | |
114 | input[prefix_len] = 0; | |
115 | ||
116 | // Concatenate specific data | |
117 | NdisMoveMemory(&input[prefix_len + 1], data, data_len); | |
118 | total_len = prefix_len + 1 + data_len; | |
119 | ||
120 | // Concatenate a single octet containing 0 | |
121 | // This octet shall be update later | |
122 | input[total_len] = 0; | |
123 | total_len++; | |
124 | ||
125 | // Iterate to calculate the result by hmac-sha-1 | |
126 | // Then concatenate to last result | |
127 | for (i = 0; i < (len + 19) / 20; i++) | |
128 | { | |
129 | HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); | |
130 | currentindex += 20; | |
131 | ||
132 | // update the last octet | |
133 | input[total_len - 1]++; | |
134 | } | |
135 | os_free_mem(NULL, input); | |
136 | } | |
137 | ||
138 | /* | |
139 | ======================================================================== | |
140 | ||
141 | Routine Description: | |
142 | It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. | |
143 | It shall be called by 4-way handshake processing. | |
144 | ||
145 | Arguments: | |
146 | pAd - pointer to our pAdapter context | |
147 | PMK - pointer to PMK | |
148 | ANonce - pointer to ANonce | |
149 | AA - pointer to Authenticator Address | |
150 | SNonce - pointer to SNonce | |
151 | SA - pointer to Supplicant Address | |
152 | len - indicate the length of PTK (octet) | |
153 | ||
154 | Return Value: | |
155 | Output pointer to the PTK | |
156 | ||
157 | Note: | |
158 | Refer to IEEE 802.11i-2004 8.5.1.2 | |
159 | ||
160 | ======================================================================== | |
161 | */ | |
162 | VOID WpaCountPTK( | |
163 | IN PRTMP_ADAPTER pAd, | |
164 | IN UCHAR *PMK, | |
165 | IN UCHAR *ANonce, | |
166 | IN UCHAR *AA, | |
167 | IN UCHAR *SNonce, | |
168 | IN UCHAR *SA, | |
169 | OUT UCHAR *output, | |
170 | IN UINT len) | |
171 | { | |
172 | UCHAR concatenation[76]; | |
173 | UINT CurrPos = 0; | |
174 | UCHAR temp[32]; | |
175 | UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', | |
176 | 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; | |
177 | ||
178 | // initiate the concatenation input | |
179 | NdisZeroMemory(temp, sizeof(temp)); | |
180 | NdisZeroMemory(concatenation, 76); | |
181 | ||
182 | // Get smaller address | |
183 | if (RTMPCompareMemory(SA, AA, 6) == 1) | |
184 | NdisMoveMemory(concatenation, AA, 6); | |
185 | else | |
186 | NdisMoveMemory(concatenation, SA, 6); | |
187 | CurrPos += 6; | |
188 | ||
189 | // Get larger address | |
190 | if (RTMPCompareMemory(SA, AA, 6) == 1) | |
191 | NdisMoveMemory(&concatenation[CurrPos], SA, 6); | |
192 | else | |
193 | NdisMoveMemory(&concatenation[CurrPos], AA, 6); | |
194 | ||
195 | // store the larger mac address for backward compatible of | |
196 | // ralink proprietary STA-key issue | |
197 | NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); | |
198 | CurrPos += 6; | |
199 | ||
200 | // Get smaller Nonce | |
201 | if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) | |
202 | NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue | |
203 | else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) | |
204 | NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); | |
205 | else | |
206 | NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); | |
207 | CurrPos += 32; | |
208 | ||
209 | // Get larger Nonce | |
210 | if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) | |
211 | NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue | |
212 | else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) | |
213 | NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); | |
214 | else | |
215 | NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); | |
216 | CurrPos += 32; | |
217 | ||
218 | hex_dump("concatenation=", concatenation, 76); | |
219 | ||
220 | // Use PRF to generate PTK | |
221 | PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); | |
222 | ||
223 | } | |
224 | ||
225 | /* | |
226 | ======================================================================== | |
227 | ||
228 | Routine Description: | |
229 | Generate random number by software. | |
230 | ||
231 | Arguments: | |
232 | pAd - pointer to our pAdapter context | |
233 | macAddr - pointer to local MAC address | |
234 | ||
235 | Return Value: | |
236 | ||
237 | Note: | |
238 | 802.1ii-2004 Annex H.5 | |
239 | ||
240 | ======================================================================== | |
241 | */ | |
242 | VOID GenRandom( | |
243 | IN PRTMP_ADAPTER pAd, | |
244 | IN UCHAR *macAddr, | |
245 | OUT UCHAR *random) | |
246 | { | |
247 | INT i, curr; | |
248 | UCHAR local[80], KeyCounter[32]; | |
249 | UCHAR result[80]; | |
250 | ULONG CurrentTime; | |
251 | UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; | |
252 | ||
253 | // Zero the related information | |
254 | NdisZeroMemory(result, 80); | |
255 | NdisZeroMemory(local, 80); | |
256 | NdisZeroMemory(KeyCounter, 32); | |
257 | ||
258 | for (i = 0; i < 32; i++) | |
259 | { | |
260 | // copy the local MAC address | |
261 | COPY_MAC_ADDR(local, macAddr); | |
262 | curr = MAC_ADDR_LEN; | |
263 | ||
264 | // concatenate the current time | |
265 | NdisGetSystemUpTime(&CurrentTime); | |
266 | NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); | |
267 | curr += sizeof(CurrentTime); | |
268 | ||
269 | // concatenate the last result | |
270 | NdisMoveMemory(&local[curr], result, 32); | |
271 | curr += 32; | |
272 | ||
273 | // concatenate a variable | |
274 | NdisMoveMemory(&local[curr], &i, 2); | |
275 | curr += 2; | |
276 | ||
277 | // calculate the result | |
278 | PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); | |
279 | } | |
280 | ||
281 | NdisMoveMemory(random, result, 32); | |
282 | } | |
283 | ||
284 | /* | |
285 | ======================================================================== | |
286 | ||
287 | Routine Description: | |
288 | Build cipher suite in RSN-IE. | |
289 | It only shall be called by RTMPMakeRSNIE. | |
290 | ||
291 | Arguments: | |
292 | pAd - pointer to our pAdapter context | |
293 | ElementID - indicate the WPA1 or WPA2 | |
294 | WepStatus - indicate the encryption type | |
295 | bMixCipher - a boolean to indicate the pairwise cipher and group | |
296 | cipher are the same or not | |
297 | ||
298 | Return Value: | |
299 | ||
300 | Note: | |
301 | ||
302 | ======================================================================== | |
303 | */ | |
304 | static VOID RTMPInsertRsnIeCipher( | |
305 | IN PRTMP_ADAPTER pAd, | |
306 | IN UCHAR ElementID, | |
307 | IN UINT WepStatus, | |
308 | IN BOOLEAN bMixCipher, | |
309 | IN UCHAR FlexibleCipher, | |
310 | OUT PUCHAR pRsnIe, | |
311 | OUT UCHAR *rsn_len) | |
312 | { | |
313 | UCHAR PairwiseCnt; | |
314 | ||
315 | *rsn_len = 0; | |
316 | ||
317 | // decide WPA2 or WPA1 | |
318 | if (ElementID == Wpa2Ie) | |
319 | { | |
320 | RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; | |
321 | ||
322 | // Assign the verson as 1 | |
323 | pRsnie_cipher->version = 1; | |
324 | ||
325 | switch (WepStatus) | |
326 | { | |
327 | // TKIP mode | |
328 | case Ndis802_11Encryption2Enabled: | |
329 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); | |
330 | pRsnie_cipher->ucount = 1; | |
331 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); | |
332 | *rsn_len = sizeof(RSNIE2); | |
333 | break; | |
334 | ||
335 | // AES mode | |
336 | case Ndis802_11Encryption3Enabled: | |
337 | if (bMixCipher) | |
338 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); | |
339 | else | |
340 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); | |
341 | pRsnie_cipher->ucount = 1; | |
342 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); | |
343 | *rsn_len = sizeof(RSNIE2); | |
344 | break; | |
345 | ||
346 | // TKIP-AES mix mode | |
347 | case Ndis802_11Encryption4Enabled: | |
348 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); | |
349 | ||
350 | PairwiseCnt = 1; | |
351 | // Insert WPA2 TKIP as the first pairwise cipher | |
352 | if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) | |
353 | { | |
354 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); | |
355 | // Insert WPA2 AES as the secondary pairwise cipher | |
356 | if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) | |
357 | { | |
358 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); | |
359 | PairwiseCnt = 2; | |
360 | } | |
361 | } | |
362 | else | |
363 | { | |
364 | // Insert WPA2 AES as the first pairwise cipher | |
365 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); | |
366 | } | |
367 | ||
368 | pRsnie_cipher->ucount = PairwiseCnt; | |
369 | *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); | |
370 | break; | |
371 | } | |
372 | ||
ed291e80 AM |
373 | if ((pAd->OpMode == OPMODE_STA) && |
374 | (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && | |
375 | (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) | |
376 | { | |
377 | UINT GroupCipher = pAd->StaCfg.GroupCipher; | |
378 | switch(GroupCipher) | |
379 | { | |
380 | case Ndis802_11GroupWEP40Enabled: | |
381 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP40, 4); | |
382 | break; | |
383 | case Ndis802_11GroupWEP104Enabled: | |
384 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP104, 4); | |
385 | break; | |
386 | } | |
387 | } | |
3cf830a1 | 388 | |
91980990 GKH |
389 | // swap for big-endian platform |
390 | pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); | |
391 | pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); | |
392 | } | |
393 | else | |
394 | { | |
395 | RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; | |
396 | ||
397 | // Assign OUI and version | |
398 | NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); | |
399 | pRsnie_cipher->version = 1; | |
400 | ||
401 | switch (WepStatus) | |
402 | { | |
403 | // TKIP mode | |
404 | case Ndis802_11Encryption2Enabled: | |
405 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); | |
406 | pRsnie_cipher->ucount = 1; | |
407 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); | |
408 | *rsn_len = sizeof(RSNIE); | |
409 | break; | |
410 | ||
411 | // AES mode | |
412 | case Ndis802_11Encryption3Enabled: | |
413 | if (bMixCipher) | |
414 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); | |
415 | else | |
416 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); | |
417 | pRsnie_cipher->ucount = 1; | |
418 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); | |
419 | *rsn_len = sizeof(RSNIE); | |
420 | break; | |
421 | ||
422 | // TKIP-AES mix mode | |
423 | case Ndis802_11Encryption4Enabled: | |
424 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); | |
425 | ||
426 | PairwiseCnt = 1; | |
427 | // Insert WPA TKIP as the first pairwise cipher | |
428 | if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) | |
429 | { | |
430 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); | |
431 | // Insert WPA AES as the secondary pairwise cipher | |
432 | if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) | |
433 | { | |
434 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); | |
435 | PairwiseCnt = 2; | |
436 | } | |
437 | } | |
438 | else | |
439 | { | |
440 | // Insert WPA AES as the first pairwise cipher | |
441 | NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); | |
442 | } | |
443 | ||
444 | pRsnie_cipher->ucount = PairwiseCnt; | |
445 | *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); | |
446 | break; | |
447 | } | |
448 | ||
ed291e80 AM |
449 | if ((pAd->OpMode == OPMODE_STA) && |
450 | (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && | |
451 | (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) | |
452 | { | |
453 | UINT GroupCipher = pAd->StaCfg.GroupCipher; | |
454 | switch(GroupCipher) | |
455 | { | |
456 | case Ndis802_11GroupWEP40Enabled: | |
457 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP40, 4); | |
458 | break; | |
459 | case Ndis802_11GroupWEP104Enabled: | |
460 | NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP104, 4); | |
461 | break; | |
462 | } | |
463 | } | |
3cf830a1 | 464 | |
91980990 GKH |
465 | // swap for big-endian platform |
466 | pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); | |
467 | pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); | |
468 | } | |
91980990 GKH |
469 | } |
470 | ||
471 | /* | |
472 | ======================================================================== | |
473 | ||
474 | Routine Description: | |
475 | Build AKM suite in RSN-IE. | |
476 | It only shall be called by RTMPMakeRSNIE. | |
477 | ||
478 | Arguments: | |
479 | pAd - pointer to our pAdapter context | |
480 | ElementID - indicate the WPA1 or WPA2 | |
481 | AuthMode - indicate the authentication mode | |
482 | apidx - indicate the interface index | |
483 | ||
484 | Return Value: | |
485 | ||
486 | Note: | |
487 | ||
488 | ======================================================================== | |
489 | */ | |
490 | static VOID RTMPInsertRsnIeAKM( | |
491 | IN PRTMP_ADAPTER pAd, | |
492 | IN UCHAR ElementID, | |
493 | IN UINT AuthMode, | |
494 | IN UCHAR apidx, | |
495 | OUT PUCHAR pRsnIe, | |
496 | OUT UCHAR *rsn_len) | |
497 | { | |
498 | RSNIE_AUTH *pRsnie_auth; | |
499 | ||
500 | pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); | |
501 | ||
502 | // decide WPA2 or WPA1 | |
503 | if (ElementID == Wpa2Ie) | |
504 | { | |
505 | switch (AuthMode) | |
506 | { | |
507 | case Ndis802_11AuthModeWPA2: | |
508 | case Ndis802_11AuthModeWPA1WPA2: | |
509 | pRsnie_auth->acount = 1; | |
510 | NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); | |
511 | break; | |
512 | ||
513 | case Ndis802_11AuthModeWPA2PSK: | |
514 | case Ndis802_11AuthModeWPA1PSKWPA2PSK: | |
515 | pRsnie_auth->acount = 1; | |
516 | NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); | |
517 | break; | |
518 | } | |
519 | } | |
520 | else | |
521 | { | |
522 | switch (AuthMode) | |
523 | { | |
524 | case Ndis802_11AuthModeWPA: | |
525 | case Ndis802_11AuthModeWPA1WPA2: | |
526 | pRsnie_auth->acount = 1; | |
527 | NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); | |
528 | break; | |
529 | ||
530 | case Ndis802_11AuthModeWPAPSK: | |
531 | case Ndis802_11AuthModeWPA1PSKWPA2PSK: | |
532 | pRsnie_auth->acount = 1; | |
533 | NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); | |
534 | break; | |
535 | ||
536 | case Ndis802_11AuthModeWPANone: | |
537 | pRsnie_auth->acount = 1; | |
538 | NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); | |
539 | break; | |
540 | } | |
541 | } | |
542 | ||
543 | pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); | |
544 | ||
545 | (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length | |
546 | ||
547 | } | |
548 | ||
549 | /* | |
550 | ======================================================================== | |
551 | ||
552 | Routine Description: | |
553 | Build capability in RSN-IE. | |
554 | It only shall be called by RTMPMakeRSNIE. | |
555 | ||
556 | Arguments: | |
557 | pAd - pointer to our pAdapter context | |
558 | ElementID - indicate the WPA1 or WPA2 | |
559 | apidx - indicate the interface index | |
560 | ||
561 | Return Value: | |
562 | ||
563 | Note: | |
564 | ||
565 | ======================================================================== | |
566 | */ | |
567 | static VOID RTMPInsertRsnIeCap( | |
568 | IN PRTMP_ADAPTER pAd, | |
569 | IN UCHAR ElementID, | |
570 | IN UCHAR apidx, | |
571 | OUT PUCHAR pRsnIe, | |
572 | OUT UCHAR *rsn_len) | |
573 | { | |
574 | RSN_CAPABILITIES *pRSN_Cap; | |
575 | ||
576 | // it could be ignored in WPA1 mode | |
577 | if (ElementID == WpaIe) | |
578 | return; | |
579 | ||
580 | pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); | |
581 | ||
582 | ||
583 | pRSN_Cap->word = cpu2le16(pRSN_Cap->word); | |
584 | ||
585 | (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length | |
586 | ||
587 | } | |
588 | ||
589 | ||
590 | /* | |
591 | ======================================================================== | |
592 | ||
593 | Routine Description: | |
594 | Build RSN IE context. It is not included element-ID and length. | |
595 | ||
596 | Arguments: | |
597 | pAd - pointer to our pAdapter context | |
598 | AuthMode - indicate the authentication mode | |
599 | WepStatus - indicate the encryption type | |
600 | apidx - indicate the interface index | |
601 | ||
602 | Return Value: | |
603 | ||
604 | Note: | |
605 | ||
606 | ======================================================================== | |
607 | */ | |
608 | VOID RTMPMakeRSNIE( | |
609 | IN PRTMP_ADAPTER pAd, | |
610 | IN UINT AuthMode, | |
611 | IN UINT WepStatus, | |
612 | IN UCHAR apidx) | |
613 | { | |
614 | PUCHAR pRsnIe = NULL; // primary RSNIE | |
615 | UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE | |
616 | UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE | |
617 | UCHAR PrimaryRsnie; | |
618 | BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different | |
619 | UCHAR p_offset; | |
8d72f98a | 620 | WPA_MIX_PAIR_CIPHER FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode |
91980990 GKH |
621 | |
622 | rsnielen_cur_p = NULL; | |
623 | rsnielen_ex_cur_p = NULL; | |
624 | ||
625 | { | |
91980990 | 626 | { |
91980990 GKH |
627 | if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) |
628 | { | |
629 | if (AuthMode < Ndis802_11AuthModeWPA) | |
630 | return; | |
631 | } | |
632 | else | |
91980990 GKH |
633 | { |
634 | // Support WPAPSK or WPA2PSK in STA-Infra mode | |
635 | // Support WPANone in STA-Adhoc mode | |
636 | if ((AuthMode != Ndis802_11AuthModeWPAPSK) && | |
637 | (AuthMode != Ndis802_11AuthModeWPA2PSK) && | |
638 | (AuthMode != Ndis802_11AuthModeWPANone) | |
639 | ) | |
640 | return; | |
641 | } | |
642 | ||
643 | DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); | |
644 | ||
645 | // Zero RSNIE context | |
646 | pAd->StaCfg.RSNIE_Len = 0; | |
647 | NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); | |
648 | ||
649 | // Pointer to RSNIE | |
650 | rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; | |
651 | pRsnIe = pAd->StaCfg.RSN_IE; | |
652 | ||
653 | bMixCipher = pAd->StaCfg.bMixCipher; | |
654 | } | |
91980990 GKH |
655 | } |
656 | ||
657 | // indicate primary RSNIE as WPA or WPA2 | |
658 | if ((AuthMode == Ndis802_11AuthModeWPA) || | |
659 | (AuthMode == Ndis802_11AuthModeWPAPSK) || | |
660 | (AuthMode == Ndis802_11AuthModeWPANone) || | |
661 | (AuthMode == Ndis802_11AuthModeWPA1WPA2) || | |
662 | (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) | |
663 | PrimaryRsnie = WpaIe; | |
664 | else | |
665 | PrimaryRsnie = Wpa2Ie; | |
666 | ||
667 | { | |
668 | // Build the primary RSNIE | |
669 | // 1. insert cipher suite | |
670 | RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); | |
671 | ||
672 | // 2. insert AKM | |
673 | RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); | |
674 | ||
675 | // 3. insert capability | |
676 | RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); | |
677 | } | |
678 | ||
679 | // 4. update the RSNIE length | |
680 | *rsnielen_cur_p = p_offset; | |
681 | ||
682 | hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); | |
683 | ||
684 | ||
685 | } | |
686 | ||
687 | /* | |
688 | ========================================================================== | |
689 | Description: | |
690 | Check whether the received frame is EAP frame. | |
691 | ||
692 | Arguments: | |
693 | pAd - pointer to our pAdapter context | |
694 | pEntry - pointer to active entry | |
695 | pData - the received frame | |
696 | DataByteCount - the received frame's length | |
697 | FromWhichBSSID - indicate the interface index | |
698 | ||
699 | Return: | |
700 | TRUE - This frame is EAP frame | |
701 | FALSE - otherwise | |
702 | ========================================================================== | |
703 | */ | |
704 | BOOLEAN RTMPCheckWPAframe( | |
705 | IN PRTMP_ADAPTER pAd, | |
706 | IN PMAC_TABLE_ENTRY pEntry, | |
707 | IN PUCHAR pData, | |
708 | IN ULONG DataByteCount, | |
709 | IN UCHAR FromWhichBSSID) | |
710 | { | |
711 | ULONG Body_len; | |
712 | BOOLEAN Cancelled; | |
713 | ||
714 | ||
715 | if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) | |
716 | return FALSE; | |
717 | ||
718 | ||
719 | // Skip LLC header | |
720 | if (NdisEqualMemory(SNAP_802_1H, pData, 6) || | |
721 | // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL | |
722 | NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) | |
723 | { | |
724 | pData += 6; | |
725 | } | |
726 | // Skip 2-bytes EAPoL type | |
727 | if (NdisEqualMemory(EAPOL, pData, 2)) | |
728 | { | |
729 | pData += 2; | |
730 | } | |
731 | else | |
732 | return FALSE; | |
733 | ||
734 | switch (*(pData+1)) | |
735 | { | |
736 | case EAPPacket: | |
737 | Body_len = (*(pData+2)<<8) | (*(pData+3)); | |
738 | DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); | |
739 | break; | |
740 | case EAPOLStart: | |
741 | DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); | |
742 | if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) | |
743 | { | |
744 | DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); | |
745 | RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); | |
746 | pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; | |
747 | } | |
748 | break; | |
749 | case EAPOLLogoff: | |
750 | DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); | |
751 | break; | |
752 | case EAPOLKey: | |
753 | Body_len = (*(pData+2)<<8) | (*(pData+3)); | |
754 | DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); | |
755 | break; | |
756 | case EAPOLASFAlert: | |
757 | DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); | |
758 | break; | |
759 | default: | |
760 | return FALSE; | |
761 | ||
762 | } | |
763 | return TRUE; | |
764 | } | |
765 | ||
91980990 GKH |
766 | /* |
767 | ======================================================================== | |
768 | ||
769 | Routine Description: | |
770 | Misc function to decrypt AES body | |
771 | ||
772 | Arguments: | |
773 | ||
774 | Return Value: | |
775 | ||
776 | Note: | |
777 | This function references to RFC 3394 for aes key unwrap algorithm. | |
778 | ||
779 | ======================================================================== | |
780 | */ | |
781 | VOID AES_GTK_KEY_UNWRAP( | |
782 | IN UCHAR *key, | |
783 | OUT UCHAR *plaintext, | |
784 | IN UCHAR c_len, | |
785 | IN UCHAR *ciphertext) | |
786 | ||
787 | { | |
788 | UCHAR A[8], BIN[16], BOUT[16]; | |
789 | UCHAR xor; | |
790 | INT i, j; | |
791 | aes_context aesctx; | |
792 | UCHAR *R; | |
793 | INT num_blocks = c_len/8; // unit:64bits | |
794 | ||
795 | ||
796 | os_alloc_mem(NULL, (PUCHAR *)&R, 512); | |
797 | ||
798 | if (R == NULL) | |
799 | { | |
800 | DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); | |
801 | return; | |
802 | } /* End of if */ | |
803 | ||
804 | // Initialize | |
805 | NdisMoveMemory(A, ciphertext, 8); | |
806 | //Input plaintext | |
807 | for(i = 0; i < (c_len-8); i++) | |
808 | { | |
809 | R[ i] = ciphertext[i + 8]; | |
810 | } | |
811 | ||
812 | rtmp_aes_set_key(&aesctx, key, 128); | |
813 | ||
814 | for(j = 5; j >= 0; j--) | |
815 | { | |
816 | for(i = (num_blocks-1); i > 0; i--) | |
817 | { | |
818 | xor = (num_blocks -1 )* j + i; | |
819 | NdisMoveMemory(BIN, A, 8); | |
820 | BIN[7] = A[7] ^ xor; | |
821 | NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); | |
822 | rtmp_aes_decrypt(&aesctx, BIN, BOUT); | |
823 | NdisMoveMemory(A, &BOUT[0], 8); | |
824 | NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); | |
825 | } | |
826 | } | |
827 | ||
828 | // OUTPUT | |
829 | for(i = 0; i < c_len; i++) | |
830 | { | |
831 | plaintext[i] = R[i]; | |
832 | } | |
833 | ||
834 | ||
835 | os_free_mem(NULL, R); | |
836 | } |