xref: /plan9-contrib/sys/src/cmd/aux/wpa.c (revision 1bbb2cb28bd9faa18a4a0c27d58656ba5679737b)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <mp.h>
5 #include <libsec.h>
6 #include <auth.h>
7 
8 enum {
9 	PMKlen = 256/8,
10 	PTKlen = 512/8,
11 	GTKlen = 256/8,
12 
13 	MIClen = 16,
14 
15 	Noncelen = 32,
16 	Eaddrlen = 6,
17 };
18 
19 enum {
20 	Fptk	= 1<<3,
21 	Fins	= 1<<6,
22 	Fack	= 1<<7,
23 	Fmic	= 1<<8,
24 	Fsec	= 1<<9,
25 	Ferr	= 1<<10,
26 	Freq	= 1<<11,
27 	Fenc	= 1<<12,
28 
29 	Keydescrlen = 1+2+2+8+32+16+8+8+16+2,
30 };
31 
32 typedef struct Keydescr Keydescr;
33 struct Keydescr
34 {
35 	uchar	type[1];
36 	uchar	flags[2];
37 	uchar	keylen[2];
38 	uchar	repc[8];
39 	uchar	nonce[32];
40 	uchar	eapoliv[16];
41 	uchar	rsc[8];
42 	uchar	id[8];
43 	uchar	mic[16];
44 	uchar	datalen[2];
45 	uchar	data[];
46 };
47 
48 typedef struct Cipher Cipher;
49 struct Cipher
50 {
51 	char	*name;
52 	int	keylen;
53 };
54 
55 typedef struct Eapconn Eapconn;
56 typedef struct TLStunn TLStunn;
57 
58 struct Eapconn
59 {
60 	int	fd;
61 	int	version;
62 
63 	uchar	type;
64 	uchar	smac[Eaddrlen];
65 	uchar	amac[Eaddrlen];
66 
67 	TLStunn	*tunn;
68 
69 	void	(*write)(Eapconn*, uchar *data, int datalen);
70 };
71 
72 struct TLStunn
73 {
74 	int	fd;
75 
76 	int	clientpid;
77 	int	readerpid;
78 
79 	uchar	id;
80 	uchar	tp;
81 };
82 
83 Cipher	tkip = { "tkip", 32 };
84 Cipher	ccmp = { "ccmp", 16 };
85 
86 Cipher	*peercipher;
87 Cipher	*groupcipher;
88 
89 int	forked;
90 int	prompt;
91 int	debug;
92 int	fd, cfd;
93 char	*dev;
94 enum {
95 	AuthNone,
96 	AuthPSK,
97 	AuthWPA,
98 };
99 int	authtype;
100 char	devdir[40];
101 uchar	ptk[PTKlen];
102 char	essid[32+1];
103 uvlong	lastrepc;
104 
105 uchar rsntkipoui[4] = {0x00, 0x0F, 0xAC, 0x02};
106 uchar rsnccmpoui[4] = {0x00, 0x0F, 0xAC, 0x04};
107 uchar rsnapskoui[4] = {0x00, 0x0F, 0xAC, 0x02};
108 uchar rsnawpaoui[4] = {0x00, 0x0F, 0xAC, 0x01};
109 
110 uchar	rsnie[] = {
111 	0x30,			/* RSN */
112 	0x14,			/* length */
113 	0x01, 0x00,		/* version 1 */
114 	0x00, 0x0F, 0xAC, 0x04,	/* group cipher suite CCMP */
115 	0x01, 0x00,		/* pairwise cipher suite count 1 */
116 	0x00, 0x0F, 0xAC, 0x04,	/* pairwise cipher suite CCMP */
117 	0x01, 0x00,		/* authentication suite count 1 */
118 	0x00, 0x0F, 0xAC, 0x02,	/* authentication suite PSK */
119 	0x00, 0x00,		/* capabilities */
120 };
121 
122 uchar wpa1oui[4]    = {0x00, 0x50, 0xF2, 0x01};
123 uchar wpatkipoui[4] = {0x00, 0x50, 0xF2, 0x02};
124 uchar wpaapskoui[4] = {0x00, 0x50, 0xF2, 0x02};
125 uchar wpaawpaoui[4] = {0x00, 0x50, 0xF2, 0x01};
126 
127 uchar	wpaie[] = {
128 	0xdd,			/* vendor specific */
129 	0x16,			/* length */
130 	0x00, 0x50, 0xf2, 0x01,	/* WPAIE type 1 */
131 	0x01, 0x00,		/* version 1 */
132 	0x00, 0x50, 0xf2, 0x02,	/* group cipher suite TKIP */
133 	0x01, 0x00,		/* pairwise cipher suite count 1 */
134 	0x00, 0x50, 0xf2, 0x02,	/* pairwise cipher suite TKIP */
135 	0x01, 0x00,		/* authentication suite count 1 */
136 	0x00, 0x50, 0xf2, 0x02,	/* authentication suite PSK */
137 };
138 
139 void*
emalloc(int len)140 emalloc(int len)
141 {
142 	void *v;
143 
144 	if((v = mallocz(len, 1)) == nil)
145 		sysfatal("malloc: %r");
146 	return v;
147 }
148 
149 int
hextob(char * s,char ** sp,uchar * b,int n)150 hextob(char *s, char **sp, uchar *b, int n)
151 {
152 	int r;
153 
154 	n <<= 1;
155 	for(r = 0; r < n && *s; s++){
156 		*b <<= 4;
157 		if(*s >= '0' && *s <= '9')
158 			*b |= (*s - '0');
159 		else if(*s >= 'a' && *s <= 'f')
160 			*b |= 10+(*s - 'a');
161 		else if(*s >= 'A' && *s <= 'F')
162 			*b |= 10+(*s - 'A');
163 		else break;
164 		if((++r & 1) == 0)
165 			b++;
166 	}
167 	if(sp != nil)
168 		*sp = s;
169 	return r >> 1;
170 }
171 
172 char*
getifstats(char * key,char * val,int nval)173 getifstats(char *key, char *val, int nval)
174 {
175 	char buf[8*1024], *f[2], *p, *e;
176 	int fd, n;
177 
178 	snprint(buf, sizeof(buf), "%s/ifstats", devdir);
179 	if((fd = open(buf, OREAD)) < 0)
180 		return nil;
181 	n = readn(fd, buf, sizeof(buf)-1);
182 	close(fd);
183 	if(n <= 0)
184 		return nil;
185 	buf[n] = 0;
186 	for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
187 		*e++ = 0;
188 		if(gettokens(p, f, 2, "\t\r\n ") != 2)
189 			continue;
190 		if(strcmp(f[0], key) != 0)
191 			continue;
192 		strncpy(val, f[1], nval);
193 		val[nval-1] = 0;
194 		return val;
195 	}
196 	return nil;
197 }
198 
199 char*
getessid(void)200 getessid(void)
201 {
202 	return getifstats("essid:", essid, sizeof(essid));
203 }
204 
205 int
getbssid(uchar mac[Eaddrlen])206 getbssid(uchar mac[Eaddrlen])
207 {
208 	char buf[64];
209 
210 	if(getifstats("bssid:", buf, sizeof(buf)) != nil)
211 		return parseether(mac, buf);
212 	return -1;
213 }
214 
215 int
connected(void)216 connected(void)
217 {
218 	char status[1024];
219 
220 	if(getifstats("status:", status, sizeof(status)) == nil)
221 		return 0;
222 	if(strcmp(status, "connecting") == 0)
223 		return 0;
224 	if(strcmp(status, "unauthenticated") == 0)
225 		return 0;
226 	if(debug)
227 		fprint(2, "status: %s\n", status);
228 	return 1;
229 }
230 
231 int
buildrsne(uchar rsne[258])232 buildrsne(uchar rsne[258])
233 {
234 	char buf[1024];
235 	uchar brsne[258];
236 	int brsnelen;
237 	uchar *p, *w, *e;
238 	int i, n;
239 
240 	if(getifstats("brsne:", buf, sizeof(buf)) == nil)
241 		return 0;	/* not an error, might be old kernel */
242 
243 	brsnelen = hextob(buf, nil, brsne, sizeof(brsne));
244 	if(brsnelen <= 4){
245 trunc:		sysfatal("invalid or truncated RSNE; brsne: %s", buf);
246 		return 0;
247 	}
248 
249 	w = rsne;
250 	p = brsne;
251 	e = p + brsnelen;
252 	if(p[0] == 0x30){
253 		p += 2;
254 
255 		/* RSN */
256 		*w++ = 0x30;
257 		*w++ = 0;	/* length */
258 	} else if(p[0] == 0xDD){
259 		p += 2;
260 		if((e - p) < 4 || memcmp(p, wpa1oui, 4) != 0){
261 			sysfatal("unrecognized WPAIE type; brsne: %s", buf);
262 			return 0;
263 		}
264 
265 		/* WPA */
266 		*w++ = 0xDD;
267 		*w++ = 0;	/* length */
268 
269 		memmove(w, wpa1oui, 4);
270 		w += 4;
271 		p += 4;
272 	} else {
273 		sysfatal("unrecognized RSNE type; brsne: %s", buf);
274 		return 0;
275 	}
276 
277 	if((e - p) < 6)
278 		goto trunc;
279 
280 	*w++ = *p++;		/* version */
281 	*w++ = *p++;
282 
283 	if(rsne[0] == 0x30){
284 		if(memcmp(p, rsnccmpoui, 4) == 0)
285 			groupcipher = &ccmp;
286 		else if(memcmp(p, rsntkipoui, 4) == 0)
287 			groupcipher = &tkip;
288 		else {
289 			sysfatal("unrecognized RSN group cipher; brsne: %s", buf);
290 			return 0;
291 		}
292 	} else {
293 		if(memcmp(p, wpatkipoui, 4) != 0){
294 			sysfatal("unrecognized WPA group cipher; brsne: %s", buf);
295 			return 0;
296 		}
297 		groupcipher = &tkip;
298 	}
299 
300 	memmove(w, p, 4);	/* group cipher */
301 	w += 4;
302 	p += 4;
303 
304 	if((e - p) < 6)
305 		goto trunc;
306 
307 	*w++ = 0x01;		/* # of peer ciphers */
308 	*w++ = 0x00;
309 	n = *p++;
310 	n |= *p++ << 8;
311 
312 	if(n <= 0)
313 		goto trunc;
314 
315 	peercipher = &tkip;
316 	for(i=0; i<n; i++){
317 		if((e - p) < 4)
318 			goto trunc;
319 
320 		if(rsne[0] == 0x30 && memcmp(p, rsnccmpoui, 4) == 0 && peercipher == &tkip)
321 			peercipher = &ccmp;
322 		p += 4;
323 	}
324 	if(peercipher == &ccmp)
325 		memmove(w, rsnccmpoui, 4);
326 	else if(rsne[0] == 0x30)
327 		memmove(w, rsntkipoui, 4);
328 	else
329 		memmove(w, wpatkipoui, 4);
330 	w += 4;
331 
332 	if((e - p) < 6)
333 		goto trunc;
334 
335 	*w++ = 0x01;		/* # of auth suites */
336 	*w++ = 0x00;
337 	n = *p++;
338 	n |= *p++ << 8;
339 
340 	if(n <= 0)
341 		goto trunc;
342 
343 	for(i=0; i<n; i++){
344 		if((e - p) < 4)
345 			goto trunc;
346 
347 		if(rsne[0] == 0x30){
348 			/* look for PSK oui */
349 			if(memcmp(p, rsnapskoui, 4) == 0)
350 				break;
351 			/* look for WPA oui */
352 			if(memcmp(p, rsnawpaoui, 4) == 0){
353 				authtype = AuthWPA;
354 				break;
355 			}
356 		} else {
357 			/* look for PSK oui */
358 			if(memcmp(p, wpaapskoui, 4) == 0)
359 				break;
360 			/* look for WPA oui */
361 			if(memcmp(p, wpaawpaoui, 4) == 0){
362 				authtype = AuthWPA;
363 				break;
364 			}
365 		}
366 		p += 4;
367 	}
368 	if(i >= n){
369 		sysfatal("auth suite is not PSK or WPA; brsne: %s", buf);
370 		return 0;
371 	}
372 
373 	memmove(w, p, 4);
374 	w += 4;
375 
376 	if(rsne[0] == 0x30){
377 		/* RSN caps */
378 		*w++ = 0x00;
379 		*w++ = 0x00;
380 	}
381 
382 	rsne[1] = (w - rsne) - 2;
383 	return w - rsne;
384 }
385 
386 char*
factotumattr(char * attr,char * fmt,...)387 factotumattr(char *attr, char *fmt, ...)
388 {
389 	char buf[1024];
390 	va_list list;
391 	AuthRpc *rpc;
392 	char *val;
393 	Attr *a;
394 	int afd;
395 
396 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
397 		return nil;
398 	if((rpc = auth_allocrpc(afd)) == nil){
399 		close(afd);
400 		return nil;
401 	}
402 	va_start(list, fmt);
403 	vsnprint(buf, sizeof(buf), fmt, list);
404 	va_end(list);
405 	val = nil;
406 	if(auth_rpc(rpc, "start", buf, strlen(buf)) == 0){
407 		if((a = auth_attr(rpc)) != nil){
408 			if((val = _strfindattr(a, attr)) != nil)
409 				val = strdup(val);
410 			_freeattr(a);
411 		}
412 	}
413 	auth_freerpc(rpc);
414 	close(afd);
415 
416 	return val;
417 }
418 
419 void
freeup(UserPasswd * up)420 freeup(UserPasswd *up)
421 {
422 	memset(up->user, 0, strlen(up->user));
423 	memset(up->passwd, 0, strlen(up->passwd));
424 	free(up);
425 }
426 
427 char*
getidentity(void)428 getidentity(void)
429 {
430 	static char *identity;
431 	char *s;
432 
433 	s = nil;
434 	for(;;){
435 		if(getessid() == nil)
436 			break;
437 		if((s = factotumattr("user", "proto=pass service=wpa essid=%q", essid)) != nil)
438 			break;
439 		if((s = factotumattr("user", "proto=mschapv2 role=client service=wpa essid=%q", essid)) != nil)
440 			break;
441 		break;
442 	}
443 	if(s != nil){
444 		free(identity);
445 		identity = s;
446 	} else if(identity == nil)
447 		identity = strdup("anonymous");
448 	if(debug)
449 		fprint(2, "identity: %s\n", identity);
450 	return identity;
451 }
452 
453 int
factotumctl(char * fmt,...)454 factotumctl(char *fmt, ...)
455 {
456 	va_list list;
457 	int fd, r, n;
458 	char *s;
459 
460 	r = -1;
461 	if((fd = open("/mnt/factotum/ctl", OWRITE)) >= 0){
462 		va_start(list, fmt);
463 		s = vsmprint(fmt, list);
464 		va_end(list);
465 		if(s != nil){
466 			n = strlen(s);
467 			r = write(fd, s, n);
468 			memset(s, 0, n);
469 			free(s);
470 		}
471 		close(fd);
472 	}
473 	return r;
474 }
475 
476 int
setpmk(uchar pmk[PMKlen])477 setpmk(uchar pmk[PMKlen])
478 {
479 	if(getessid() == nil)
480 		return -1;
481 	return factotumctl("key proto=wpapsk role=client essid=%q !password=%.*H\n", essid, PMKlen, pmk);
482 }
483 
484 int
getptk(AuthGetkey * getkey,uchar smac[Eaddrlen],uchar amac[Eaddrlen],uchar snonce[Noncelen],uchar anonce[Noncelen],uchar ptk[PTKlen])485 getptk(AuthGetkey *getkey,
486 	uchar smac[Eaddrlen], uchar amac[Eaddrlen],
487 	uchar snonce[Noncelen],  uchar anonce[Noncelen],
488 	uchar ptk[PTKlen])
489 {
490 	uchar buf[2*Eaddrlen + 2*Noncelen], *p;
491 	AuthRpc *rpc;
492 	int afd, ret;
493 	char *s;
494 
495 	ret = -1;
496 	s = nil;
497 	rpc = nil;
498 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
499 		goto out;
500 	if((rpc = auth_allocrpc(afd)) == nil)
501 		goto out;
502 	if((s = getessid()) == nil)
503 		goto out;
504 	if((s = smprint("proto=wpapsk role=client essid=%q", s)) == nil)
505 		goto out;
506 	if((ret = auth_rpc(rpc, "start", s, strlen(s))) != ARok)
507 		goto out;
508 	p = buf;
509 	memmove(p, smac, Eaddrlen); p += Eaddrlen;
510 	memmove(p, amac, Eaddrlen); p += Eaddrlen;
511 	memmove(p, snonce, Noncelen); p += Noncelen;
512 	memmove(p, anonce, Noncelen); p += Noncelen;
513 	if((ret = auth_rpc(rpc, "write", buf, p - buf)) != ARok)
514 		goto out;
515 	if((ret = auth_rpc(rpc, "read", nil, 0)) != ARok)
516 		goto out;
517 	if(rpc->narg != PTKlen){
518 		ret = -1;
519 		goto out;
520 	}
521 	memmove(ptk, rpc->arg, PTKlen);
522 	ret = 0;
523 out:
524 	if(getkey != nil){
525 		switch(ret){
526 		case ARneedkey:
527 		case ARbadkey:
528 			(*getkey)(rpc->arg);
529 			break;
530 		}
531 	}
532 	free(s);
533 	if(afd >= 0) close(afd);
534 	if(rpc != nil) auth_freerpc(rpc);
535 	return ret;
536 }
537 
538 void
dumpkeydescr(Keydescr * kd)539 dumpkeydescr(Keydescr *kd)
540 {
541 	static struct {
542 		int	flag;
543 		char	*name;
544 	} flags[] = {
545 		Fptk,	"ptk",
546 		Fins,	"ins",
547 		Fack,	"ack",
548 		Fmic,	"mic",
549 		Fsec,	"sec",
550 		Ferr,	"err",
551 		Freq,	"req",
552 		Fenc,	"enc",
553 	};
554 	int i, f;
555 
556 	f = kd->flags[0]<<8 | kd->flags[1];
557 	fprint(2, "type=%.*H vers=%d flags=%.*H ( ",
558 		sizeof(kd->type), kd->type, kd->flags[1] & 7,
559 		sizeof(kd->flags), kd->flags);
560 	for(i=0; i<nelem(flags); i++)
561 		if(flags[i].flag & f)
562 			fprint(2, "%s ", flags[i].name);
563 	fprint(2, ") len=%.*H\nrepc=%.*H nonce=%.*H\neapoliv=%.*H rsc=%.*H id=%.*H mic=%.*H\n",
564 		sizeof(kd->keylen), kd->keylen,
565 		sizeof(kd->repc), kd->repc,
566 		sizeof(kd->nonce), kd->nonce,
567 		sizeof(kd->eapoliv), kd->eapoliv,
568 		sizeof(kd->rsc), kd->rsc,
569 		sizeof(kd->id), kd->id,
570 		sizeof(kd->mic), kd->mic);
571 	i = kd->datalen[0]<<8 | kd->datalen[1];
572 	fprint(2, "data[%.4x]=%.*H\n", i, i, kd->data);
573 }
574 
575 int
rc4unwrap(uchar key[16],uchar iv[16],uchar * data,int len)576 rc4unwrap(uchar key[16], uchar iv[16], uchar *data, int len)
577 {
578 	uchar seed[32];
579 	RC4state rs;
580 
581 	memmove(seed, iv, 16);
582 	memmove(seed+16, key, 16);
583 	setupRC4state(&rs, seed, sizeof(seed));
584 	rc4skip(&rs, 256);
585 	rc4(&rs, data, len);
586 	return len;
587 }
588 
589 int
aesunwrap(uchar * key,int nkey,uchar * data,int len)590 aesunwrap(uchar *key, int nkey, uchar *data, int len)
591 {
592 	static uchar IV[8] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, };
593 	uchar B[16], *R;
594 	AESstate s;
595 	uint t;
596 	int n;
597 
598 	len -= 8;
599 	if(len < 16 || (len % 8) != 0)
600 		return -1;
601 	n = len/8;
602 	t = n*6;
603 	setupAESstate(&s, key, nkey, 0);
604 	memmove(B, data, 8);
605 	memmove(data, data+8, n*8);
606 	do {
607 		for(R = data + (n - 1)*8; R >= data; t--, R -= 8){
608 			memmove(B+8, R, 8);
609 			B[7] ^= (t >> 0);
610 			B[6] ^= (t >> 8);
611 			B[5] ^= (t >> 16);
612 			B[4] ^= (t >> 24);
613 			aes_decrypt(s.dkey, s.rounds, B, B);
614 			memmove(R, B+8, 8);
615 		}
616 	} while(t > 0);
617 	if(memcmp(B, IV, 8) != 0)
618 		return -1;
619 	return n*8;
620 }
621 
622 int
calcmic(Keydescr * kd,uchar * msg,int msglen)623 calcmic(Keydescr *kd, uchar *msg, int msglen)
624 {
625 	int vers;
626 
627 	vers = kd->flags[1] & 7;
628 	memset(kd->mic, 0, MIClen);
629 	if(vers == 1){
630 		uchar digest[MD5dlen];
631 
632 		hmac_md5(msg, msglen, ptk, 16, digest, nil);
633 		memmove(kd->mic, digest, MIClen);
634 		return 0;
635 	}
636 	if(vers == 2){
637 		uchar digest[SHA1dlen];
638 
639 		hmac_sha1(msg, msglen, ptk, 16, digest, nil);
640 		memmove(kd->mic, digest, MIClen);
641 		return 0;
642 	}
643 	return -1;
644 }
645 
646 int
checkmic(Keydescr * kd,uchar * msg,int msglen)647 checkmic(Keydescr *kd, uchar *msg, int msglen)
648 {
649 	uchar tmp[MIClen];
650 
651 	memmove(tmp, kd->mic, MIClen);
652 	if(calcmic(kd, msg, msglen) != 0)
653 		return -1;
654 	return memcmp(tmp, kd->mic, MIClen) != 0;
655 }
656 
657 void
fdwrite(Eapconn * conn,uchar * data,int len)658 fdwrite(Eapconn *conn, uchar *data, int len)
659 {
660 	if(write(conn->fd, data, len) != len)
661 		sysfatal("write: %r");
662 }
663 
664 void
etherwrite(Eapconn * conn,uchar * data,int len)665 etherwrite(Eapconn *conn, uchar *data, int len)
666 {
667 	uchar *buf, *p;
668 	int n;
669 
670 	if(debug)
671 		fprint(2, "\nreply(v%d,t%d) %E -> %E: ", conn->version, conn->type, conn->smac, conn->amac);
672 	n = 2*Eaddrlen + 2 + len;
673 	if(n < 60) n = 60;	/* ETHERMINTU */
674 	p = buf = emalloc(n);
675 	/* ethernet header */
676 	memmove(p, conn->amac, Eaddrlen); p += Eaddrlen;
677 	memmove(p, conn->smac, Eaddrlen); p += Eaddrlen;
678 	*p++ = 0x88;
679 	*p++ = 0x8e;
680 	/* eapol data */
681 	memmove(p, data, len);
682 	fdwrite(conn, buf, n);
683 	free(buf);
684 }
685 
686 void
eapwrite(Eapconn * conn,uchar * data,int len)687 eapwrite(Eapconn *conn, uchar *data, int len)
688 {
689 	uchar *buf, *p;
690 
691 	p = buf = emalloc(len + 4);
692 	/* eapol header */
693 	*p++ = conn->version;
694 	*p++ = conn->type;
695 	*p++ = len >> 8;
696 	*p++ = len;
697 	/* eap data */
698 	memmove(p, data, len); p += len;
699 	etherwrite(conn, buf, p - buf);
700 	free(buf);
701 }
702 
703 void
replykey(Eapconn * conn,int flags,Keydescr * kd,uchar * data,int datalen)704 replykey(Eapconn *conn, int flags, Keydescr *kd, uchar *data, int datalen)
705 {
706 	uchar buf[4096], *p = buf;
707 
708 	/* eapol hader */
709 	*p++ = conn->version;
710 	*p++ = conn->type;
711 	datalen += Keydescrlen;
712 	*p++ = datalen >> 8;
713 	*p++ = datalen;
714 	datalen -= Keydescrlen;
715 	/* key header */
716 	memmove(p, kd, Keydescrlen);
717 	kd = (Keydescr*)p;
718 	kd->flags[0] = flags >> 8;
719 	kd->flags[1] = flags;
720 	kd->datalen[0] = datalen >> 8;
721 	kd->datalen[1] = datalen;
722 	/* key data */
723 	p = kd->data;
724 	memmove(p, data, datalen);
725 	p += datalen;
726 	/* mic */
727 	memset(kd->mic, 0, MIClen);
728 	if(flags & Fmic)
729 		calcmic(kd, buf, p - buf);
730 	etherwrite(conn, buf, p - buf);
731 	if(debug)
732 		dumpkeydescr(kd);
733 }
734 
735 void
eapresp(Eapconn * conn,int code,int id,uchar * data,int len)736 eapresp(Eapconn *conn, int code, int id, uchar *data, int len)
737 {
738 	uchar *buf, *p;
739 
740 	len += 4;
741 	p = buf = emalloc(len);
742 	/* eap header */
743 	*p++ = code;
744 	*p++ = id;
745 	*p++ = len >> 8;
746 	*p++ = len;
747 	memmove(p, data, len-4);
748 	(*conn->write)(conn, buf, len);
749 	free(buf);
750 
751 	if(debug)
752 		fprint(2, "eapresp(code=%d, id=%d, data=%.*H)\n", code, id, len-4, data);
753 }
754 
755 void
tlsreader(TLStunn * tunn,Eapconn * conn)756 tlsreader(TLStunn *tunn, Eapconn *conn)
757 {
758 	enum {
759 		Tlshdrsz = 5,
760 		TLStunnhdrsz = 6,
761 	};
762 	uchar *rec, *w, *p;
763 	int fd, n, css;
764 
765 	fd = tunn->fd;
766 	rec = nil;
767 	css = 0;
768 Reset:
769 	w = rec;
770 	w += TLStunnhdrsz;
771 	for(;;w += n){
772 		if((p = realloc(rec, (w - rec) + Tlshdrsz)) == nil)
773 			break;
774 		w = p + (w - rec), rec = p;
775 		if(readn(fd, w, Tlshdrsz) != Tlshdrsz)
776 			break;
777 		n = w[3]<<8 | w[4];
778 		if(n < 1)
779 			break;
780 		if((p = realloc(rec, (w - rec) + Tlshdrsz+n)) == nil)
781 			break;
782 		w = p + (w - rec), rec = p;
783 		if(readn(fd, w+Tlshdrsz, n) != n)
784 			break;
785 		n += Tlshdrsz;
786 
787 		/* batch records that need to be send together */
788 		if(!css){
789 			/* Client Certificate */
790 			if(w[0] == 22 && w[5] == 11)
791 				continue;
792 			/* Client Key Exchange */
793 			if(w[0] == 22 && w[5] == 16)
794 				continue;
795 			/* Change Cipher Spec */
796 			if(w[0] == 20){
797 				css = 1;
798 				continue;
799 			}
800 		}
801 
802 		/* do not forward alert, close connection */
803 		if(w[0] == 21)
804 			break;
805 
806 		/* check if we'r still the tunnel for this connection */
807 		if(conn->tunn != tunn)
808 			break;
809 
810 		/* flush records in encapsulation */
811 		p = rec + TLStunnhdrsz;
812 		w += n;
813 		n = w - p;
814 		*(--p) = n;
815 		*(--p) = n >> 8;
816 		*(--p) = n >> 16;
817 		*(--p) = n >> 24;
818 		*(--p) = 0x80;	/* flags: Length included */
819 		*(--p) = tunn->tp;
820 
821 		eapresp(conn, 2, tunn->id, p, w - p);
822 		goto Reset;
823 	}
824 	free(rec);
825 }
826 
827 void ttlsclient(int);
828 void peapclient(int);
829 
830 void
eapreset(Eapconn * conn)831 eapreset(Eapconn *conn)
832 {
833 	TLStunn *tunn;
834 
835 	tunn = conn->tunn;
836 	if(tunn == nil)
837 		return;
838 	if(debug)
839 		fprint(2, "eapreset: kill client %d\n", tunn->clientpid);
840 	conn->tunn = nil;
841 	postnote(PNPROC, tunn->clientpid, "kill");
842 }
843 
844 int
tlswrap(int fd,char * label)845 tlswrap(int fd, char *label)
846 {
847 	TLSconn *tls;
848 
849 	tls = emalloc(sizeof(TLSconn));
850 	if(debug)
851 		tls->trace = print;
852 	if(label != nil){
853 		/* tls client computes the 1024 bit MSK for us */
854 		tls->sessionType = "ttls";
855 		tls->sessionConst = label;
856 		tls->sessionKeylen = 128;
857 		tls->sessionKey = emalloc(tls->sessionKeylen);
858 	}
859 	fd = tlsClient(fd, tls);
860 	if(fd < 0)
861 		sysfatal("tlsClient: %r");
862 	if(label != nil && tls->sessionKey != nil){
863 		/*
864 		 * PMK is derived from MSK by taking the first 256 bits.
865 		 * we store the PMK into factotum with setpmk() associated
866 		 * with the current essid.
867 		 */
868 		if(setpmk(tls->sessionKey) < 0)
869 			sysfatal("setpmk: %r");
870 
871 		/* destroy session key */
872 		memset(tls->sessionKey, 0, tls->sessionKeylen);
873 	}
874 	free(tls->cert);	/* TODO: check cert */
875 	free(tls->sessionID);
876 	free(tls->sessionKey);
877 	free(tls);
878 	return fd;
879 }
880 
881 void
eapreq(Eapconn * conn,int code,int id,uchar * data,int datalen)882 eapreq(Eapconn *conn, int code, int id, uchar *data, int datalen)
883 {
884 	TLStunn *tunn;
885 	int tp, frag;
886 	char *user;
887 
888 	if(debug)
889 		fprint(2, "eapreq(code=%d, id=%d, data=%.*H)\n", code, id, datalen, data);
890 
891 	switch(code){
892 	case 1:	/* Request */
893 		break;
894 	case 4:	/* NAK */
895 	case 3:	/* Success */
896 		eapreset(conn);
897 		if(code == 4 || debug)
898 			fprint(2, "%s: eap code %s\n", argv0, code == 3 ? "Success" : "NAK");
899 		return;
900 	default:
901 	unhandled:
902 		if(debug)
903 			fprint(2, "unhandled: %.*H\n", datalen < 0 ? 0 : datalen, data);
904 		return;
905 	}
906 	if(datalen < 1)
907 		goto unhandled;
908 
909 	tp = data[0];
910 	switch(tp){
911 	case 1:		/* Identity */
912 		user = getidentity();
913 		datalen = 1+strlen(user);
914 		memmove(data+1, user, datalen-1);
915 		eapresp(conn, 2, id, data, datalen);
916 		return;
917 	case 2:
918 		fprint(2, "%s: eap error: %.*s\n",
919 			argv0, utfnlen((char*)data+1, datalen-1), (char*)data+1);
920 		return;
921 	case 33:	/* EAP Extensions (AVP) */
922 		if(debug)
923 			fprint(2, "eap extension: %.*H\n", datalen, data);
924 		eapresp(conn, 2, id, data, datalen);
925 		return;
926 	case 26:	/* MS-CHAP-V2 */
927 		data++;
928 		datalen--;
929 		if(datalen < 1)
930 			break;
931 
932 		/* OpCode */
933 		switch(data[0]){
934 		case 1:	/* Challenge */
935 			if(datalen > 4) {
936 				uchar cid, chal[16], resp[48];
937 				char user[256+1];
938 				int len;
939 
940 				cid = data[1];
941 				len = data[2]<<8 | data[3];
942 				if(data[4] != sizeof(chal))
943 					break;
944 				if(len > datalen || (5 + data[4]) > len)
945 					break;
946 				memmove(chal, data+5, sizeof(chal));
947 				memset(user, 0, sizeof(user));
948 				memset(resp, 0, sizeof(resp));
949 				if(auth_respond(chal, sizeof(chal), user, sizeof(user), resp, sizeof(resp), nil,
950 					"proto=mschapv2 role=client service=wpa essid=%q", essid) < 0){
951 					fprint(2, "%s: eap mschapv2: auth_respond: %r\n", argv0);
952 					break;
953 				}
954 				len = 5 + sizeof(resp) + 1 + strlen(user);
955 				data[0] = 2;		/* OpCode - Response */
956 				data[1] = cid;		/* Identifier */
957 				data[2] = len >> 8;
958 				data[3] = len;
959 				data[4] = sizeof(resp)+1;	/* ValueSize */
960 				memmove(data+5, resp, sizeof(resp));
961 				data[5 + sizeof(resp)] = 0;	/* flags */
962 				strcpy((char*)&data[5 + sizeof(resp) + 1], user);
963 
964 				*(--data) = tp, len++;
965 				eapresp(conn, 2, id, data, len);
966 				return;
967 			}
968 			break;
969 
970 		case 3:	/* Success */
971 		case 4:	/* Failure */
972 			if(debug || data[0] == 4)
973 				fprint(2, "%s: eap mschapv2 %s: %.*s\n", argv0,
974 					data[0] == 3 ? "Success" : "Failure",
975 					datalen < 4 ? 0 : utfnlen((char*)data+4, datalen-4), (char*)data+4);
976 			*(--data) = tp;
977 			eapresp(conn, 2, id, data, 2);
978 			return;
979 		}
980 		break;
981 
982 	case 21:	/* EAP-TTLS */
983 	case 25:	/* PEAP */
984 		if(datalen < 2)
985 			break;
986 		datalen -= 2;
987 		data++;
988 		tunn = conn->tunn;
989 		if(*data & 0x20){	/* flags: start */
990 			int p[2], pid;
991 
992 			if(tunn != nil){
993 				if(tunn->id == id && tunn->tp == tp)
994 					break;	/* is retransmit, ignore */
995 				eapreset(conn);
996 			}
997 			if(pipe(p) < 0)
998 				sysfatal("pipe: %r");
999 			if((pid = fork()) == -1)
1000 				sysfatal("fork: %r");
1001 			if(pid == 0){
1002 				close(p[0]);
1003 				switch(tp){
1004 				case 21:
1005 					ttlsclient(p[1]);
1006 					break;
1007 				case 25:
1008 					peapclient(p[1]);
1009 					break;
1010 				}
1011 				exits(nil);
1012 			}
1013 			close(p[1]);
1014 			tunn = emalloc(sizeof(TLStunn));
1015 			tunn->tp = tp;
1016 			tunn->id = id;
1017 			tunn->fd = p[0];
1018 			tunn->clientpid = pid;
1019 			conn->tunn = tunn;
1020 			if((pid = rfork(RFPROC|RFMEM)) == -1)
1021 				sysfatal("fork: %r");
1022 			if(pid == 0){
1023 				tunn->readerpid = getpid();
1024 				tlsreader(tunn, conn);
1025 				if(conn->tunn == tunn)
1026 					conn->tunn = nil;
1027 				close(tunn->fd);
1028 				free(tunn);
1029 				exits(nil);
1030 			}
1031 			return;
1032 		}
1033 		if(tunn == nil)
1034 			break;
1035 		if(id <= tunn->id || tunn->tp != tp)
1036 			break;
1037 		tunn->id = id;
1038 		frag = *data & 0x40;	/* flags: more fragments */
1039 		if(*data & 0x80){	/* flags: length included */
1040 			datalen -= 4;
1041 			data += 4;
1042 		}
1043 		data++;
1044 		if(datalen > 0)
1045 			write(tunn->fd, data, datalen);
1046 		if(frag || (tp == 25 && data[0] == 20)){	/* ack change cipher spec */
1047 			data -= 2;
1048 			data[0] = tp;
1049 			data[1] = 0;
1050 			eapresp(conn, 2, id, data, 2);
1051 		}
1052 		return;
1053 	}
1054 	goto unhandled;
1055 }
1056 
1057 int
avp(uchar * p,int n,int code,void * val,int len,int pad)1058 avp(uchar *p, int n, int code, void *val, int len, int pad)
1059 {
1060 	pad = 8 + ((len + pad) & ~pad);	/* header + data + data pad */
1061 	assert(((pad + 3) & ~3) <= n);
1062 	p[0] = code >> 24;
1063 	p[1] = code >> 16;
1064 	p[2] = code >> 8;
1065 	p[3] = code;
1066 	p[4] = 2;
1067 	p[5] = pad >> 16;
1068 	p[6] = pad >> 8;
1069 	p[7] = pad;
1070 	memmove(p+8, val, len);
1071 	len += 8;
1072 	pad = (pad + 3) & ~3;	/* packet padding */
1073 	memset(p+len, 0, pad - len);
1074 	return pad;
1075 }
1076 
1077 enum {
1078 	/* Avp Code */
1079 	AvpUserName = 1,
1080 	AvpUserPass = 2,
1081 	AvpChapPass = 3,
1082 	AvpChapChal = 60,
1083 };
1084 
1085 void
ttlsclient(int fd)1086 ttlsclient(int fd)
1087 {
1088 	uchar buf[4096];
1089 	UserPasswd *up;
1090 	int n;
1091 
1092 	fd = tlswrap(fd, "ttls keying material");
1093 	if((up = auth_getuserpasswd(nil, "proto=pass service=wpa essid=%q", essid)) == nil)
1094 		sysfatal("auth_getuserpasswd: %r");
1095 	n = avp(buf, sizeof(buf), AvpUserName, up->user, strlen(up->user), 0);
1096 	n += avp(buf+n, sizeof(buf)-n, AvpUserPass, up->passwd, strlen(up->passwd), 15);
1097 	freeup(up);
1098 	write(fd, buf, n);
1099 	memset(buf, 0, n);
1100 }
1101 
1102 void
peapwrite(Eapconn * conn,uchar * data,int len)1103 peapwrite(Eapconn *conn, uchar *data, int len)
1104 {
1105 	assert(len >= 4);
1106 	fdwrite(conn, data + 4, len - 4);
1107 }
1108 
1109 void
peapclient(int fd)1110 peapclient(int fd)
1111 {
1112 	static Eapconn conn;
1113 	uchar buf[4096], *p;
1114 	int n, id, code;
1115 
1116 	conn.fd = fd = tlswrap(fd, "client EAP encryption");
1117 	while((n = read(fd, p = buf, sizeof(buf))) > 0){
1118 		if(n > 4 && (p[2] << 8 | p[3]) == n && p[4] == 33){
1119 			code = p[0];
1120 			id = p[1];
1121 			p += 4, n -= 4;
1122 			conn.write = fdwrite;
1123 		} else {
1124 			code = 1;
1125 			id = 0;
1126 			conn.write = peapwrite;
1127 		}
1128 		eapreq(&conn, code, id, p, n);
1129 	}
1130 }
1131 
1132 void
usage(void)1133 usage(void)
1134 {
1135 	fprint(2, "%s: [-dp12] [-s essid] dev\n", argv0);
1136 	exits("usage");
1137 }
1138 
1139 void
background(void)1140 background(void)
1141 {
1142 	if(forked || debug)
1143 		return;
1144 	switch(rfork(RFNOTEG|RFREND|RFPROC|RFNOWAIT)){
1145 	default:
1146 		exits(nil);
1147 	case -1:
1148 		sysfatal("fork: %r");
1149 		return;
1150 	case 0:
1151 		break;
1152 	}
1153 	forked = 1;
1154 }
1155 
1156 void
main(int argc,char * argv[])1157 main(int argc, char *argv[])
1158 {
1159 	uchar mac[Eaddrlen], buf[4096], snonce[Noncelen], anonce[Noncelen];
1160 	static uchar brsne[258];
1161 	static Eapconn conn;
1162 	char addr[128];
1163 	uchar *rsne;
1164 	int newptk; /* gate key reinstallation */
1165 	int rsnelen;
1166 	int n, try;
1167 
1168 	quotefmtinstall();
1169 	fmtinstall('H', encodefmt);
1170 	fmtinstall('E', eipfmt);
1171 
1172 	rsne = nil;
1173 	rsnelen = -1;
1174 	peercipher = nil;
1175 	groupcipher = nil;
1176 
1177 	ARGBEGIN {
1178 	case 'd':
1179 		debug = 1;
1180 		break;
1181 	case 'p':
1182 		prompt = 1;
1183 		break;
1184 	case 's':
1185 		strncpy(essid, EARGF(usage()), 32);
1186 		break;
1187 	case '1':
1188 		rsne = wpaie;
1189 		rsnelen = sizeof(wpaie);
1190 		peercipher = &tkip;
1191 		groupcipher = &tkip;
1192 		break;
1193 	case '2':
1194 		rsne = rsnie;
1195 		rsnelen = sizeof(rsnie);
1196 		peercipher = &ccmp;
1197 		groupcipher = &ccmp;
1198 		break;
1199 	default:
1200 		usage();
1201 	} ARGEND;
1202 
1203 	if(*argv != nil)
1204 		dev = *argv++;
1205 
1206 	if(*argv != nil || dev == nil)
1207 		usage();
1208 
1209 	if(myetheraddr(mac, dev) < 0)
1210 		sysfatal("can't get mac address: %r");
1211 
1212 	snprint(addr, sizeof(addr), "%s!0x888e", dev);
1213 	if((fd = dial(addr, nil, devdir, &cfd)) < 0)
1214 		sysfatal("dial: %r");
1215 
1216 	if(essid[0] != 0){
1217 		if(fprint(cfd, "essid %q", essid) < 0)
1218 			sysfatal("write essid: %r");
1219 	} else if(prompt) {
1220 		getessid();
1221 		if(essid[0] == 0)
1222 			sysfatal("no essid set");
1223 	}
1224 	if(!prompt)
1225 		background();
1226 
1227 Connect:
1228  	/* bss scan might not be complete yet, so check for 10 seconds.	*/
1229 	for(try = 100; (forked || try >= 0) && !connected(); try--)
1230 		sleep(100);
1231 
1232 	authtype = AuthPSK;
1233 	if(rsnelen <= 0 || rsne == brsne){
1234 		rsne = brsne;
1235 		rsnelen = buildrsne(rsne);
1236 	}
1237 	if(rsnelen > 0){
1238 		if(debug)
1239 			fprint(2, "rsne: %.*H\n", rsnelen, rsne);
1240 		/*
1241 		 * we use write() instead of fprint so the message gets written
1242 		 * at once and not chunked up on fprint buffer.
1243 		 */
1244 		n = sprint((char*)buf, "auth %.*H", rsnelen, rsne);
1245 		if(write(cfd, buf, n) != n)
1246 			sysfatal("write auth: %r");
1247 	} else {
1248 		authtype = AuthNone;
1249 	}
1250 
1251 	conn.fd = fd;
1252 	conn.write = eapwrite;
1253 	conn.type = 1;	/* Start */
1254 	conn.version = 1;
1255 	memmove(conn.smac, mac, Eaddrlen);
1256 	getbssid(conn.amac);
1257 
1258 	if(prompt){
1259 		UserPasswd *up;
1260 		prompt = 0;
1261 		switch(authtype){
1262 		case AuthNone:
1263 			print("no authentication required\n");
1264 			break;
1265 		case AuthPSK:
1266 			/* dummy to for factotum keyprompt */
1267 			genrandom(anonce, sizeof(anonce));
1268 			genrandom(snonce, sizeof(snonce));
1269 			getptk(auth_getkey, conn.smac, conn.amac, snonce, anonce, ptk);
1270 			break;
1271 		case AuthWPA:
1272 			up = auth_getuserpasswd(auth_getkey, "proto=pass service=wpa essid=%q", essid);
1273 			if(up != nil){
1274 				factotumctl("key proto=mschapv2 role=client service=wpa"
1275 					" essid=%q user=%q !password=%q\n",
1276 					essid, up->user, up->passwd);
1277 				freeup(up);
1278 			}
1279 			break;
1280 		}
1281 		background();
1282 	}
1283 
1284 	genrandom(ptk, sizeof(ptk));
1285 	newptk = 0;
1286 
1287 	lastrepc = 0ULL;
1288 	for(;;){
1289 		uchar *p, *e, *m;
1290 		int proto, flags, vers, datalen;
1291 		uvlong repc, rsc, tsc;
1292 		Keydescr *kd;
1293 
1294 		if((n = read(fd, buf, sizeof(buf))) < 0)
1295 			sysfatal("read: %r");
1296 
1297 		if(n == 0){
1298 			if(debug)
1299 				fprint(2, "got deassociation\n");
1300 			eapreset(&conn);
1301 			goto Connect;
1302 		}
1303 
1304 		p = buf;
1305 		e = buf+n;
1306 		if(n < 2*Eaddrlen + 2)
1307 			continue;
1308 
1309 		memmove(conn.smac, p, Eaddrlen); p += Eaddrlen;
1310 		memmove(conn.amac, p, Eaddrlen); p += Eaddrlen;
1311 		proto = p[0]<<8 | p[1]; p += 2;
1312 
1313 		if(proto != 0x888e || memcmp(conn.smac, mac, Eaddrlen) != 0)
1314 			continue;
1315 
1316 		m = p;
1317 		n = e - p;
1318 		if(n < 4)
1319 			continue;
1320 
1321 		conn.version = p[0];
1322 		if(conn.version != 0x01 && conn.version != 0x02)
1323 			continue;
1324 		conn.type = p[1];
1325 		n = p[2]<<8 | p[3];
1326 		p += 4;
1327 		if(p+n > e)
1328 			continue;
1329 		e = p + n;
1330 
1331 		if(debug)
1332 			fprint(2, "\nrecv(v%d,t%d) %E <- %E: ", conn.version, conn.type, conn.smac, conn.amac);
1333 
1334 		if(authtype == AuthNone)
1335 			continue;
1336 
1337 		if(conn.type == 0x00 && authtype == AuthWPA){
1338 			uchar code, id;
1339 
1340 			if(n < 4)
1341 				continue;
1342 			code = p[0];
1343 			id = p[1];
1344 			n = p[3] | p[2]<<8;
1345 			if(n < 4 || p + n > e)
1346 				continue;
1347 			p += 4, n -= 4;
1348 			eapreq(&conn, code, id, p, n);
1349 			continue;
1350 		}
1351 
1352 		if(conn.type != 0x03)
1353 			continue;
1354 
1355 		if(n < Keydescrlen){
1356 			if(debug)
1357 				fprint(2, "bad kd size\n");
1358 			continue;
1359 		}
1360 		kd = (Keydescr*)p;
1361 		if(debug)
1362 			dumpkeydescr(kd);
1363 
1364 		if(kd->type[0] != 0xFE && kd->type[0] != 0x02)
1365 			continue;
1366 
1367 		vers = kd->flags[1] & 7;
1368 		flags = kd->flags[0]<<8 | kd->flags[1];
1369 		datalen = kd->datalen[0]<<8 | kd->datalen[1];
1370 		if(kd->data + datalen > e)
1371 			continue;
1372 
1373 		if((flags & Fmic) == 0){
1374 			if((flags & (Fptk|Fack)) != (Fptk|Fack))
1375 				continue;
1376 
1377 			memmove(anonce, kd->nonce, sizeof(anonce));
1378 			genrandom(snonce, sizeof(snonce));
1379 			if(getptk(nil, conn.smac, conn.amac, snonce, anonce, ptk) != 0){
1380 				if(debug)
1381 					fprint(2, "getptk: %r\n");
1382 				continue;
1383 			}
1384 			/* allow installation of new keys */
1385 			newptk = 1;
1386 
1387 			/* ack key exchange with mic */
1388 			memset(kd->rsc, 0, sizeof(kd->rsc));
1389 			memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1390 			memmove(kd->nonce, snonce, sizeof(kd->nonce));
1391 			replykey(&conn, (flags & ~(Fack|Fins)) | Fmic, kd, rsne, rsnelen);
1392 		} else {
1393 			uchar gtk[GTKlen];
1394 			int gtklen, gtkkid;
1395 
1396 			if(checkmic(kd, m, e - m) != 0){
1397 				if(debug)
1398 					fprint(2, "bad mic\n");
1399 				continue;
1400 			}
1401 
1402 			repc =	(uvlong)kd->repc[7] |
1403 				(uvlong)kd->repc[6]<<8 |
1404 				(uvlong)kd->repc[5]<<16 |
1405 				(uvlong)kd->repc[4]<<24 |
1406 				(uvlong)kd->repc[3]<<32 |
1407 				(uvlong)kd->repc[2]<<40 |
1408 				(uvlong)kd->repc[1]<<48 |
1409 				(uvlong)kd->repc[0]<<56;
1410 			if(repc <= lastrepc){
1411 				if(debug)
1412 					fprint(2, "bad repc: %llux <= %llux\n", repc, lastrepc);
1413 				continue;
1414 			}
1415 			lastrepc = repc;
1416 
1417 			rsc =	(uvlong)kd->rsc[0] |
1418 				(uvlong)kd->rsc[1]<<8 |
1419 				(uvlong)kd->rsc[2]<<16 |
1420 				(uvlong)kd->rsc[3]<<24 |
1421 				(uvlong)kd->rsc[4]<<32 |
1422 				(uvlong)kd->rsc[5]<<40;
1423 
1424 			if(datalen > 0 && (flags & Fenc) != 0){
1425 				if(vers == 1)
1426 					datalen = rc4unwrap(ptk+16, kd->eapoliv, kd->data, datalen);
1427 				else
1428 					datalen = aesunwrap(ptk+16, 16, kd->data, datalen);
1429 				if(datalen <= 0){
1430 					if(debug)
1431 						fprint(2, "bad keywrap\n");
1432 					continue;
1433 				}
1434 				if(debug)
1435 					fprint(2, "unwraped keydata[%.4x]=%.*H\n", datalen, datalen, kd->data);
1436 			}
1437 
1438 			gtklen = 0;
1439 			gtkkid = -1;
1440 
1441 			if(kd->type[0] != 0xFE || (flags & (Fptk|Fack)) == (Fptk|Fack)){
1442 				uchar *p, *x, *e;
1443 
1444 				p = kd->data;
1445 				e = p + datalen;
1446 				for(; p+2 <= e; p = x){
1447 					if((x = p+2+p[1]) > e)
1448 						break;
1449 					if(debug)
1450 						fprint(2, "ie=%.2x data[%.2x]=%.*H\n", p[0], p[1], p[1], p+2);
1451 					if(p[0] == 0x30){ /* RSN */
1452 					}
1453 					if(p[0] == 0xDD){ /* WPA */
1454 						static uchar oui[] = { 0x00, 0x0f, 0xac, 0x01, };
1455 
1456 						if(p+2+sizeof(oui) > x || memcmp(p+2, oui, sizeof(oui)) != 0)
1457 							continue;
1458 						if((flags & Fenc) == 0)
1459 							continue;	/* ignore gorup key if unencrypted */
1460 						gtklen = x - (p + 8);
1461 						if(gtklen <= 0)
1462 							continue;
1463 						if(gtklen > sizeof(gtk))
1464 							gtklen = sizeof(gtk);
1465 						memmove(gtk, p + 8, gtklen);
1466 						gtkkid = p[6] & 3;
1467 					}
1468 				}
1469 			}
1470 
1471 			if((flags & (Fptk|Fack)) == (Fptk|Fack)){
1472 				if(!newptk)	/* a retransmit, already installed PTK */
1473 					continue;
1474 				if(vers != 1)	/* in WPA2, RSC is for group key only */
1475 					tsc = 0LL;
1476 				else {
1477 					tsc = rsc;
1478 					rsc = 0LL;
1479 				}
1480 				/* install pairwise receive key (PTK) */
1481 				if(fprint(cfd, "rxkey %E %s:%.*H@%llux", conn.amac,
1482 					peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
1483 					sysfatal("write rxkey: %r");
1484 
1485 				memset(kd->rsc, 0, sizeof(kd->rsc));
1486 				memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1487 				memset(kd->nonce, 0, sizeof(kd->nonce));
1488 				replykey(&conn, flags & ~(Fack|Fenc|Fins), kd, nil, 0);
1489 				sleep(100);
1490 
1491 				tsc = 0LL;
1492 				/* install pairwise transmit key (PTK) */
1493 				if(fprint(cfd, "txkey %E %s:%.*H@%llux", conn.amac,
1494 					peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
1495 					sysfatal("write txkey: %r");
1496 				newptk = 0; /* prevent PTK re-installation on (replayed) retransmits */
1497 			} else
1498 			if((flags & (Fptk|Fsec|Fack)) == (Fsec|Fack)){
1499 				if(kd->type[0] == 0xFE){
1500 					/* WPA always RC4 encrypts the GTK, even tho the flag isnt set */
1501 					if((flags & Fenc) == 0)
1502 						datalen = rc4unwrap(ptk+16, kd->eapoliv, kd->data, datalen);
1503 					gtklen = datalen;
1504 					if(gtklen > sizeof(gtk))
1505 						gtklen = sizeof(gtk);
1506 					memmove(gtk, kd->data, gtklen);
1507 					gtkkid = (flags >> 4) & 3;
1508 				}
1509 				memset(kd->rsc, 0, sizeof(kd->rsc));
1510 				memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1511 				memset(kd->nonce, 0, sizeof(kd->nonce));
1512 				replykey(&conn, flags & ~(Fenc|Fack), kd, nil, 0);
1513 			} else
1514 				continue;
1515 			/* install group key (GTK) */
1516 			if(gtklen >= groupcipher->keylen && gtkkid != -1)
1517 				if(fprint(cfd, "rxkey%d %E %s:%.*H@%llux",
1518 					gtkkid, conn.amac,
1519 					groupcipher->name, groupcipher->keylen, gtk, rsc) < 0)
1520 					sysfatal("write rxkey%d: %r", gtkkid);
1521 		}
1522 	}
1523 }
1524