summaryrefslogtreecommitdiff
path: root/sys/src
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-06-15 19:02:17 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-06-15 19:02:17 +0200
commit4cf627a131bb343f2ca0c252658186bcd68dfc5a (patch)
tree9ceb41f94c2d30da9e2840b62d64d765861bd775 /sys/src
parent2e0fac766c44301086d98910555ba351778cfb52 (diff)
wpa: automatically pick cipher suits from beacon rsne
Diffstat (limited to 'sys/src')
-rw-r--r--sys/src/9/pc/wifi.c29
-rw-r--r--sys/src/9/pc/wifi.h5
-rw-r--r--sys/src/cmd/aux/wpa.c232
3 files changed, 245 insertions, 21 deletions
diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c
index 1f0bd73b2..9d17fd249 100644
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -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++){
diff --git a/sys/src/9/pc/wifi.h b/sys/src/9/pc/wifi.h
index 718e1038d..c76357ea7 100644
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -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
diff --git a/sys/src/cmd/aux/wpa.c b/sys/src/cmd/aux/wpa.c
index f97116296..7b1712368 100644
--- a/sys/src/cmd/aux/wpa.c
+++ b/sys/src/cmd/aux/wpa.c
@@ -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.