]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/wpa.c
usb lib: add maxpkt and ntds to Altc struct
[plan9front.git] / sys / src / cmd / aux / wpa.c
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*
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
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*
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*
200 getessid(void)
201 {
202         return getifstats("essid:", essid, sizeof(essid));
203 }
204
205 int
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
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
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*
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
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*
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
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
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
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
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
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
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(tsmemcmp(B, IV, 8) != 0)
618                 return -1;
619         return n*8;
620 }
621
622 int
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
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 tsmemcmp(tmp, kd->mic, MIClen) != 0;
655 }
656
657 void
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
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
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
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
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
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
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
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
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", argv0, datalen-1, (char*)data+1);
919                 return;
920         case 33:        /* EAP Extensions (AVP) */
921                 if(debug)
922                         fprint(2, "eap extension: %.*H\n", datalen, data);
923                 eapresp(conn, 2, id, data, datalen);
924                 return;
925         case 26:        /* MS-CHAP-V2 */
926                 data++;
927                 datalen--;
928                 if(datalen < 1)
929                         break;
930
931                 /* OpCode */    
932                 switch(data[0]){
933                 case 1: /* Challenge */
934                         if(datalen > 4) {
935                                 uchar cid, chal[16], resp[48];
936                                 char user[256+1];
937                                 int len;
938
939                                 cid = data[1];
940                                 len = data[2]<<8 | data[3];
941                                 if(data[4] != sizeof(chal))
942                                         break;
943                                 if(len > datalen || (5 + data[4]) > len)
944                                         break;
945                                 memmove(chal, data+5, sizeof(chal));
946                                 memset(user, 0, sizeof(user));
947                                 memset(resp, 0, sizeof(resp));
948                                 if(auth_respond(chal, sizeof(chal), user, sizeof(user), resp, sizeof(resp), nil,
949                                         "proto=mschapv2 role=client service=wpa essid=%q", essid) < 0){
950                                         fprint(2, "%s: eap mschapv2: auth_respond: %r\n", argv0);
951                                         break;
952                                 }
953                                 len = 5 + sizeof(resp) + 1 + strlen(user);
954                                 data[0] = 2;            /* OpCode - Response */
955                                 data[1] = cid;          /* Identifier */
956                                 data[2] = len >> 8;
957                                 data[3] = len;
958                                 data[4] = sizeof(resp)+1;       /* ValueSize */
959                                 memmove(data+5, resp, sizeof(resp));
960                                 data[5 + sizeof(resp)] = 0;     /* flags */
961                                 strcpy((char*)&data[5 + sizeof(resp) + 1], user);
962
963                                 *(--data) = tp, len++;
964                                 eapresp(conn, 2, id, data, len);
965                                 return;
966                         }
967                         break;
968
969                 case 3: /* Success */
970                 case 4: /* Failure */
971                         if(debug || data[0] == 4)
972                                 fprint(2, "%s: eap mschapv2 %s: %.*s\n", argv0,
973                                         data[0] == 3 ? "Success" : "Failure",
974                                         datalen < 4 ? 0 : datalen-4, (char*)data+4);
975                         *(--data) = tp;
976                         eapresp(conn, 2, id, data, 2);
977                         return;
978                 }
979                 break;
980
981         case 21:        /* EAP-TTLS */
982         case 25:        /* PEAP */
983                 if(datalen < 2)
984                         break;
985                 datalen -= 2;
986                 data++;
987                 tunn = conn->tunn;
988                 if(*data & 0x20){       /* flags: start */
989                         int p[2], pid;
990
991                         if(tunn != nil){
992                                 if(tunn->id == id && tunn->tp == tp)
993                                         break;  /* is retransmit, ignore */
994                                 eapreset(conn);
995                         }
996                         if(pipe(p) < 0)
997                                 sysfatal("pipe: %r");
998                         if((pid = fork()) == -1)
999                                 sysfatal("fork: %r");
1000                         if(pid == 0){
1001                                 close(p[0]);
1002                                 switch(tp){
1003                                 case 21:
1004                                         ttlsclient(p[1]);
1005                                         break;
1006                                 case 25:
1007                                         peapclient(p[1]);
1008                                         break;
1009                                 }
1010                                 exits(nil);
1011                         }
1012                         close(p[1]);
1013                         tunn = emalloc(sizeof(TLStunn));
1014                         tunn->tp = tp;
1015                         tunn->id = id;
1016                         tunn->fd = p[0];
1017                         tunn->clientpid = pid;
1018                         conn->tunn = tunn;
1019                         if((pid = rfork(RFPROC|RFMEM)) == -1)
1020                                 sysfatal("fork: %r");
1021                         if(pid == 0){
1022                                 tunn->readerpid = getpid();
1023                                 tlsreader(tunn, conn);
1024                                 if(conn->tunn == tunn)
1025                                         conn->tunn = nil;
1026                                 close(tunn->fd);
1027                                 free(tunn);
1028                                 exits(nil);
1029                         }
1030                         return;
1031                 }
1032                 if(tunn == nil)
1033                         break;
1034                 if(id <= tunn->id || tunn->tp != tp)
1035                         break;
1036                 tunn->id = id;
1037                 frag = *data & 0x40;    /* flags: more fragments */
1038                 if(*data & 0x80){       /* flags: length included */
1039                         datalen -= 4;
1040                         data += 4;
1041                 }
1042                 data++;
1043                 if(datalen > 0)
1044                         write(tunn->fd, data, datalen);
1045                 if(frag || (tp == 25 && data[0] == 20)){        /* ack change cipher spec */
1046                         data -= 2;
1047                         data[0] = tp;
1048                         data[1] = 0;
1049                         eapresp(conn, 2, id, data, 2);
1050                 }
1051                 return;
1052         }
1053         goto unhandled;
1054 }
1055
1056 int
1057 avp(uchar *p, int n, int code, void *val, int len, int pad)
1058 {
1059         pad = 8 + ((len + pad) & ~pad); /* header + data + data pad */
1060         assert(((pad + 3) & ~3) <= n);
1061         p[0] = code >> 24;
1062         p[1] = code >> 16;
1063         p[2] = code >> 8;
1064         p[3] = code;
1065         p[4] = 2;
1066         p[5] = pad >> 16;
1067         p[6] = pad >> 8;
1068         p[7] = pad;
1069         memmove(p+8, val, len);
1070         len += 8;
1071         pad = (pad + 3) & ~3;   /* packet padding */
1072         memset(p+len, 0, pad - len);
1073         return pad;
1074 }
1075
1076 enum {
1077         /* Avp Code */
1078         AvpUserName = 1,
1079         AvpUserPass = 2,
1080         AvpChapPass = 3,
1081         AvpChapChal = 60,
1082 };
1083
1084 void
1085 ttlsclient(int fd)
1086 {
1087         uchar buf[4096];
1088         UserPasswd *up;
1089         int n;
1090
1091         fd = tlswrap(fd, "ttls keying material");
1092         if((up = auth_getuserpasswd(nil, "proto=pass service=wpa essid=%q", essid)) == nil)
1093                 sysfatal("auth_getuserpasswd: %r");
1094         n = avp(buf, sizeof(buf), AvpUserName, up->user, strlen(up->user), 0);
1095         n += avp(buf+n, sizeof(buf)-n, AvpUserPass, up->passwd, strlen(up->passwd), 15);
1096         freeup(up);
1097         write(fd, buf, n);
1098         memset(buf, 0, n);
1099 }
1100
1101 void
1102 peapwrite(Eapconn *conn, uchar *data, int len)
1103 {
1104         assert(len >= 4);
1105         fdwrite(conn, data + 4, len - 4);
1106 }
1107
1108 void
1109 peapclient(int fd)
1110 {
1111         static Eapconn conn;
1112         uchar buf[4096], *p;
1113         int n, id, code;
1114
1115         conn.fd = fd = tlswrap(fd, "client EAP encryption");
1116         while((n = read(fd, p = buf, sizeof(buf))) > 0){
1117                 if(n > 4 && (p[2] << 8 | p[3]) == n && p[4] == 33){
1118                         code = p[0];
1119                         id = p[1];
1120                         p += 4, n -= 4;
1121                         conn.write = fdwrite;
1122                 } else {
1123                         code = 1;
1124                         id = 0;
1125                         conn.write = peapwrite;
1126                 }
1127                 eapreq(&conn, code, id, p, n);
1128         }
1129 }
1130
1131 void
1132 usage(void)
1133 {
1134         fprint(2, "%s: [-dp12] [-s essid] dev\n", argv0);
1135         exits("usage");
1136 }
1137
1138 void
1139 background(void)
1140 {
1141         if(forked || debug)
1142                 return;
1143         switch(rfork(RFNOTEG|RFREND|RFPROC|RFNOWAIT)){
1144         default:
1145                 exits(nil);
1146         case -1:
1147                 sysfatal("fork: %r");
1148                 return;
1149         case 0:
1150                 break;
1151         }
1152         forked = 1;
1153 }
1154
1155 void
1156 main(int argc, char *argv[])
1157 {
1158         uchar mac[Eaddrlen], buf[4096], snonce[Noncelen], anonce[Noncelen];
1159         static uchar brsne[258];
1160         static Eapconn conn;
1161         char addr[128];
1162         uchar *rsne;
1163         int newptk; /* gate key reinstallation */
1164         int rsnelen;
1165         int n, try;
1166
1167         quotefmtinstall();
1168         fmtinstall('H', encodefmt);
1169         fmtinstall('E', eipfmt);
1170
1171         rsne = nil;
1172         rsnelen = -1;
1173         peercipher = nil;
1174         groupcipher = nil;
1175
1176         ARGBEGIN {
1177         case 'd':
1178                 debug = 1;
1179                 break;
1180         case 'p':
1181                 prompt = 1;
1182                 break;
1183         case 's':
1184                 strncpy(essid, EARGF(usage()), 32);
1185                 break;
1186         case '1':
1187                 rsne = wpaie;
1188                 rsnelen = sizeof(wpaie);
1189                 peercipher = &tkip;
1190                 groupcipher = &tkip;
1191                 break;
1192         case '2':
1193                 rsne = rsnie;
1194                 rsnelen = sizeof(rsnie);
1195                 peercipher = &ccmp;
1196                 groupcipher = &ccmp;
1197                 break;
1198         default:
1199                 usage();
1200         } ARGEND;
1201
1202         if(*argv != nil)
1203                 dev = *argv++;
1204
1205         if(*argv != nil || dev == nil)
1206                 usage();
1207
1208         if(myetheraddr(mac, dev) < 0)
1209                 sysfatal("can't get mac address: %r");
1210
1211         snprint(addr, sizeof(addr), "%s!0x888e", dev);
1212         if((fd = dial(addr, nil, devdir, &cfd)) < 0)
1213                 sysfatal("dial: %r");
1214
1215         if(essid[0] != 0){
1216                 if(fprint(cfd, "essid %q", essid) < 0)
1217                         sysfatal("write essid: %r");
1218         } else if(prompt) {
1219                 getessid();
1220                 if(essid[0] == 0)
1221                         sysfatal("no essid set");
1222         }
1223         if(!prompt)
1224                 background();
1225
1226 Connect:
1227         /* bss scan might not be complete yet, so check for 10 seconds. */
1228         for(try = 100; (forked || try >= 0) && !connected(); try--)
1229                 sleep(100);
1230
1231         authtype = AuthPSK;
1232         if(rsnelen <= 0 || rsne == brsne){
1233                 rsne = brsne;
1234                 rsnelen = buildrsne(rsne);
1235         }
1236         if(rsnelen > 0){
1237                 if(debug)
1238                         fprint(2, "rsne: %.*H\n", rsnelen, rsne);
1239                 /*
1240                  * we use write() instead of fprint so the message gets written
1241                  * at once and not chunked up on fprint buffer.
1242                  */
1243                 n = sprint((char*)buf, "auth %.*H", rsnelen, rsne);
1244                 if(write(cfd, buf, n) != n)
1245                         sysfatal("write auth: %r");
1246         } else {
1247                 authtype = AuthNone;
1248         }
1249
1250         conn.fd = fd;
1251         conn.write = eapwrite;
1252         conn.type = 1;  /* Start */
1253         conn.version = 1;
1254         memmove(conn.smac, mac, Eaddrlen);
1255         getbssid(conn.amac);
1256
1257         if(prompt){
1258                 UserPasswd *up;
1259                 prompt = 0;
1260                 switch(authtype){
1261                 case AuthNone:
1262                         print("no authentication required\n");
1263                         break;
1264                 case AuthPSK:
1265                         /* dummy to for factotum keyprompt */
1266                         genrandom(anonce, sizeof(anonce));
1267                         genrandom(snonce, sizeof(snonce));
1268                         getptk(auth_getkey, conn.smac, conn.amac, snonce, anonce, ptk);
1269                         break;
1270                 case AuthWPA:
1271                         up = auth_getuserpasswd(auth_getkey, "proto=pass service=wpa essid=%q", essid);
1272                         if(up != nil){
1273                                 factotumctl("key proto=mschapv2 role=client service=wpa"
1274                                         " essid=%q user=%q !password=%q\n",
1275                                         essid, up->user, up->passwd);
1276                                 freeup(up);
1277                         }
1278                         break;
1279                 }
1280                 background();
1281         }
1282
1283         genrandom(ptk, sizeof(ptk));
1284         newptk = 0;
1285
1286         lastrepc = 0ULL;
1287         for(;;){
1288                 uchar *p, *e, *m;
1289                 int proto, flags, vers, datalen;
1290                 uvlong repc, rsc, tsc;
1291                 Keydescr *kd;
1292
1293                 if((n = read(fd, buf, sizeof(buf))) < 0)
1294                         sysfatal("read: %r");
1295
1296                 if(n == 0){
1297                         if(debug)
1298                                 fprint(2, "got deassociation\n");
1299                         eapreset(&conn);
1300                         goto Connect;
1301                 }
1302
1303                 p = buf;
1304                 e = buf+n;
1305                 if(n < 2*Eaddrlen + 2)
1306                         continue;
1307
1308                 memmove(conn.smac, p, Eaddrlen); p += Eaddrlen;
1309                 memmove(conn.amac, p, Eaddrlen); p += Eaddrlen;
1310                 proto = p[0]<<8 | p[1]; p += 2;
1311
1312                 if(proto != 0x888e || memcmp(conn.smac, mac, Eaddrlen) != 0)
1313                         continue;
1314
1315                 m = p;
1316                 n = e - p;
1317                 if(n < 4)
1318                         continue;
1319
1320                 conn.version = p[0];
1321                 if(conn.version != 0x01 && conn.version != 0x02)
1322                         continue;
1323                 conn.type = p[1];
1324                 n = p[2]<<8 | p[3];
1325                 p += 4;
1326                 if(p+n > e)
1327                         continue;
1328                 e = p + n;
1329
1330                 if(debug)
1331                         fprint(2, "\nrecv(v%d,t%d) %E <- %E: ", conn.version, conn.type, conn.smac, conn.amac);
1332
1333                 if(authtype == AuthNone)
1334                         continue;
1335
1336                 if(conn.type == 0x00 && authtype == AuthWPA){
1337                         uchar code, id;
1338
1339                         if(n < 4)
1340                                 continue;
1341                         code = p[0];
1342                         id = p[1];
1343                         n = p[3] | p[2]<<8;
1344                         if(n < 4 || p + n > e)
1345                                 continue;
1346                         p += 4, n -= 4;
1347                         eapreq(&conn, code, id, p, n);
1348                         continue;
1349                 }
1350
1351                 if(conn.type != 0x03)
1352                         continue;
1353
1354                 if(n < Keydescrlen){
1355                         if(debug)
1356                                 fprint(2, "bad kd size\n");
1357                         continue;
1358                 }
1359                 kd = (Keydescr*)p;
1360                 if(debug)
1361                         dumpkeydescr(kd);
1362
1363                 if(kd->type[0] != 0xFE && kd->type[0] != 0x02)
1364                         continue;
1365
1366                 vers = kd->flags[1] & 7;
1367                 flags = kd->flags[0]<<8 | kd->flags[1];
1368                 datalen = kd->datalen[0]<<8 | kd->datalen[1];
1369                 if(kd->data + datalen > e)
1370                         continue;
1371
1372                 if((flags & Fmic) == 0){
1373                         if((flags & (Fptk|Fack)) != (Fptk|Fack))
1374                                 continue;
1375
1376                         memmove(anonce, kd->nonce, sizeof(anonce));
1377                         genrandom(snonce, sizeof(snonce));
1378                         if(getptk(nil, conn.smac, conn.amac, snonce, anonce, ptk) != 0){
1379                                 if(debug)
1380                                         fprint(2, "getptk: %r\n");
1381                                 continue;
1382                         }
1383                         /* allow installation of new keys */    
1384                         newptk = 1;
1385
1386                         /* ack key exchange with mic */
1387                         memset(kd->rsc, 0, sizeof(kd->rsc));
1388                         memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1389                         memmove(kd->nonce, snonce, sizeof(kd->nonce));
1390                         replykey(&conn, (flags & ~(Fack|Fins)) | Fmic, kd, rsne, rsnelen);
1391                 } else {
1392                         uchar gtk[GTKlen];
1393                         int gtklen, gtkkid;
1394
1395                         if(checkmic(kd, m, e - m) != 0){
1396                                 if(debug)
1397                                         fprint(2, "bad mic\n");
1398                                 continue;
1399                         }
1400
1401                         repc =  (uvlong)kd->repc[7] |
1402                                 (uvlong)kd->repc[6]<<8 |
1403                                 (uvlong)kd->repc[5]<<16 |
1404                                 (uvlong)kd->repc[4]<<24 |
1405                                 (uvlong)kd->repc[3]<<32 |
1406                                 (uvlong)kd->repc[2]<<40 |
1407                                 (uvlong)kd->repc[1]<<48 |
1408                                 (uvlong)kd->repc[0]<<56;
1409                         if(repc <= lastrepc){
1410                                 if(debug)
1411                                         fprint(2, "bad repc: %llux <= %llux\n", repc, lastrepc);
1412                                 continue;
1413                         }
1414                         lastrepc = repc;
1415
1416                         rsc =   (uvlong)kd->rsc[0] |
1417                                 (uvlong)kd->rsc[1]<<8 |
1418                                 (uvlong)kd->rsc[2]<<16 |
1419                                 (uvlong)kd->rsc[3]<<24 |
1420                                 (uvlong)kd->rsc[4]<<32 |
1421                                 (uvlong)kd->rsc[5]<<40;
1422
1423                         if(datalen > 0 && (flags & Fenc) != 0){
1424                                 if(vers == 1)
1425                                         datalen = rc4unwrap(ptk+16, kd->eapoliv, kd->data, datalen);
1426                                 else
1427                                         datalen = aesunwrap(ptk+16, 16, kd->data, datalen);
1428                                 if(datalen <= 0){
1429                                         if(debug)
1430                                                 fprint(2, "bad keywrap\n");
1431                                         continue;
1432                                 }
1433                                 if(debug)
1434                                         fprint(2, "unwraped keydata[%.4x]=%.*H\n", datalen, datalen, kd->data);
1435                         }
1436
1437                         gtklen = 0;
1438                         gtkkid = -1;
1439
1440                         if(kd->type[0] != 0xFE || (flags & (Fptk|Fack)) == (Fptk|Fack)){
1441                                 uchar *p, *x, *e;
1442
1443                                 p = kd->data;
1444                                 e = p + datalen;
1445                                 for(; p+2 <= e; p = x){
1446                                         if((x = p+2+p[1]) > e)
1447                                                 break;
1448                                         if(debug)
1449                                                 fprint(2, "ie=%.2x data[%.2x]=%.*H\n", p[0], p[1], p[1], p+2);
1450                                         if(p[0] == 0x30){ /* RSN */
1451                                         }
1452                                         if(p[0] == 0xDD){ /* WPA */
1453                                                 static uchar oui[] = { 0x00, 0x0f, 0xac, 0x01, };
1454
1455                                                 if(p+2+sizeof(oui) > x || memcmp(p+2, oui, sizeof(oui)) != 0)
1456                                                         continue;
1457                                                 if((flags & Fenc) == 0)
1458                                                         continue;       /* ignore gorup key if unencrypted */
1459                                                 gtklen = x - (p + 8);
1460                                                 if(gtklen <= 0)
1461                                                         continue;
1462                                                 if(gtklen > sizeof(gtk))
1463                                                         gtklen = sizeof(gtk);
1464                                                 memmove(gtk, p + 8, gtklen);
1465                                                 gtkkid = p[6] & 3;
1466                                         }
1467                                 }
1468                         }
1469
1470                         if((flags & (Fptk|Fack)) == (Fptk|Fack)){
1471                                 if(!newptk)     /* a retransmit, already installed PTK */
1472                                         continue;
1473                                 if(vers != 1)   /* in WPA2, RSC is for group key only */
1474                                         tsc = 0LL;
1475                                 else {
1476                                         tsc = rsc;
1477                                         rsc = 0LL;
1478                                 }
1479                                 /* install pairwise receive key (PTK) */
1480                                 if(fprint(cfd, "rxkey %E %s:%.*H@%llux", conn.amac,
1481                                         peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
1482                                         sysfatal("write rxkey: %r");
1483
1484                                 memset(kd->rsc, 0, sizeof(kd->rsc));
1485                                 memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1486                                 memset(kd->nonce, 0, sizeof(kd->nonce));
1487                                 replykey(&conn, flags & ~(Fack|Fenc|Fins), kd, nil, 0);
1488                                 sleep(100);
1489
1490                                 tsc = 0LL;
1491                                 /* install pairwise transmit key (PTK) */ 
1492                                 if(fprint(cfd, "txkey %E %s:%.*H@%llux", conn.amac,
1493                                         peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
1494                                         sysfatal("write txkey: %r");
1495                                 newptk = 0; /* prevent PTK re-installation on (replayed) retransmits */
1496                         } else
1497                         if((flags & (Fptk|Fsec|Fack)) == (Fsec|Fack)){
1498                                 if(kd->type[0] == 0xFE){
1499                                         /* WPA always RC4 encrypts the GTK, even tho the flag isnt set */
1500                                         if((flags & Fenc) == 0)
1501                                                 datalen = rc4unwrap(ptk+16, kd->eapoliv, kd->data, datalen);
1502                                         gtklen = datalen;
1503                                         if(gtklen > sizeof(gtk))
1504                                                 gtklen = sizeof(gtk);
1505                                         memmove(gtk, kd->data, gtklen);
1506                                         gtkkid = (flags >> 4) & 3;
1507                                 }
1508                                 memset(kd->rsc, 0, sizeof(kd->rsc));
1509                                 memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
1510                                 memset(kd->nonce, 0, sizeof(kd->nonce));
1511                                 replykey(&conn, flags & ~(Fenc|Fack), kd, nil, 0);
1512                         } else
1513                                 continue;
1514                         /* install group key (GTK) */
1515                         if(gtklen >= groupcipher->keylen && gtkkid != -1)
1516                                 if(fprint(cfd, "rxkey%d %E %s:%.*H@%llux",
1517                                         gtkkid, conn.amac, 
1518                                         groupcipher->name, groupcipher->keylen, gtk, rsc) < 0)
1519                                         sysfatal("write rxkey%d: %r", gtkkid);
1520                 }
1521         }
1522 }