wpa: automatically pick cipher suits from beacon rsne
This commit is contained in:
parent
2e0fac766c
commit
4cf627a131
3 changed files with 245 additions and 21 deletions
|
@ -280,6 +280,7 @@ recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
|
|||
static void
|
||||
recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
||||
{
|
||||
static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
|
||||
uchar *e, *x;
|
||||
uchar t, m[256/8];
|
||||
|
||||
|
@ -304,7 +305,7 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
|||
m[t/8] |= 1<<(t%8);
|
||||
|
||||
switch(t){
|
||||
case 0: /* SSID */
|
||||
case 0x00: /* SSID */
|
||||
len = 0;
|
||||
while(len < Essidlen && d+len < x && d[len] != 0)
|
||||
len++;
|
||||
|
@ -315,10 +316,20 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
|||
wn->ssid[len] = 0;
|
||||
}
|
||||
break;
|
||||
case 3: /* DSPARAMS */
|
||||
case 0x03: /* DSPARAMS */
|
||||
if(d != x)
|
||||
wn->channel = d[0];
|
||||
break;
|
||||
case 0xdd: /* vendor specific */
|
||||
len = x - d;
|
||||
if(len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0)
|
||||
break;
|
||||
/* no break */
|
||||
case 0x30: /* RSN information */
|
||||
len = x - &d[-2];
|
||||
memmove(wn->brsne, &d[-2], len);
|
||||
wn->brsnelen = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -655,8 +666,20 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off)
|
|||
|
||||
p = seprint(p, e, "status: %s\n", wifi->status);
|
||||
p = seprint(p, e, "essid: %s\n", wifi->essid);
|
||||
|
||||
wn = wifi->bss;
|
||||
p = seprint(p, e, "bssid: %E\n", wn != nil ? wn->bssid : zeros);
|
||||
if(wn != nil){
|
||||
p = seprint(p, e, "bssid: %E\n", wn->bssid);
|
||||
if(wn->brsnelen > 0){
|
||||
int i;
|
||||
|
||||
p = seprint(p, e, "brsne: ");
|
||||
for(i=0; i<wn->brsnelen; i++)
|
||||
p = seprint(p, e, "%.2X", wn->brsne[i]);
|
||||
p = seprint(p, e, "\n");
|
||||
}
|
||||
p = seprint(p, e, "channel: %.2d\n", wn->channel);
|
||||
}
|
||||
|
||||
now = MACHP(0)->ticks;
|
||||
for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
|
||||
|
|
|
@ -27,15 +27,18 @@ struct Wnode
|
|||
char ssid[Essidlen+2];
|
||||
|
||||
int rsnelen;
|
||||
uchar rsne[256];
|
||||
uchar rsne[258];
|
||||
Wkey txkey[1];
|
||||
Wkey rxkey[5];
|
||||
|
||||
/* stuff from beacon */
|
||||
int ival;
|
||||
int cap;
|
||||
int aid;
|
||||
int channel;
|
||||
long lastseen;
|
||||
int brsnelen;
|
||||
uchar brsne[258];
|
||||
};
|
||||
|
||||
struct Wifi
|
||||
|
|
|
@ -66,6 +66,10 @@ uchar ptk[PTKlen];
|
|||
char essid[32+1];
|
||||
uvlong lastrepc;
|
||||
|
||||
uchar rsntkipoui[4] = {0x00, 0x0F, 0xAC, 0x02};
|
||||
uchar rsnccmpoui[4] = {0x00, 0x0F, 0xAC, 0x04};
|
||||
uchar rsnapskoui[4] = {0x00, 0x0F, 0xAC, 0x02};
|
||||
|
||||
uchar rsnie[] = {
|
||||
0x30, /* RSN */
|
||||
0x14, /* length */
|
||||
|
@ -78,6 +82,10 @@ uchar rsnie[] = {
|
|||
0x00, 0x00, /* capabilities */
|
||||
};
|
||||
|
||||
uchar wpa1oui[4] = {0x00, 0x50, 0xF2, 0x01};
|
||||
uchar wpatkipoui[4] = {0x00, 0x50, 0xF2, 0x02};
|
||||
uchar wpaapskoui[4] = {0x00, 0x50, 0xF2, 0x02};
|
||||
|
||||
uchar wpaie[] = {
|
||||
0xdd, /* vendor specific */
|
||||
0x16, /* length */
|
||||
|
@ -90,8 +98,31 @@ uchar wpaie[] = {
|
|||
0x00, 0x50, 0xf2, 0x02, /* authentication suite PSK */
|
||||
};
|
||||
|
||||
int
|
||||
hextob(char *s, char **sp, uchar *b, int n)
|
||||
{
|
||||
int r;
|
||||
|
||||
n <<= 1;
|
||||
for(r = 0; r < n && *s; s++){
|
||||
*b <<= 4;
|
||||
if(*s >= '0' && *s <= '9')
|
||||
*b |= (*s - '0');
|
||||
else if(*s >= 'a' && *s <= 'f')
|
||||
*b |= 10+(*s - 'a');
|
||||
else if(*s >= 'A' && *s <= 'F')
|
||||
*b |= 10+(*s - 'A');
|
||||
else break;
|
||||
if((++r & 1) == 0)
|
||||
b++;
|
||||
}
|
||||
if(sp != nil)
|
||||
*sp = s;
|
||||
return r >> 1;
|
||||
}
|
||||
|
||||
char*
|
||||
getessid(void)
|
||||
getifstats(char *key, char *val, int nval)
|
||||
{
|
||||
char buf[8*1024], *f[2], *p, *e;
|
||||
int fd, n;
|
||||
|
@ -101,21 +132,171 @@ getessid(void)
|
|||
return nil;
|
||||
n = read(fd, buf, sizeof(buf)-1);
|
||||
close(fd);
|
||||
if(n > 0){
|
||||
buf[n] = 0;
|
||||
for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
|
||||
*e++ = 0;
|
||||
if(tokenize(p, f, 2) != 2)
|
||||
continue;
|
||||
if(strcmp(f[0], "essid:") != 0)
|
||||
continue;
|
||||
strncpy(essid, f[1], 32);
|
||||
return essid;
|
||||
}
|
||||
if(n <= 0)
|
||||
return nil;
|
||||
buf[n] = 0;
|
||||
for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
|
||||
*e++ = 0;
|
||||
if(tokenize(p, f, 2) != 2)
|
||||
continue;
|
||||
if(strcmp(f[0], key) != 0)
|
||||
continue;
|
||||
strncpy(val, f[1], nval);
|
||||
val[nval-1] = 0;
|
||||
return val;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
getessid(void)
|
||||
{
|
||||
return getifstats("essid:", essid, sizeof(essid));
|
||||
}
|
||||
|
||||
int
|
||||
buildrsne(uchar rsne[258])
|
||||
{
|
||||
char buf[1024];
|
||||
uchar brsne[258];
|
||||
int brsnelen;
|
||||
uchar *p, *w, *e;
|
||||
int i, n;
|
||||
|
||||
if(getifstats("brsne:", buf, sizeof(buf)) == nil)
|
||||
return 0; /* not an error, might be old kernel */
|
||||
|
||||
brsnelen = hextob(buf, nil, brsne, sizeof(brsne));
|
||||
if(brsnelen <= 4){
|
||||
trunc: sysfatal("invalid or truncated RSNE; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
w = rsne;
|
||||
p = brsne;
|
||||
e = p + brsnelen;
|
||||
if(p[0] == 0x30){
|
||||
p += 2;
|
||||
|
||||
/* RSN */
|
||||
*w++ = 0x30;
|
||||
*w++ = 0; /* length */
|
||||
} else if(p[0] == 0xDD){
|
||||
p += 2;
|
||||
if((e - p) < 4 || memcmp(p, wpa1oui, 4) != 0){
|
||||
sysfatal("unrecognized WPAIE type; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* WPA */
|
||||
*w++ = 0xDD;
|
||||
*w++ = 0; /* length */
|
||||
|
||||
memmove(w, wpa1oui, 4);
|
||||
w += 4;
|
||||
} else {
|
||||
sysfatal("unrecognized RSNE type; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((e - p) < 6)
|
||||
goto trunc;
|
||||
|
||||
*w++ = *p++; /* version */
|
||||
*w++ = *p++;
|
||||
|
||||
if(rsne[0] == 0x30){
|
||||
if(memcmp(p, rsnccmpoui, 4) == 0)
|
||||
groupcipher = &ccmp;
|
||||
else if(memcmp(p, rsnccmpoui, 4) == 0)
|
||||
groupcipher = &tkip;
|
||||
else {
|
||||
sysfatal("unrecognized RSN group cipher; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(memcmp(p, wpatkipoui, 4) != 0){
|
||||
sysfatal("unrecognized WPA group cipher; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
groupcipher = &tkip;
|
||||
}
|
||||
|
||||
memmove(w, p, 4); /* group cipher */
|
||||
w += 4;
|
||||
p += 4;
|
||||
|
||||
if((e - p) < 6)
|
||||
goto trunc;
|
||||
|
||||
*w++ = 0x01; /* # of peer ciphers */
|
||||
*w++ = 0x00;
|
||||
n = *p++;
|
||||
n |= *p++ << 8;
|
||||
|
||||
if(n <= 0)
|
||||
goto trunc;
|
||||
|
||||
peercipher = &tkip;
|
||||
for(i=0; i<n; i++){
|
||||
if((e - p) < 4)
|
||||
goto trunc;
|
||||
|
||||
if(rsne[0] == 0x30 && memcmp(p, rsnccmpoui, 4) == 0 && peercipher == &tkip)
|
||||
peercipher = &ccmp;
|
||||
p += 4;
|
||||
}
|
||||
if(peercipher == &ccmp)
|
||||
memmove(w, rsnccmpoui, 4);
|
||||
else if(rsne[0] == 0x30)
|
||||
memmove(w, rsntkipoui, 4);
|
||||
else
|
||||
memmove(w, wpatkipoui, 4);
|
||||
w += 4;
|
||||
|
||||
if((e - p) < 6)
|
||||
goto trunc;
|
||||
|
||||
*w++ = 0x01; /* # of auth suites */
|
||||
*w++ = 0x00;
|
||||
n = *p++;
|
||||
n |= *p++ << 8;
|
||||
|
||||
if(n <= 0)
|
||||
goto trunc;
|
||||
|
||||
for(i=0; i<n; i++){
|
||||
if((e - p) < 4)
|
||||
goto trunc;
|
||||
|
||||
/* look for PSK oui */
|
||||
if(rsne[0] == 0x30){
|
||||
if(memcmp(p, rsnapskoui, 4) == 0)
|
||||
break;
|
||||
} else {
|
||||
if(memcmp(p, wpaapskoui, 4) == 0)
|
||||
break;
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
if(i >= n){
|
||||
sysfatal("auth suite is not PSK; brsne: %s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memmove(w, p, 4);
|
||||
w += 4;
|
||||
|
||||
if(rsne[0] == 0x30){
|
||||
/* RSN caps */
|
||||
*w++ = 0x00;
|
||||
*w++ = 0x00;
|
||||
}
|
||||
|
||||
rsne[1] = (w - rsne) - 2;
|
||||
return w - rsne;
|
||||
}
|
||||
|
||||
int
|
||||
getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
|
||||
uchar snonce[Noncelen], uchar anonce[Noncelen],
|
||||
|
@ -353,11 +534,10 @@ main(int argc, char *argv[])
|
|||
fmtinstall('H', Hfmt);
|
||||
fmtinstall('E', eipfmt);
|
||||
|
||||
/* default is WPA */
|
||||
rsne = wpaie;
|
||||
rsnelen = sizeof(wpaie);
|
||||
peercipher = &tkip;
|
||||
groupcipher = &tkip;
|
||||
rsne = nil;
|
||||
rsnelen = -1;
|
||||
peercipher = nil;
|
||||
groupcipher = nil;
|
||||
|
||||
ARGBEGIN {
|
||||
case 'd':
|
||||
|
@ -415,6 +595,24 @@ main(int argc, char *argv[])
|
|||
free(s);
|
||||
}
|
||||
|
||||
if(rsnelen <= 0){
|
||||
static uchar brsne[258];
|
||||
|
||||
rsne = brsne;
|
||||
rsnelen = buildrsne(rsne);
|
||||
}
|
||||
|
||||
if(rsnelen <= 0){
|
||||
/* default is WPA */
|
||||
rsne = wpaie;
|
||||
rsnelen = sizeof(wpaie);
|
||||
peercipher = &tkip;
|
||||
groupcipher = &tkip;
|
||||
}
|
||||
|
||||
if(debug)
|
||||
fprint(2, "rsne: %.*H\n", rsnelen, rsne);
|
||||
|
||||
/*
|
||||
* we use write() instead of fprint so message gets written
|
||||
* at once and not chunked up on fprint buffer.
|
||||
|
|
Loading…
Reference in a new issue