diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-06-15 19:02:17 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-06-15 19:02:17 +0200 |
commit | 4cf627a131bb343f2ca0c252658186bcd68dfc5a (patch) | |
tree | 9ceb41f94c2d30da9e2840b62d64d765861bd775 /sys/src/cmd/aux/wpa.c | |
parent | 2e0fac766c44301086d98910555ba351778cfb52 (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.c | 232 |
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. |