wpa: automatically pick cipher suits from beacon rsne

This commit is contained in:
cinap_lenrek 2013-06-15 19:02:17 +02:00
parent 2e0fac766c
commit 4cf627a131
3 changed files with 245 additions and 21 deletions

View file

@ -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++){

View file

@ -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

View file

@ -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.