summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-03-09 17:22:59 +0100
committercinap_lenrek <cinap_lenrek@gmx.de>2013-03-09 17:22:59 +0100
commit420efd93d728c937f88beeeb6ff80e4182dfe172 (patch)
tree682d37c7bd10f05ddf7ec769f2cf80ce1eac2849
parentd9dd0970b18098fe881889ff16fcd57f5c97cf80 (diff)
factotum: add wpapsk client authentication
-rw-r--r--sys/src/cmd/auth/factotum/dat.h4
-rw-r--r--sys/src/cmd/auth/factotum/fs.c1
-rw-r--r--sys/src/cmd/auth/factotum/mkfile1
-rw-r--r--sys/src/cmd/auth/factotum/wpapsk.c237
4 files changed, 242 insertions, 1 deletions
diff --git a/sys/src/cmd/auth/factotum/dat.h b/sys/src/cmd/auth/factotum/dat.h
index b36f869e5..2652de85a 100644
--- a/sys/src/cmd/auth/factotum/dat.h
+++ b/sys/src/cmd/auth/factotum/dat.h
@@ -237,4 +237,6 @@ extern Proto rsa; /* rsa.c */
extern Proto wep; /* wep.c */
/* extern Proto srs; /* srs.c */
extern Proto httpdigest; /* httpdigest.c */
-extern Proto ecdsa;
+extern Proto ecdsa; /* ecdsa.c */
+extern Proto wpapsk; /* wpapsk.c */
+
diff --git a/sys/src/cmd/auth/factotum/fs.c b/sys/src/cmd/auth/factotum/fs.c
index d7b992507..3093ef3dc 100644
--- a/sys/src/cmd/auth/factotum/fs.c
+++ b/sys/src/cmd/auth/factotum/fs.c
@@ -41,6 +41,7 @@ prototab[] =
&vnc,
&wep,
&ecdsa,
+ &wpapsk,
nil,
};
diff --git a/sys/src/cmd/auth/factotum/mkfile b/sys/src/cmd/auth/factotum/mkfile
index fe1bb1526..be3421002 100644
--- a/sys/src/cmd/auth/factotum/mkfile
+++ b/sys/src/cmd/auth/factotum/mkfile
@@ -14,6 +14,7 @@ PROTO=\
rsa.$O\
wep.$O\
ecdsa.$O\
+ wpapsk.$O\
FOFILES=\
$PROTO\
diff --git a/sys/src/cmd/auth/factotum/wpapsk.c b/sys/src/cmd/auth/factotum/wpapsk.c
new file mode 100644
index 000000000..785d1c0ff
--- /dev/null
+++ b/sys/src/cmd/auth/factotum/wpapsk.c
@@ -0,0 +1,237 @@
+/*
+ * WPA-PSK
+ *
+ * Client protocol:
+ * write challenge: smac[6] + amac[6] + snonce[32] + anonce[32]
+ * read response: ptk[64]
+ *
+ * Server protocol:
+ * unimplemented
+ */
+#include "dat.h"
+
+enum {
+ PMKlen = 256/8,
+ PTKlen = 512/8,
+
+ Eaddrlen = 6,
+ Noncelen = 32,
+};
+
+enum
+{
+ CNeedChal,
+ CHaveResp,
+ Maxphase,
+};
+
+static char *phasenames[Maxphase] = {
+[CNeedChal] "CNeedChal",
+[CHaveResp] "CHaveResp",
+};
+
+struct State
+{
+ uchar resp[PTKlen];
+};
+
+static void
+pbkdf2(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d, ulong dlen)
+{
+ uchar block[SHA1dlen], tmp[SHA1dlen], tmp2[SHA1dlen];
+ ulong i, j, k, n;
+ DigestState *ds;
+
+ for(i = 1; dlen > 0; i++, d += n, dlen -= n){
+ tmp[3] = i;
+ tmp[2] = i >> 8;
+ tmp[1] = i >> 16;
+ tmp[0] = i >> 24;
+ ds = hmac_sha1(s, slen, p, plen, nil, nil);
+ hmac_sha1(tmp, 4, p, plen, block, ds);
+ memmove(tmp, block, sizeof(tmp));
+ for(j = 1; j < rounds; j++){
+ hmac_sha1(tmp, sizeof(tmp), p, plen, tmp2, nil);
+ memmove(tmp, tmp2, sizeof(tmp));
+ for(k=0; k<sizeof(tmp); k++)
+ block[k] ^= tmp[k];
+ }
+ n = dlen > sizeof(block) ? sizeof(block) : dlen;
+ memmove(d, block, n);
+ }
+}
+
+static 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;
+}
+
+static void
+pass2pmk(char *pass, char *ssid, uchar pmk[PMKlen])
+{
+ if(hextob(pass, nil, pmk, PMKlen) == PMKlen)
+ return;
+ pbkdf2((uchar*)pass, strlen(pass), (uchar*)ssid, strlen(ssid), 4096, pmk, PMKlen);
+}
+
+static void
+prfn(uchar *k, int klen, char *a, uchar *b, int blen, uchar *d, int dlen)
+{
+ uchar r[SHA1dlen], i;
+ DigestState *ds;
+ int n;
+
+ i = 0;
+ while(dlen > 0){
+ ds = hmac_sha1((uchar*)a, strlen(a)+1, k, klen, nil, nil);
+ hmac_sha1(b, blen, k, klen, nil, ds);
+ hmac_sha1(&i, 1, k, klen, r, ds);
+ i++;
+ n = dlen;
+ if(n > sizeof(r))
+ n = sizeof(r);
+ memmove(d, r, n); d += n;
+ dlen -= n;
+ }
+}
+
+static void
+calcptk(uchar pmk[PMKlen], uchar smac[Eaddrlen], uchar amac[Eaddrlen],
+ uchar snonce[Noncelen], uchar anonce[Noncelen],
+ uchar ptk[PTKlen])
+{
+ uchar b[2*Eaddrlen + 2*Noncelen];
+
+ if(memcmp(smac, amac, Eaddrlen) > 0){
+ memmove(b + Eaddrlen*0, amac, Eaddrlen);
+ memmove(b + Eaddrlen*1, smac, Eaddrlen);
+ } else {
+ memmove(b + Eaddrlen*0, smac, Eaddrlen);
+ memmove(b + Eaddrlen*1, amac, Eaddrlen);
+ }
+ if(memcmp(snonce, anonce, Eaddrlen) > 0){
+ memmove(b + Eaddrlen*2 + Noncelen*0, anonce, Noncelen);
+ memmove(b + Eaddrlen*2 + Noncelen*1, snonce, Noncelen);
+ } else {
+ memmove(b + Eaddrlen*2 + Noncelen*0, snonce, Noncelen);
+ memmove(b + Eaddrlen*2 + Noncelen*1, anonce, Noncelen);
+ }
+ prfn(pmk, PMKlen, "Pairwise key expansion", b, sizeof(b), ptk, PTKlen);
+}
+
+static int
+wpapskinit(Proto *p, Fsstate *fss)
+{
+ int iscli;
+ State *s;
+
+ if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
+ return failure(fss, nil);
+ if(!iscli)
+ return failure(fss, "%s server not supported", p->name);
+
+ s = emalloc(sizeof *s);
+ fss->phasename = phasenames;
+ fss->maxphase = Maxphase;
+ fss->phase = CNeedChal;
+ fss->ps = s;
+ return RpcOk;
+}
+
+static int
+wpapskwrite(Fsstate *fss, void *va, uint n)
+{
+ uchar pmk[PMKlen], *smac, *amac, *snonce, *anonce;
+ char *pass, *essid;
+ State *s;
+ int ret;
+ Key *k;
+ Keyinfo ki;
+ Attr *attr;
+
+ s = fss->ps;
+
+ if(fss->phase != CNeedChal)
+ return phaseerror(fss, "write");
+ if(n != (2*Eaddrlen + 2*Noncelen))
+ return phaseerror(fss, "bad write size");
+
+ attr = _delattr(_copyattr(fss->attr), "role");
+ mkkeyinfo(&ki, fss, attr);
+ ret = findkey(&k, &ki, "%s", fss->proto->keyprompt);
+ _freeattr(attr);
+ if(ret != RpcOk)
+ return ret;
+
+ pass = _strfindattr(k->privattr, "!password");
+ if(pass == nil)
+ return failure(fss, "key has no password");
+ essid = _strfindattr(k->attr, "essid");
+ if(essid == nil)
+ return failure(fss, "key has no essid");
+ setattrs(fss->attr, k->attr);
+ closekey(k);
+
+ pass2pmk(pass, essid, pmk);
+
+ smac = va;
+ amac = smac + Eaddrlen;
+ snonce = amac + Eaddrlen;
+ anonce = snonce + Noncelen;
+ calcptk(pmk, smac, amac, snonce, anonce, s->resp);
+
+ fss->phase = CHaveResp;
+ return RpcOk;
+}
+
+static int
+wpapskread(Fsstate *fss, void *va, uint *n)
+{
+ State *s;
+
+ s = fss->ps;
+ if(fss->phase != CHaveResp)
+ return phaseerror(fss, "read");
+ if(*n > sizeof(s->resp))
+ *n = sizeof(s->resp);
+ memmove(va, s->resp, *n);
+ fss->phase = Established;
+ fss->haveai = 0;
+ return RpcOk;
+}
+
+static void
+wpapskclose(Fsstate *fss)
+{
+ State *s;
+ s = fss->ps;
+ free(s);
+}
+
+Proto wpapsk = {
+.name= "wpapsk",
+.init= wpapskinit,
+.write= wpapskwrite,
+.read= wpapskread,
+.close= wpapskclose,
+.addkey= replacekey,
+.keyprompt= "!password? essid?"
+};