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
|
static void
|
||||||
recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
||||||
{
|
{
|
||||||
|
static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
|
||||||
uchar *e, *x;
|
uchar *e, *x;
|
||||||
uchar t, m[256/8];
|
uchar t, m[256/8];
|
||||||
|
|
||||||
|
@ -304,7 +305,7 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
||||||
m[t/8] |= 1<<(t%8);
|
m[t/8] |= 1<<(t%8);
|
||||||
|
|
||||||
switch(t){
|
switch(t){
|
||||||
case 0: /* SSID */
|
case 0x00: /* SSID */
|
||||||
len = 0;
|
len = 0;
|
||||||
while(len < Essidlen && d+len < x && d[len] != 0)
|
while(len < Essidlen && d+len < x && d[len] != 0)
|
||||||
len++;
|
len++;
|
||||||
|
@ -315,10 +316,20 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
|
||||||
wn->ssid[len] = 0;
|
wn->ssid[len] = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: /* DSPARAMS */
|
case 0x03: /* DSPARAMS */
|
||||||
if(d != x)
|
if(d != x)
|
||||||
wn->channel = d[0];
|
wn->channel = d[0];
|
||||||
break;
|
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, "status: %s\n", wifi->status);
|
||||||
p = seprint(p, e, "essid: %s\n", wifi->essid);
|
p = seprint(p, e, "essid: %s\n", wifi->essid);
|
||||||
|
|
||||||
wn = wifi->bss;
|
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;
|
now = MACHP(0)->ticks;
|
||||||
for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
|
for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
|
||||||
|
|
|
@ -27,15 +27,18 @@ struct Wnode
|
||||||
char ssid[Essidlen+2];
|
char ssid[Essidlen+2];
|
||||||
|
|
||||||
int rsnelen;
|
int rsnelen;
|
||||||
uchar rsne[256];
|
uchar rsne[258];
|
||||||
Wkey txkey[1];
|
Wkey txkey[1];
|
||||||
Wkey rxkey[5];
|
Wkey rxkey[5];
|
||||||
|
|
||||||
|
/* stuff from beacon */
|
||||||
int ival;
|
int ival;
|
||||||
int cap;
|
int cap;
|
||||||
int aid;
|
int aid;
|
||||||
int channel;
|
int channel;
|
||||||
long lastseen;
|
long lastseen;
|
||||||
|
int brsnelen;
|
||||||
|
uchar brsne[258];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Wifi
|
struct Wifi
|
||||||
|
|
|
@ -66,6 +66,10 @@ uchar ptk[PTKlen];
|
||||||
char essid[32+1];
|
char essid[32+1];
|
||||||
uvlong lastrepc;
|
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[] = {
|
uchar rsnie[] = {
|
||||||
0x30, /* RSN */
|
0x30, /* RSN */
|
||||||
0x14, /* length */
|
0x14, /* length */
|
||||||
|
@ -78,6 +82,10 @@ uchar rsnie[] = {
|
||||||
0x00, 0x00, /* capabilities */
|
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[] = {
|
uchar wpaie[] = {
|
||||||
0xdd, /* vendor specific */
|
0xdd, /* vendor specific */
|
||||||
0x16, /* length */
|
0x16, /* length */
|
||||||
|
@ -90,8 +98,31 @@ uchar wpaie[] = {
|
||||||
0x00, 0x50, 0xf2, 0x02, /* authentication suite PSK */
|
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*
|
char*
|
||||||
getessid(void)
|
getifstats(char *key, char *val, int nval)
|
||||||
{
|
{
|
||||||
char buf[8*1024], *f[2], *p, *e;
|
char buf[8*1024], *f[2], *p, *e;
|
||||||
int fd, n;
|
int fd, n;
|
||||||
|
@ -101,21 +132,171 @@ getessid(void)
|
||||||
return nil;
|
return nil;
|
||||||
n = read(fd, buf, sizeof(buf)-1);
|
n = read(fd, buf, sizeof(buf)-1);
|
||||||
close(fd);
|
close(fd);
|
||||||
if(n > 0){
|
if(n <= 0)
|
||||||
buf[n] = 0;
|
return nil;
|
||||||
for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
|
buf[n] = 0;
|
||||||
*e++ = 0;
|
for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
|
||||||
if(tokenize(p, f, 2) != 2)
|
*e++ = 0;
|
||||||
continue;
|
if(tokenize(p, f, 2) != 2)
|
||||||
if(strcmp(f[0], "essid:") != 0)
|
continue;
|
||||||
continue;
|
if(strcmp(f[0], key) != 0)
|
||||||
strncpy(essid, f[1], 32);
|
continue;
|
||||||
return essid;
|
strncpy(val, f[1], nval);
|
||||||
}
|
val[nval-1] = 0;
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
return nil;
|
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
|
int
|
||||||
getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
|
getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
|
||||||
uchar snonce[Noncelen], uchar anonce[Noncelen],
|
uchar snonce[Noncelen], uchar anonce[Noncelen],
|
||||||
|
@ -353,11 +534,10 @@ main(int argc, char *argv[])
|
||||||
fmtinstall('H', Hfmt);
|
fmtinstall('H', Hfmt);
|
||||||
fmtinstall('E', eipfmt);
|
fmtinstall('E', eipfmt);
|
||||||
|
|
||||||
/* default is WPA */
|
rsne = nil;
|
||||||
rsne = wpaie;
|
rsnelen = -1;
|
||||||
rsnelen = sizeof(wpaie);
|
peercipher = nil;
|
||||||
peercipher = &tkip;
|
groupcipher = nil;
|
||||||
groupcipher = &tkip;
|
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -415,6 +595,24 @@ main(int argc, char *argv[])
|
||||||
free(s);
|
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
|
* we use write() instead of fprint so message gets written
|
||||||
* at once and not chunked up on fprint buffer.
|
* at once and not chunked up on fprint buffer.
|
||||||
|
|
Loading…
Reference in a new issue