summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/wpa.c
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/cmd/aux/wpa.c
parent2e0fac766c44301086d98910555ba351778cfb52 (diff)
wpa: automatically pick cipher suits from beacon rsne
Diffstat (limited to 'sys/src/cmd/aux/wpa.c')
-rw-r--r--sys/src/cmd/aux/wpa.c232
1 files changed, 215 insertions, 17 deletions
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.