25 Keydescrlen = 1+2+2+8+32+16+8+8+16+2,
28 typedef struct Keydescr Keydescr;
56 0x01, 0x00, /* version 1 */
57 0x00, 0x0F, 0xAC, 0x02, /* group cipher suite TKIP */
58 0x01, 0x00, /* peerwise cipher suite count 1 */
59 0x00, 0x0F, 0xAC, 0x02, /* peerwise cipher suite TKIP */
60 0x01, 0x00, /* authentication suite count 1 */
61 0x00, 0x0F, 0xAC, 0x02, /* authentication suite PSK */
62 0x00, 0x00, /* capabilities */
66 0xdd, /* vendor specific */
68 0x00, 0x50, 0xf2, 0x01, /* WPAIE type 1 */
69 0x01, 0x00, /* version 1 */
70 0x00, 0x50, 0xf2, 0x02, /* group cipher suite TKIP */
71 0x01, 0x00, /* peerwise cipher suite count 1 */
72 0x00, 0x50, 0xf2, 0x02, /* peerwise cipher suite TKIP */
73 0x01, 0x00, /* authentication suite count 1 */
74 0x00, 0x50, 0xf2, 0x02, /* authentication suite PSK */
77 /* only WPA for now */
79 int rsnelen = sizeof(wpaie);
84 char buf[8*1024], *f[2], *p, *e;
87 snprint(buf, sizeof(buf), "%s/ifstats", devdir);
88 if((fd = open(buf, OREAD)) < 0)
90 n = read(fd, buf, sizeof(buf)-1);
94 for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
96 if(tokenize(p, f, 2) != 2)
98 if(strcmp(f[0], "essid:") != 0)
100 strncpy(essid, f[1], 32);
108 getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
109 uchar snonce[Noncelen], uchar anonce[Noncelen],
112 uchar buf[2*Eaddrlen + 2*Noncelen], *p;
120 if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
122 if((rpc = auth_allocrpc(afd)) == nil)
124 if((s = getessid()) == nil)
126 if((s = smprint("proto=wpapsk role=client essid=%q", s)) == nil)
128 if((ret = auth_rpc(rpc, "start", s, strlen(s))) != ARok)
131 memmove(p, smac, Eaddrlen); p += Eaddrlen;
132 memmove(p, amac, Eaddrlen); p += Eaddrlen;
133 memmove(p, snonce, Noncelen); p += Noncelen;
134 memmove(p, anonce, Noncelen); p += Noncelen;
135 if((ret = auth_rpc(rpc, "write", buf, p - buf)) != ARok)
137 if((ret = auth_rpc(rpc, "read", nil, 0)) != ARok)
139 if(rpc->narg != PTKlen)
141 memmove(ptk, rpc->arg, PTKlen);
145 if(afd >= 0) close(afd);
146 if(rpc != nil) auth_freerpc(rpc);
155 p = va_arg(f->args, uchar*);
160 if(fmtprint(f, "%.2x", *p) < 0)
166 dumpkeydescr(Keydescr *kd)
183 f = kd->flags[0]<<8 | kd->flags[1];
184 fprint(2, "type=%.*H flags=%.*H ( ",
185 sizeof(kd->type), kd->type,
186 sizeof(kd->flags), kd->flags);
187 for(i=0; i<nelem(flags); i++)
188 if(flags[i].flag & f)
189 fprint(2, "%s ", flags[i].name);
190 fprint(2, ") len=%.*H\nrepc=%.*H nonce=%.*H\neapoliv=%.*H rsc=%.*H id=%.*H mic=%.*H\n",
191 sizeof(kd->keylen), kd->keylen,
192 sizeof(kd->repc), kd->repc,
193 sizeof(kd->nonce), kd->nonce,
194 sizeof(kd->eapoliv), kd->eapoliv,
195 sizeof(kd->rsc), kd->rsc,
196 sizeof(kd->id), kd->id,
197 sizeof(kd->mic), kd->mic);
198 i = kd->datalen[0]<<8 | kd->datalen[1];
199 fprint(2, "data[%.4x]=%.*H\n\n", i, i, kd->data);
203 reply(uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar *data, int datalen)
205 uchar buf[4096], mic[MD5dlen], *m, *p = buf;
207 memmove(p, amac, Eaddrlen); p += Eaddrlen;
208 memmove(p, smac, Eaddrlen); p += Eaddrlen;
215 datalen += Keydescrlen;
218 datalen -= Keydescrlen;
220 memmove(p, kd, Keydescrlen);
222 kd->flags[0] = flags >> 8;
223 kd->flags[1] = flags;
224 kd->datalen[0] = datalen >> 8;
225 kd->datalen[1] = datalen;
227 memmove(p, data, datalen);
230 memset(kd->mic, 0, sizeof(kd->mic));
232 hmac_md5(m, p - m, ptk, 16, mic, nil);
233 memmove(kd->mic, mic, sizeof(kd->mic));
236 fprint(2, "reply %E -> %E: ", smac, amac);
240 if(write(fd, buf, datalen) != datalen)
241 sysfatal("write: %r");
247 fprint(2, "%s: [-dp] [-s essid] dev\n", argv0);
252 main(int argc, char *argv[])
254 uchar mac[Eaddrlen], buf[1024];
259 fmtinstall('H', Hfmt);
260 fmtinstall('E', eipfmt);
270 strncpy(essid, EARGF(usage()), 32);
279 if(*argv != nil || dev == nil)
282 if(myetheraddr(mac, dev) < 0)
283 sysfatal("can't get mac address: %r");
285 snprint(addr, sizeof(addr), "%s!0x888e", dev);
286 if((fd = dial(addr, nil, devdir, &cfd)) < 0)
287 sysfatal("dial: %r");
290 if(fprint(cfd, "essid %s", essid) < 0)
291 sysfatal("write essid: %r");
299 s = smprint("proto=wpapsk essid=%q !password?", essid);
301 s = smprint("proto=wpapsk essid? !password?");
307 * we use write() instead of fprint so message gets written
308 * at once and not chunked up on fprint buffer.
310 n = sprint((char*)buf, "auth %.*H", rsnelen, rsne);
311 if(write(cfd, buf, n) != n)
312 sysfatal("write auth: %r");
315 switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)){
319 sysfatal("fork: %r");
327 uchar smac[Eaddrlen], amac[Eaddrlen], snonce[Noncelen], anonce[Noncelen], *p, *e, *m;
328 int proto, flags, kid;
332 if((n = read(fd, buf, sizeof(buf))) < 0)
333 sysfatal("read: %r");
336 if(n < 2*Eaddrlen + 2)
338 memmove(smac, p, Eaddrlen); p += Eaddrlen;
339 memmove(amac, p, Eaddrlen); p += Eaddrlen;
340 proto = p[0]<<8 | p[1]; p += 2;
341 if(proto != 0x888e || memcmp(smac, mac, Eaddrlen) != 0)
346 if(n < 4 || p[0] != 0x01 || p[1] != 0x03)
350 if(n < Keydescrlen || p + n > e)
354 fprint(2, "recv %E <- %E: ", smac, amac);
358 /* only WPA, RSN descriptor format not suppoted yet */
359 if(kd->type[0] != 0xFE)
362 flags = kd->flags[0]<<8 | kd->flags[1];
364 rsc = (uvlong)kd->rsc[0] |
365 (uvlong)kd->rsc[1]<<8 |
366 (uvlong)kd->rsc[2]<<16 |
367 (uvlong)kd->rsc[3]<<24 |
368 (uvlong)kd->rsc[4]<<32 |
369 (uvlong)kd->rsc[5]<<40;
371 repc = (uvlong)kd->repc[7] |
372 (uvlong)kd->repc[6]<<8 |
373 (uvlong)kd->repc[5]<<16 |
374 (uvlong)kd->repc[4]<<24 |
375 (uvlong)kd->repc[3]<<32 |
376 (uvlong)kd->repc[2]<<40 |
377 (uvlong)kd->repc[1]<<48 |
378 (uvlong)kd->repc[0]<<56;
383 if((flags & Fmic) == 0){
384 if((flags & (Fptk|Fack)) != (Fptk|Fack))
387 memmove(anonce, kd->nonce, sizeof(anonce));
388 genrandom(snonce, sizeof(snonce));
389 if(getptk(smac, amac, snonce, anonce, ptk) < 0)
392 /* ack key exchange with mic */
393 memset(kd->rsc, 0, sizeof(kd->rsc));
394 memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
395 memmove(kd->nonce, snonce, sizeof(kd->nonce));
396 reply(smac, amac, (flags & ~(Fack|Fins)) | Fmic, kd, rsne, rsnelen);
398 uchar tmp[MD5dlen], mic[MD5dlen];
401 memmove(tmp, kd->mic, sizeof(mic));
402 memset(kd->mic, 0, sizeof(kd->mic));
403 hmac_md5(m, e - m, ptk, 16, mic, nil);
404 if(memcmp(tmp, mic, sizeof(mic)) != 0)
409 if((flags & (Fptk|Fsec|Fack)) == (Fptk|Fack)){
410 /* install peerwise receive key */
411 if(fprint(cfd, "rxkey %.*H tkip:%.*H@%llux", Eaddrlen, amac, 32, ptk+32, rsc) < 0)
412 sysfatal("write rxkey: %r");
414 /* pick random 16bit tsc value for transmit */
415 rsc = 1 + (truerand() & 0x7fff);
416 memset(kd->rsc, 0, sizeof(kd->rsc));
419 memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
420 memset(kd->nonce, 0, sizeof(kd->nonce));
421 reply(smac, amac, flags & ~Fack, kd, nil, 0);
424 /* install peerwise transmit key */
425 if(fprint(cfd, "txkey %.*H tkip:%.*H@%llux", Eaddrlen, amac, 32, ptk+32, rsc) < 0)
426 sysfatal("write txkey: %r");
428 if((flags & (Fptk|Fsec|Fack)) == (Fsec|Fack)){
429 uchar seed[32], gtk[GTKlen];
433 len = kd->datalen[1]<<8 | kd->datalen[0];
434 if(len > sizeof(gtk))
436 memmove(gtk, kd->data, len);
437 memmove(seed, kd->eapoliv, 16);
438 memmove(seed+16, ptk+16, 16);
439 setupRC4state(&rs, seed, sizeof(seed));
443 /* install group key */
444 kid = (flags >> 4) & 3;
445 if(fprint(cfd, "rxkey%d %.*H tkip:%.*H@%llux", kid, Eaddrlen, amac, len, gtk, rsc) < 0)
446 sysfatal("write rxkey%d: %r", kid);
448 memset(kd->rsc, 0, sizeof(kd->rsc));
449 memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
450 memset(kd->nonce, 0, sizeof(kd->nonce));
451 reply(smac, amac, flags & ~Fack, kd, nil, 0);