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