ref: 0b8851ddb688e8de813196b7cd62f113edde2e3a
parent: 0f97eb3a609cd892a0de1d61ef61e5b48be082d8
author: cinap_lenrek <[email protected]>
date: Sat Aug 27 16:35:39 EDT 2016
wifi: allocate cipher states in secret memory, do AESstate key setup once
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -48,6 +48,7 @@
static Block* wifidecrypt(Wifi *, Wnode *, Block *);
static Block* wifiencrypt(Wifi *, Wnode *, Block *);
+static void freewifikeys(Wifi *, Wnode *);
static uchar*
srcaddr(Wifipkt *w)
@@ -197,6 +198,7 @@
}
if(!new)
return nil;
+ freewifikeys(wifi, nn);
memset(nn, 0, sizeof(Wnode));
memmove(nn->bssid, bssid, Eaddrlen);
nn->lastseen = MACHP(0)->ticks;
@@ -466,6 +468,23 @@
}
static void
+freewifikeys(Wifi *wifi, Wnode *wn)
+{
+ int i;
+
+ wlock(&wifi->crypt);
+ for(i=0; i<nelem(wn->rxkey); i++){
+ secfree(wn->rxkey[i]);
+ wn->rxkey[i] = nil;
+ }
+ for(i=0; i<nelem(wn->txkey); i++){
+ secfree(wn->txkey[i]);
+ wn->txkey[i] = nil;
+ }
+ wunlock(&wifi->crypt);
+}
+
+static void
wifideauth(Wifi *wifi, Wnode *wn)
{
Ether *ether;
@@ -474,8 +493,7 @@
/* deassociate node, clear keys */
setstatus(wifi, wn, Sunauth);
- memset(wn->rxkey, 0, sizeof(wn->rxkey));
- memset(wn->txkey, 0, sizeof(wn->txkey));
+ freewifikeys(wifi, wn);
wn->aid = 0;
if(wn == wifi->bss){
@@ -789,11 +807,13 @@
[CCMP] "ccmp",
};
-static int
-parsekey(Wkey *k, char *s)
+static Wkey*
+parsekey(char *s)
{
char buf[256], *p;
- int i;
+ uchar key[32];
+ int i, n;
+ Wkey *k;
strncpy(buf, s, sizeof(buf)-1);
buf[sizeof(buf)-1] = 0;
@@ -801,20 +821,35 @@
*p++ = 0;
else
p = buf;
- for(i=0; i<nelem(ciphers); i++){
- if(ciphers[i] == nil)
- continue;
+ n = hextob(p, &p, key, sizeof(key));
+ for(i=0; i<nelem(ciphers); i++)
if(strcmp(ciphers[i], buf) == 0)
break;
+ switch(i){
+ case 0:
+ k = secalloc(sizeof(Wkey));
+ break;
+ case TKIP:
+ if(n != 32)
+ return nil;
+ k = secalloc(sizeof(Wkey) + n);
+ memmove(k->key, key, n);
+ break;
+ case CCMP:
+ if(n != 16)
+ return nil;
+ k = secalloc(sizeof(Wkey) + sizeof(AESstate));
+ setupAESstate((AESstate*)k->key, key, n, nil);
+ break;
+ default:
+ return nil;
}
- if(i >= nelem(ciphers))
- return -1;
- memset(k, 0, sizeof(Wkey));
- k->len = hextob(p, &p, k->key, sizeof(k->key));
+ memset(key, 0, sizeof(key));
if(*p == '@')
k->tsc = strtoull(++p, nil, 16);
+ k->len = n;
k->cipher = i;
- return 0;
+ return k;
}
void
@@ -874,7 +909,7 @@
Cmdbuf *cb;
Cmdtab *ct;
Wnode *wn;
- Wkey *k;
+ Wkey *k, **kk;
cb = nil;
if(waserror()){
@@ -931,8 +966,7 @@
memmove(wifi->bssid, addr, Eaddrlen);
goto Findbss;
case CMauth:
- memset(wn->rxkey, 0, sizeof(wn->rxkey));
- memset(wn->txkey, 0, sizeof(wn->txkey));
+ freewifikeys(wifi, wn);
if(cb->f[1] == nil)
wn->rsnelen = 0;
else
@@ -947,12 +981,24 @@
break;
case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4:
case CMtxkey0:
+ if(cb->f[1] == nil)
+ error(Ebadarg);
+ k = parsekey(cb->f[1]);
+ if(k == nil)
+ error("bad key");
+ memset(cb->f[1], 0, strlen(cb->f[1]));
+ if(k->cipher == 0){
+ secfree(k);
+ k = nil;
+ }
if(ct->index < CMtxkey0)
- k = &wn->rxkey[ct->index - CMrxkey0];
+ kk = &wn->rxkey[ct->index - CMrxkey0];
else
- k = &wn->txkey[ct->index - CMtxkey0];
- if(cb->f[1] == nil || parsekey(k, cb->f[1]) != 0)
- error("bad key");
+ kk = &wn->txkey[ct->index - CMtxkey0];
+ wlock(&wifi->crypt);
+ secfree(*kk);
+ *kk = k;
+ wunlock(&wifi->crypt);
if(ct->index >= CMtxkey0 && wn->status == Sblocked)
setstatus(wifi, wn, Sassoc);
break;
@@ -968,6 +1014,7 @@
static uchar zeros[Eaddrlen];
char *s, *p, *e;
Wnode *wn;
+ Wkey *k;
long now;
int i;
@@ -982,12 +1029,18 @@
p = seprint(p, e, "channel: %.2d\n", wn->channel);
/* only print key ciphers and key length */
- for(i = 0; i<nelem(wn->rxkey); i++)
- p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
- ciphers[wn->rxkey[i].cipher], wn->rxkey[i].len);
- for(i = 0; i<nelem(wn->txkey); i++)
- p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
- ciphers[wn->txkey[i].cipher], wn->txkey[i].len);
+ rlock(&wifi->crypt);
+ for(i = 0; i<nelem(wn->rxkey); i++){
+ if((k = wn->rxkey[i]) != nil)
+ p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
+ ciphers[k->cipher], k->len);
+ }
+ for(i = 0; i<nelem(wn->txkey); i++){
+ if((k = wn->txkey[i]) != nil)
+ p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
+ ciphers[k->cipher], k->len);
+ }
+ runlock(&wifi->crypt);
if(wn->brsnelen > 0){
p = seprint(p, e, "brsne: ");
@@ -1018,7 +1071,7 @@
static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
static Block*
-wifiencrypt(Wifi *, Wnode *wn, Block *b)
+wifiencrypt(Wifi *wifi, Wnode *wn, Block *b)
{
uvlong tsc;
int n, kid;
@@ -1025,10 +1078,14 @@
Wifipkt *w;
Wkey *k;
+ rlock(&wifi->crypt);
+
kid = 0;
- k = &wn->txkey[kid];
- if(k->cipher == 0)
+ k = wn->txkey[kid];
+ if(k == nil){
+ runlock(&wifi->crypt);
return b;
+ }
n = wifihdrlen((Wifipkt*)b->rp);
@@ -1052,8 +1109,6 @@
b->rp[6] = tsc>>32;
b->rp[7] = tsc>>40;
b->rp += 8;
- if(k->len != 32)
- goto drop;
tkipencrypt(k, w, b, tsc);
break;
case CCMP:
@@ -1066,15 +1121,10 @@
b->rp[6] = tsc>>32;
b->rp[7] = tsc>>40;
b->rp += 8;
- if(k->len != 16)
- goto drop;
ccmpencrypt(k, w, b, tsc);
break;
- default:
- drop:
- free(b);
- return nil;
}
+ runlock(&wifi->crypt);
b->rp = (uchar*)w;
w->fc[1] |= 0x40;
@@ -1082,7 +1132,7 @@
}
static Block*
-wifidecrypt(Wifi *, Wnode *wn, Block *b)
+wifidecrypt(Wifi *wifi, Wnode *wn, Block *b)
{
uvlong tsc;
int n, kid;
@@ -1089,6 +1139,8 @@
Wifipkt *w;
Wkey *k;
+ rlock(&wifi->crypt);
+
w = (Wifipkt*)b->rp;
n = wifihdrlen(w);
b->rp += n;
@@ -1101,7 +1153,9 @@
if((w->a1[0] & 1) == 0)
kid = 4; /* use peerwise key for non-unicast */
- k = &wn->rxkey[kid];
+ k = wn->rxkey[kid];
+ if(k == nil)
+ goto drop;
switch(k->cipher){
case TKIP:
tsc = (uvlong)b->rp[7]<<40 |
@@ -1111,7 +1165,7 @@
(uvlong)b->rp[0]<<8 |
(uvlong)b->rp[2];
b->rp += 8;
- if(tsc <= k->tsc || k->len != 32)
+ if(tsc <= k->tsc)
goto drop;
if(tkipdecrypt(k, w, b, tsc) != 0)
goto drop;
@@ -1124,7 +1178,7 @@
(uvlong)b->rp[1]<<8 |
(uvlong)b->rp[0];
b->rp += 8;
- if(tsc <= k->tsc || k->len != 16)
+ if(tsc <= k->tsc)
goto drop;
if(ccmpdecrypt(k, w, b, tsc) != 0)
goto drop;
@@ -1131,9 +1185,11 @@
break;
default:
drop:
+ runlock(&wifi->crypt);
freeb(b);
return nil;
}
+ runlock(&wifi->crypt);
k->tsc = tsc;
b->rp -= n;
@@ -1564,12 +1620,10 @@
}
static int
-setupCCMP(Wkey *k, Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32], AESstate *as)
+setupCCMP(Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32])
{
uchar *p;
- setupAESstate(as, k->key, k->len, nil);
-
nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4;
memmove(&nonce[1], w->a2, Eaddrlen);
nonce[7] = tsc >> 40;
@@ -1599,11 +1653,10 @@
ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
{
uchar auth[32], nonce[13];
- AESstate as;
aesCCMencrypt(2, 8, nonce, auth,
- setupCCMP(k, w, tsc, nonce, auth, &as),
- b->rp, BLEN(b), &as);
+ setupCCMP(w, tsc, nonce, auth),
+ b->rp, BLEN(b), (AESstate*)k->key);
b->wp += 8;
}
@@ -1611,7 +1664,6 @@
ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
{
uchar auth[32], nonce[13];
- AESstate as;
if(BLEN(b) < 8)
return -1;
@@ -1618,6 +1670,6 @@
b->wp -= 8;
return aesCCMdecrypt(2, 8, nonce, auth,
- setupCCMP(k, w, tsc, nonce, auth, &as),
- b->rp, BLEN(b), &as);
+ setupCCMP(w, tsc, nonce, auth),
+ b->rp, BLEN(b), (AESstate*)k->key);
}