1*13e26254SDavid du Colombier /*
2*13e26254SDavid du Colombier * WPA-PSK
3*13e26254SDavid du Colombier *
4*13e26254SDavid du Colombier * Client protocol:
5*13e26254SDavid du Colombier * write challenge: smac[6] + amac[6] + snonce[32] + anonce[32]
6*13e26254SDavid du Colombier * read response: ptk[64]
7*13e26254SDavid du Colombier *
8*13e26254SDavid du Colombier * Server protocol:
9*13e26254SDavid du Colombier * unimplemented
10*13e26254SDavid du Colombier */
11*13e26254SDavid du Colombier #include "dat.h"
12*13e26254SDavid du Colombier
13*13e26254SDavid du Colombier enum {
14*13e26254SDavid du Colombier PMKlen = 256/8,
15*13e26254SDavid du Colombier PTKlen = 512/8,
16*13e26254SDavid du Colombier
17*13e26254SDavid du Colombier Eaddrlen = 6,
18*13e26254SDavid du Colombier Noncelen = 32,
19*13e26254SDavid du Colombier };
20*13e26254SDavid du Colombier
21*13e26254SDavid du Colombier enum
22*13e26254SDavid du Colombier {
23*13e26254SDavid du Colombier CNeedChal,
24*13e26254SDavid du Colombier CHaveResp,
25*13e26254SDavid du Colombier Maxphase,
26*13e26254SDavid du Colombier };
27*13e26254SDavid du Colombier
28*13e26254SDavid du Colombier static char *phasenames[Maxphase] = {
29*13e26254SDavid du Colombier [CNeedChal] "CNeedChal",
30*13e26254SDavid du Colombier [CHaveResp] "CHaveResp",
31*13e26254SDavid du Colombier };
32*13e26254SDavid du Colombier
33*13e26254SDavid du Colombier struct State
34*13e26254SDavid du Colombier {
35*13e26254SDavid du Colombier uchar resp[PTKlen];
36*13e26254SDavid du Colombier };
37*13e26254SDavid du Colombier
38*13e26254SDavid du Colombier static void
pass2pmk(char * pass,char * ssid,uchar pmk[PMKlen])39*13e26254SDavid du Colombier pass2pmk(char *pass, char *ssid, uchar pmk[PMKlen])
40*13e26254SDavid du Colombier {
41*13e26254SDavid du Colombier int npass = strlen(pass);
42*13e26254SDavid du Colombier if(npass == 2*PMKlen && dec16(pmk, PMKlen, pass, npass) == PMKlen)
43*13e26254SDavid du Colombier return;
44*13e26254SDavid du Colombier pbkdf2_x((uchar*)pass, npass, (uchar*)ssid, strlen(ssid), 4096, pmk, PMKlen, hmac_sha1, SHA1dlen);
45*13e26254SDavid du Colombier }
46*13e26254SDavid du Colombier
47*13e26254SDavid du Colombier static void
prfn(uchar * k,int klen,char * a,uchar * b,int blen,uchar * d,int dlen)48*13e26254SDavid du Colombier prfn(uchar *k, int klen, char *a, uchar *b, int blen, uchar *d, int dlen)
49*13e26254SDavid du Colombier {
50*13e26254SDavid du Colombier uchar r[SHA1dlen], i;
51*13e26254SDavid du Colombier DigestState *ds;
52*13e26254SDavid du Colombier int n;
53*13e26254SDavid du Colombier
54*13e26254SDavid du Colombier i = 0;
55*13e26254SDavid du Colombier while(dlen > 0){
56*13e26254SDavid du Colombier ds = hmac_sha1((uchar*)a, strlen(a)+1, k, klen, nil, nil);
57*13e26254SDavid du Colombier hmac_sha1(b, blen, k, klen, nil, ds);
58*13e26254SDavid du Colombier hmac_sha1(&i, 1, k, klen, r, ds);
59*13e26254SDavid du Colombier i++;
60*13e26254SDavid du Colombier n = dlen;
61*13e26254SDavid du Colombier if(n > sizeof(r))
62*13e26254SDavid du Colombier n = sizeof(r);
63*13e26254SDavid du Colombier memmove(d, r, n); d += n;
64*13e26254SDavid du Colombier dlen -= n;
65*13e26254SDavid du Colombier }
66*13e26254SDavid du Colombier }
67*13e26254SDavid du Colombier
68*13e26254SDavid du Colombier static void
calcptk(uchar pmk[PMKlen],uchar smac[Eaddrlen],uchar amac[Eaddrlen],uchar snonce[Noncelen],uchar anonce[Noncelen],uchar ptk[PTKlen])69*13e26254SDavid du Colombier calcptk(uchar pmk[PMKlen], uchar smac[Eaddrlen], uchar amac[Eaddrlen],
70*13e26254SDavid du Colombier uchar snonce[Noncelen], uchar anonce[Noncelen],
71*13e26254SDavid du Colombier uchar ptk[PTKlen])
72*13e26254SDavid du Colombier {
73*13e26254SDavid du Colombier uchar b[2*Eaddrlen + 2*Noncelen];
74*13e26254SDavid du Colombier
75*13e26254SDavid du Colombier if(memcmp(smac, amac, Eaddrlen) > 0){
76*13e26254SDavid du Colombier memmove(b + Eaddrlen*0, amac, Eaddrlen);
77*13e26254SDavid du Colombier memmove(b + Eaddrlen*1, smac, Eaddrlen);
78*13e26254SDavid du Colombier } else {
79*13e26254SDavid du Colombier memmove(b + Eaddrlen*0, smac, Eaddrlen);
80*13e26254SDavid du Colombier memmove(b + Eaddrlen*1, amac, Eaddrlen);
81*13e26254SDavid du Colombier }
82*13e26254SDavid du Colombier if(memcmp(snonce, anonce, Eaddrlen) > 0){
83*13e26254SDavid du Colombier memmove(b + Eaddrlen*2 + Noncelen*0, anonce, Noncelen);
84*13e26254SDavid du Colombier memmove(b + Eaddrlen*2 + Noncelen*1, snonce, Noncelen);
85*13e26254SDavid du Colombier } else {
86*13e26254SDavid du Colombier memmove(b + Eaddrlen*2 + Noncelen*0, snonce, Noncelen);
87*13e26254SDavid du Colombier memmove(b + Eaddrlen*2 + Noncelen*1, anonce, Noncelen);
88*13e26254SDavid du Colombier }
89*13e26254SDavid du Colombier prfn(pmk, PMKlen, "Pairwise key expansion", b, sizeof(b), ptk, PTKlen);
90*13e26254SDavid du Colombier }
91*13e26254SDavid du Colombier
92*13e26254SDavid du Colombier static int
wpapskinit(Proto * p,Fsstate * fss)93*13e26254SDavid du Colombier wpapskinit(Proto *p, Fsstate *fss)
94*13e26254SDavid du Colombier {
95*13e26254SDavid du Colombier int iscli;
96*13e26254SDavid du Colombier State *s;
97*13e26254SDavid du Colombier
98*13e26254SDavid du Colombier if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
99*13e26254SDavid du Colombier return failure(fss, nil);
100*13e26254SDavid du Colombier if(!iscli)
101*13e26254SDavid du Colombier return failure(fss, "%s server not supported", p->name);
102*13e26254SDavid du Colombier
103*13e26254SDavid du Colombier s = emalloc(sizeof *s);
104*13e26254SDavid du Colombier fss->phasename = phasenames;
105*13e26254SDavid du Colombier fss->maxphase = Maxphase;
106*13e26254SDavid du Colombier fss->phase = CNeedChal;
107*13e26254SDavid du Colombier fss->ps = s;
108*13e26254SDavid du Colombier return RpcOk;
109*13e26254SDavid du Colombier }
110*13e26254SDavid du Colombier
111*13e26254SDavid du Colombier static int
wpapskwrite(Fsstate * fss,void * va,uint n)112*13e26254SDavid du Colombier wpapskwrite(Fsstate *fss, void *va, uint n)
113*13e26254SDavid du Colombier {
114*13e26254SDavid du Colombier uchar pmk[PMKlen], *smac, *amac, *snonce, *anonce;
115*13e26254SDavid du Colombier char *pass, *essid;
116*13e26254SDavid du Colombier State *s;
117*13e26254SDavid du Colombier int ret;
118*13e26254SDavid du Colombier Key *k;
119*13e26254SDavid du Colombier Keyinfo ki;
120*13e26254SDavid du Colombier Attr *attr;
121*13e26254SDavid du Colombier
122*13e26254SDavid du Colombier s = fss->ps;
123*13e26254SDavid du Colombier
124*13e26254SDavid du Colombier if(fss->phase != CNeedChal)
125*13e26254SDavid du Colombier return phaseerror(fss, "write");
126*13e26254SDavid du Colombier if(n != (2*Eaddrlen + 2*Noncelen))
127*13e26254SDavid du Colombier return phaseerror(fss, "bad write size");
128*13e26254SDavid du Colombier
129*13e26254SDavid du Colombier attr = _delattr(_copyattr(fss->attr), "role");
130*13e26254SDavid du Colombier mkkeyinfo(&ki, fss, attr);
131*13e26254SDavid du Colombier ret = findkey(&k, &ki, "%s", fss->proto->keyprompt);
132*13e26254SDavid du Colombier _freeattr(attr);
133*13e26254SDavid du Colombier if(ret != RpcOk)
134*13e26254SDavid du Colombier return ret;
135*13e26254SDavid du Colombier
136*13e26254SDavid du Colombier pass = _strfindattr(k->privattr, "!password");
137*13e26254SDavid du Colombier if(pass == nil)
138*13e26254SDavid du Colombier return failure(fss, "key has no password");
139*13e26254SDavid du Colombier essid = _strfindattr(k->attr, "essid");
140*13e26254SDavid du Colombier if(essid == nil)
141*13e26254SDavid du Colombier return failure(fss, "key has no essid");
142*13e26254SDavid du Colombier setattrs(fss->attr, k->attr);
143*13e26254SDavid du Colombier closekey(k);
144*13e26254SDavid du Colombier
145*13e26254SDavid du Colombier pass2pmk(pass, essid, pmk);
146*13e26254SDavid du Colombier
147*13e26254SDavid du Colombier smac = va;
148*13e26254SDavid du Colombier amac = smac + Eaddrlen;
149*13e26254SDavid du Colombier snonce = amac + Eaddrlen;
150*13e26254SDavid du Colombier anonce = snonce + Noncelen;
151*13e26254SDavid du Colombier calcptk(pmk, smac, amac, snonce, anonce, s->resp);
152*13e26254SDavid du Colombier
153*13e26254SDavid du Colombier fss->phase = CHaveResp;
154*13e26254SDavid du Colombier return RpcOk;
155*13e26254SDavid du Colombier }
156*13e26254SDavid du Colombier
157*13e26254SDavid du Colombier static int
wpapskread(Fsstate * fss,void * va,uint * n)158*13e26254SDavid du Colombier wpapskread(Fsstate *fss, void *va, uint *n)
159*13e26254SDavid du Colombier {
160*13e26254SDavid du Colombier State *s;
161*13e26254SDavid du Colombier
162*13e26254SDavid du Colombier s = fss->ps;
163*13e26254SDavid du Colombier if(fss->phase != CHaveResp)
164*13e26254SDavid du Colombier return phaseerror(fss, "read");
165*13e26254SDavid du Colombier if(*n > sizeof(s->resp))
166*13e26254SDavid du Colombier *n = sizeof(s->resp);
167*13e26254SDavid du Colombier memmove(va, s->resp, *n);
168*13e26254SDavid du Colombier fss->phase = Established;
169*13e26254SDavid du Colombier fss->haveai = 0;
170*13e26254SDavid du Colombier return RpcOk;
171*13e26254SDavid du Colombier }
172*13e26254SDavid du Colombier
173*13e26254SDavid du Colombier static void
wpapskclose(Fsstate * fss)174*13e26254SDavid du Colombier wpapskclose(Fsstate *fss)
175*13e26254SDavid du Colombier {
176*13e26254SDavid du Colombier State *s;
177*13e26254SDavid du Colombier s = fss->ps;
178*13e26254SDavid du Colombier free(s);
179*13e26254SDavid du Colombier }
180*13e26254SDavid du Colombier
181*13e26254SDavid du Colombier Proto wpapsk = {
182*13e26254SDavid du Colombier .name= "wpapsk",
183*13e26254SDavid du Colombier .init= wpapskinit,
184*13e26254SDavid du Colombier .write= wpapskwrite,
185*13e26254SDavid du Colombier .read= wpapskread,
186*13e26254SDavid du Colombier .close= wpapskclose,
187*13e26254SDavid du Colombier .addkey= replacekey,
188*13e26254SDavid du Colombier .keyprompt= "!password? essid?"
189*13e26254SDavid du Colombier };
190