shithub: riscv

Download patch

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);
 }