• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3  * All rights reserved.
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 as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  *
20  * File: wpa2.c
21  *
22  * Purpose: Handles the Basic Service Set & Node Database functions
23  *
24  * Functions:
25  *
26  * Revision History:
27  *
28  * Author: Yiching Chen
29  *
30  * Date: Oct. 4, 2004
31  *
32  */
33 
34 #include "wpa2.h"
35 #include "device.h"
36 #include "wmgr.h"
37 
38 /*---------------------  Static Classes  ----------------------------*/
39 
40 /*---------------------  Static Variables  --------------------------*/
41 
42 static const unsigned char abyOUIGK[4]      = { 0x00, 0x0F, 0xAC, 0x00 };
43 static const unsigned char abyOUIWEP40[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
44 static const unsigned char abyOUIWEP104[4]  = { 0x00, 0x0F, 0xAC, 0x05 };
45 static const unsigned char abyOUITKIP[4]    = { 0x00, 0x0F, 0xAC, 0x02 };
46 static const unsigned char abyOUICCMP[4]    = { 0x00, 0x0F, 0xAC, 0x04 };
47 
48 static const unsigned char abyOUI8021X[4]   = { 0x00, 0x0F, 0xAC, 0x01 };
49 static const unsigned char abyOUIPSK[4]     = { 0x00, 0x0F, 0xAC, 0x02 };
50 
51 /*---------------------  Static Functions  --------------------------*/
52 
53 /*---------------------  Export Variables  --------------------------*/
54 
55 /*---------------------  Export Functions  --------------------------*/
56 
57 /*+
58  *
59  * Description:
60  *    Clear RSN information in BSSList.
61  *
62  * Parameters:
63  *  In:
64  *      pBSSNode - BSS list.
65  *  Out:
66  *      none
67  *
68  * Return Value: none.
69  *
70  -*/
71 void
WPA2_ClearRSN(PKnownBSS pBSSNode)72 WPA2_ClearRSN(
73 	PKnownBSS        pBSSNode
74 )
75 {
76 	int ii;
77 
78 	pBSSNode->bWPA2Valid = false;
79 
80 	pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
81 	for (ii = 0; ii < 4; ii++)
82 		pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP;
83 	pBSSNode->wCSSPKCount = 1;
84 	for (ii = 0; ii < 4; ii++)
85 		pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
86 	pBSSNode->wAKMSSAuthCount = 1;
87 	pBSSNode->sRSNCapObj.bRSNCapExist = false;
88 	pBSSNode->sRSNCapObj.wRSNCap = 0;
89 }
90 
91 /*+
92  *
93  * Description:
94  *    Parse RSN IE.
95  *
96  * Parameters:
97  *  In:
98  *      pBSSNode - BSS list.
99  *      pRSN - Pointer to the RSN IE.
100  *  Out:
101  *      none
102  *
103  * Return Value: none.
104  *
105  -*/
106 void
WPA2vParseRSN(PKnownBSS pBSSNode,PWLAN_IE_RSN pRSN)107 WPA2vParseRSN(
108 	PKnownBSS        pBSSNode,
109 	PWLAN_IE_RSN     pRSN
110 )
111 {
112 	int                 i, j;
113 	unsigned short m = 0, n = 0;
114 	unsigned char *pbyOUI;
115 	bool bUseGK = false;
116 
117 	pr_debug("WPA2_ParseRSN: [%d]\n", pRSN->len);
118 
119 	WPA2_ClearRSN(pBSSNode);
120 
121 	if (pRSN->len == 2) { // ver(2)
122 		if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1))
123 			pBSSNode->bWPA2Valid = true;
124 
125 		return;
126 	}
127 
128 	if (pRSN->len < 6) { // ver(2) + GK(4)
129 		// invalid CSS, P802.11i/D10.0, p31
130 		return;
131 	}
132 
133 	// information element header makes sense
134 	if ((pRSN->byElementID == WLAN_EID_RSN) &&
135 	    (pRSN->wVersion == 1)) {
136 		pr_debug("Legal 802.11i RSN\n");
137 
138 		pbyOUI = &(pRSN->abyRSN[0]);
139 		if (!memcmp(pbyOUI, abyOUIWEP40, 4))
140 			pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40;
141 		else if (!memcmp(pbyOUI, abyOUITKIP, 4))
142 			pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP;
143 		else if (!memcmp(pbyOUI, abyOUICCMP, 4))
144 			pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
145 		else if (!memcmp(pbyOUI, abyOUIWEP104, 4))
146 			pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104;
147 		else if (!memcmp(pbyOUI, abyOUIGK, 4)) {
148 			// invalid CSS, P802.11i/D10.0, p32
149 			return;
150 		} else
151 			// any vendor checks here
152 			pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN;
153 
154 		pr_debug("802.11i CSS: %X\n", pBSSNode->byCSSGK);
155 
156 		if (pRSN->len == 6) {
157 			pBSSNode->bWPA2Valid = true;
158 			return;
159 		}
160 
161 		if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
162 			pBSSNode->wCSSPKCount = *((unsigned short *)&(pRSN->abyRSN[4]));
163 			j = 0;
164 			pbyOUI = &(pRSN->abyRSN[6]);
165 
166 			for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
167 				if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
168 					if (!memcmp(pbyOUI, abyOUIGK, 4)) {
169 						pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
170 						bUseGK = true;
171 					} else if (!memcmp(pbyOUI, abyOUIWEP40, 4)) {
172 						// Invalid CSS, continue to parsing
173 					} else if (!memcmp(pbyOUI, abyOUITKIP, 4)) {
174 						if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
175 							pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
176 						else
177 							; // Invalid CSS, continue to parsing
178 					} else if (!memcmp(pbyOUI, abyOUICCMP, 4)) {
179 						pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
180 					} else if (!memcmp(pbyOUI, abyOUIWEP104, 4)) {
181 						// Invalid CSS, continue to parsing
182 					} else {
183 						// any vendor checks here
184 						pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
185 					}
186 					pbyOUI += 4;
187 					pr_debug("abyCSSPK[%d]: %X\n",
188 						 j-1, pBSSNode->abyCSSPK[j-1]);
189 				} else
190 					break;
191 			} //for
192 
193 			if (bUseGK) {
194 				if (j != 1) {
195 					// invalid CSS, This should be only PK CSS.
196 					return;
197 				}
198 				if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
199 					// invalid CSS, If CCMP is enable , PK can't be CSSGK.
200 					return;
201 				}
202 			}
203 			if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) {
204 				// invalid CSS, No valid PK.
205 				return;
206 			}
207 			pBSSNode->wCSSPKCount = (unsigned short)j;
208 			pr_debug("wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
209 		}
210 
211 		m = *((unsigned short *)&(pRSN->abyRSN[4]));
212 
213 		if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
214 			pBSSNode->wAKMSSAuthCount = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
215 			j = 0;
216 			pbyOUI = &(pRSN->abyRSN[8+4*m]);
217 			for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
218 				if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
219 					if (!memcmp(pbyOUI, abyOUI8021X, 4))
220 						pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
221 					else if (!memcmp(pbyOUI, abyOUIPSK, 4))
222 						pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK;
223 					else
224 						// any vendor checks here
225 						pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN;
226 					pr_debug("abyAKMSSAuthType[%d]: %X\n",
227 						 j-1,
228 						 pBSSNode->abyAKMSSAuthType[j-1]);
229 				} else
230 					break;
231 			}
232 			pBSSNode->wAKMSSAuthCount = (unsigned short)j;
233 			pr_debug("wAKMSSAuthCount: %d\n",
234 				 pBSSNode->wAKMSSAuthCount);
235 
236 			n = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
237 			if (pRSN->len >= 12 + 4 * m + 4 * n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
238 				pBSSNode->sRSNCapObj.bRSNCapExist = true;
239 				pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *)&(pRSN->abyRSN[8+4*m+4*n]));
240 			}
241 		}
242 		//ignore PMKID lists bcs only (Re)Assocrequest has this field
243 		pBSSNode->bWPA2Valid = true;
244 	}
245 }
246 
247 /*+
248  *
249  * Description:
250  *    Set WPA IEs
251  *
252  * Parameters:
253  *  In:
254  *      pMgmtHandle - Pointer to management object
255  *  Out:
256  *      pRSNIEs     - Pointer to the RSN IE to set.
257  *
258  * Return Value: length of IEs.
259  *
260  -*/
261 unsigned int
WPA2uSetIEs(void * pMgmtHandle,PWLAN_IE_RSN pRSNIEs)262 WPA2uSetIEs(
263 	void *pMgmtHandle,
264 	PWLAN_IE_RSN pRSNIEs
265 )
266 {
267 	PSMgmtObject    pMgmt = (PSMgmtObject) pMgmtHandle;
268 	unsigned char *pbyBuffer = NULL;
269 	unsigned int ii = 0;
270 	unsigned short *pwPMKID = NULL;
271 
272 	if (pRSNIEs == NULL)
273 		return 0;
274 
275 	if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
276 	     (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
277 	    (pMgmt->pCurrBSS != NULL)) {
278 		/* WPA2 IE */
279 		pbyBuffer = (unsigned char *)pRSNIEs;
280 		pRSNIEs->byElementID = WLAN_EID_RSN;
281 		pRSNIEs->len = 6; //Version(2)+GK(4)
282 		pRSNIEs->wVersion = 1;
283 		//Group Key Cipher Suite
284 		pRSNIEs->abyRSN[0] = 0x00;
285 		pRSNIEs->abyRSN[1] = 0x0F;
286 		pRSNIEs->abyRSN[2] = 0xAC;
287 		if (pMgmt->byCSSGK == KEY_CTL_WEP)
288 			pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
289 		else if (pMgmt->byCSSGK == KEY_CTL_TKIP)
290 			pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
291 		else if (pMgmt->byCSSGK == KEY_CTL_CCMP)
292 			pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
293 		else
294 			pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
295 
296 		// Pairwise Key Cipher Suite
297 		pRSNIEs->abyRSN[4] = 1;
298 		pRSNIEs->abyRSN[5] = 0;
299 		pRSNIEs->abyRSN[6] = 0x00;
300 		pRSNIEs->abyRSN[7] = 0x0F;
301 		pRSNIEs->abyRSN[8] = 0xAC;
302 		if (pMgmt->byCSSPK == KEY_CTL_TKIP)
303 			pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP;
304 		else if (pMgmt->byCSSPK == KEY_CTL_CCMP)
305 			pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP;
306 		else if (pMgmt->byCSSPK == KEY_CTL_NONE)
307 			pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
308 		else
309 			pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
310 
311 		pRSNIEs->len += 6;
312 
313 		// Auth Key Management Suite
314 		pRSNIEs->abyRSN[10] = 1;
315 		pRSNIEs->abyRSN[11] = 0;
316 		pRSNIEs->abyRSN[12] = 0x00;
317 		pRSNIEs->abyRSN[13] = 0x0F;
318 		pRSNIEs->abyRSN[14] = 0xAC;
319 		if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)
320 			pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK;
321 		else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)
322 			pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
323 		else
324 			pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
325 
326 		pRSNIEs->len += 6;
327 
328 		// RSN Capabilities
329 		if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
330 			memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
331 		} else {
332 			pRSNIEs->abyRSN[16] = 0;
333 			pRSNIEs->abyRSN[17] = 0;
334 		}
335 		pRSNIEs->len += 2;
336 
337 		if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
338 		    pMgmt->bRoaming &&
339 		    (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
340 			// RSN PMKID
341 			pwPMKID = (unsigned short *)(&pRSNIEs->abyRSN[18]);  // Point to PMKID count
342 			*pwPMKID = 0;                               // Initialize PMKID count
343 			pbyBuffer = &pRSNIEs->abyRSN[20];           // Point to PMKID list
344 			for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
345 				if (!memcmp(&pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
346 					(*pwPMKID)++;
347 					memcpy(pbyBuffer, pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 16);
348 					pbyBuffer += 16;
349 				}
350 			}
351 			if (*pwPMKID != 0)
352 				pRSNIEs->len += (2 + (*pwPMKID)*16);
353 			else
354 				pbyBuffer = &pRSNIEs->abyRSN[18];
355 		}
356 		return pRSNIEs->len + WLAN_IEHDR_LEN;
357 	}
358 	return 0;
359 }
360