Blame


1 6e527fbc 2005-02-13 devnull /*
2 6e527fbc 2005-02-13 devnull * APOP, CRAM - MD5 challenge/response authentication
3 6e527fbc 2005-02-13 devnull *
4 6e527fbc 2005-02-13 devnull * The client does not authenticate the server, hence no CAI.
5 6e527fbc 2005-02-13 devnull *
6 6e527fbc 2005-02-13 devnull * Protocol:
7 6e527fbc 2005-02-13 devnull *
8 6e527fbc 2005-02-13 devnull * S -> C: random@domain
9 1757e76a 2005-02-13 devnull * C -> S: user hex-response
10 6e527fbc 2005-02-13 devnull * S -> C: ok
11 6e527fbc 2005-02-13 devnull *
12 6e527fbc 2005-02-13 devnull * Note that this is the protocol between factotum and the local
13 6e527fbc 2005-02-13 devnull * program, not between the two factotums. The information
14 6e527fbc 2005-02-13 devnull * exchanged here is wrapped in the APOP protocol by the local
15 6e527fbc 2005-02-13 devnull * programs.
16 6e527fbc 2005-02-13 devnull *
17 6e527fbc 2005-02-13 devnull * If S sends "bad [msg]" instead of "ok", that is a hint that the key is bad.
18 1757e76a 2005-02-13 devnull * The protocol goes back to "C -> S: user hex-response".
19 6e527fbc 2005-02-13 devnull */
20 6e527fbc 2005-02-13 devnull
21 6e527fbc 2005-02-13 devnull #include "std.h"
22 6e527fbc 2005-02-13 devnull #include "dat.h"
23 6e527fbc 2005-02-13 devnull
24 6e527fbc 2005-02-13 devnull extern Proto apop, cram;
25 6e527fbc 2005-02-13 devnull
26 6e527fbc 2005-02-13 devnull static int
27 6e527fbc 2005-02-13 devnull apopcheck(Key *k)
28 6e527fbc 2005-02-13 devnull {
29 6e527fbc 2005-02-13 devnull if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
30 6e527fbc 2005-02-13 devnull werrstr("need user and !password attributes");
31 6e527fbc 2005-02-13 devnull return -1;
32 6e527fbc 2005-02-13 devnull }
33 6e527fbc 2005-02-13 devnull return 0;
34 6e527fbc 2005-02-13 devnull }
35 6e527fbc 2005-02-13 devnull
36 6e527fbc 2005-02-13 devnull static int
37 6e527fbc 2005-02-13 devnull apopclient(Conv *c)
38 6e527fbc 2005-02-13 devnull {
39 6e527fbc 2005-02-13 devnull char *chal, *pw, *res;
40 6e527fbc 2005-02-13 devnull int astype, nchal, npw, ntry, ret;
41 6e527fbc 2005-02-13 devnull uchar resp[MD5dlen];
42 6e527fbc 2005-02-13 devnull Attr *attr;
43 6e527fbc 2005-02-13 devnull DigestState *ds;
44 6e527fbc 2005-02-13 devnull Key *k;
45 6e527fbc 2005-02-13 devnull
46 6e527fbc 2005-02-13 devnull chal = nil;
47 6e527fbc 2005-02-13 devnull k = nil;
48 6e527fbc 2005-02-13 devnull res = nil;
49 6e527fbc 2005-02-13 devnull ret = -1;
50 6e527fbc 2005-02-13 devnull attr = c->attr;
51 6e527fbc 2005-02-13 devnull
52 6e527fbc 2005-02-13 devnull if(c->proto == &apop)
53 6e527fbc 2005-02-13 devnull astype = AuthApop;
54 6e527fbc 2005-02-13 devnull else if(c->proto == &cram)
55 6e527fbc 2005-02-13 devnull astype = AuthCram;
56 6e527fbc 2005-02-13 devnull else{
57 6e527fbc 2005-02-13 devnull werrstr("bad proto");
58 6e527fbc 2005-02-13 devnull goto out;
59 6e527fbc 2005-02-13 devnull }
60 6e527fbc 2005-02-13 devnull
61 6e527fbc 2005-02-13 devnull c->state = "find key";
62 6e527fbc 2005-02-13 devnull k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
63 6e527fbc 2005-02-13 devnull if(k == nil)
64 6e527fbc 2005-02-13 devnull goto out;
65 6e527fbc 2005-02-13 devnull
66 6e527fbc 2005-02-13 devnull c->state = "read challenge";
67 6e527fbc 2005-02-13 devnull if((nchal = convreadm(c, &chal)) < 0)
68 6e527fbc 2005-02-13 devnull goto out;
69 6e527fbc 2005-02-13 devnull
70 6e527fbc 2005-02-13 devnull for(ntry=1;; ntry++){
71 6e527fbc 2005-02-13 devnull if(c->attr != attr)
72 6e527fbc 2005-02-13 devnull freeattr(c->attr);
73 6e527fbc 2005-02-13 devnull c->attr = addattrs(copyattr(attr), k->attr);
74 6e527fbc 2005-02-13 devnull if((pw = strfindattr(k->privattr, "!password")) == nil){
75 6e527fbc 2005-02-13 devnull werrstr("key has no password (cannot happen?)");
76 6e527fbc 2005-02-13 devnull goto out;
77 6e527fbc 2005-02-13 devnull }
78 6e527fbc 2005-02-13 devnull npw = strlen(pw);
79 6e527fbc 2005-02-13 devnull
80 6e527fbc 2005-02-13 devnull switch(astype){
81 6e527fbc 2005-02-13 devnull case AuthApop:
82 6e527fbc 2005-02-13 devnull ds = md5((uchar*)chal, nchal, nil, nil);
83 6e527fbc 2005-02-13 devnull md5((uchar*)pw, npw, resp, ds);
84 6e527fbc 2005-02-13 devnull break;
85 6e527fbc 2005-02-13 devnull case AuthCram:
86 6e527fbc 2005-02-13 devnull hmac_md5((uchar*)chal, nchal, (uchar*)pw, npw, resp, nil);
87 6e527fbc 2005-02-13 devnull break;
88 6e527fbc 2005-02-13 devnull }
89 6e527fbc 2005-02-13 devnull
90 6e527fbc 2005-02-13 devnull /* C->S: APOP user hex-response\n */
91 6e527fbc 2005-02-13 devnull if(ntry == 1)
92 6e527fbc 2005-02-13 devnull c->state = "write user";
93 6e527fbc 2005-02-13 devnull else{
94 6e527fbc 2005-02-13 devnull sprint(c->statebuf, "write user (auth attempt #%d)", ntry);
95 6e527fbc 2005-02-13 devnull c->state = c->statebuf;
96 6e527fbc 2005-02-13 devnull }
97 6e527fbc 2005-02-13 devnull if(convprint(c, "%s", strfindattr(k->attr, "user")) < 0)
98 6e527fbc 2005-02-13 devnull goto out;
99 6e527fbc 2005-02-13 devnull
100 6e527fbc 2005-02-13 devnull c->state = "write response";
101 6e527fbc 2005-02-13 devnull if(convprint(c, "%.*H", sizeof resp, resp) < 0)
102 6e527fbc 2005-02-13 devnull goto out;
103 6e527fbc 2005-02-13 devnull
104 6e527fbc 2005-02-13 devnull c->state = "read result";
105 6e527fbc 2005-02-13 devnull if(convreadm(c, &res) < 0)
106 6e527fbc 2005-02-13 devnull goto out;
107 6e527fbc 2005-02-13 devnull
108 6e527fbc 2005-02-13 devnull if(strcmp(res, "ok") == 0)
109 6e527fbc 2005-02-13 devnull break;
110 6e527fbc 2005-02-13 devnull
111 6e527fbc 2005-02-13 devnull if(strncmp(res, "bad ", 4) != 0){
112 6e527fbc 2005-02-13 devnull werrstr("bad result: %s", res);
113 6e527fbc 2005-02-13 devnull goto out;
114 6e527fbc 2005-02-13 devnull }
115 6e527fbc 2005-02-13 devnull
116 6e527fbc 2005-02-13 devnull c->state = "replace key";
117 6e527fbc 2005-02-13 devnull if((k = keyreplace(c, k, "%s", res+4)) == nil){
118 6e527fbc 2005-02-13 devnull c->state = "auth failed";
119 6e527fbc 2005-02-13 devnull werrstr("%s", res+4);
120 6e527fbc 2005-02-13 devnull goto out;
121 6e527fbc 2005-02-13 devnull }
122 6e527fbc 2005-02-13 devnull free(res);
123 6e527fbc 2005-02-13 devnull res = nil;
124 6e527fbc 2005-02-13 devnull }
125 6e527fbc 2005-02-13 devnull
126 6e527fbc 2005-02-13 devnull werrstr("succeeded");
127 6e527fbc 2005-02-13 devnull ret = 0;
128 6e527fbc 2005-02-13 devnull
129 6e527fbc 2005-02-13 devnull out:
130 6e527fbc 2005-02-13 devnull keyclose(k);
131 6e527fbc 2005-02-13 devnull free(chal);
132 6e527fbc 2005-02-13 devnull if(c->attr != attr)
133 6e527fbc 2005-02-13 devnull freeattr(attr);
134 6e527fbc 2005-02-13 devnull return ret;
135 6e527fbc 2005-02-13 devnull }
136 6e527fbc 2005-02-13 devnull
137 6e527fbc 2005-02-13 devnull /* shared with auth dialing routines */
138 6e527fbc 2005-02-13 devnull typedef struct ServerState ServerState;
139 6e527fbc 2005-02-13 devnull struct ServerState
140 6e527fbc 2005-02-13 devnull {
141 6e527fbc 2005-02-13 devnull int asfd;
142 6e527fbc 2005-02-13 devnull Key *k;
143 6e527fbc 2005-02-13 devnull Ticketreq tr;
144 6e527fbc 2005-02-13 devnull Ticket t;
145 6e527fbc 2005-02-13 devnull char *dom;
146 6e527fbc 2005-02-13 devnull char *hostid;
147 6e527fbc 2005-02-13 devnull };
148 6e527fbc 2005-02-13 devnull
149 6e527fbc 2005-02-13 devnull enum
150 6e527fbc 2005-02-13 devnull {
151 6e527fbc 2005-02-13 devnull APOPCHALLEN = 128,
152 6e527fbc 2005-02-13 devnull };
153 6e527fbc 2005-02-13 devnull
154 6e527fbc 2005-02-13 devnull static int apopchal(ServerState*, int, char[APOPCHALLEN]);
155 6e527fbc 2005-02-13 devnull static int apopresp(ServerState*, char*, char*);
156 6e527fbc 2005-02-13 devnull
157 6e527fbc 2005-02-13 devnull static int
158 6e527fbc 2005-02-13 devnull apopserver(Conv *c)
159 6e527fbc 2005-02-13 devnull {
160 6e527fbc 2005-02-13 devnull char chal[APOPCHALLEN], *user, *resp;
161 6e527fbc 2005-02-13 devnull ServerState s;
162 6e527fbc 2005-02-13 devnull int astype, ret;
163 6e527fbc 2005-02-13 devnull Attr *a;
164 6e527fbc 2005-02-13 devnull
165 6e527fbc 2005-02-13 devnull ret = -1;
166 6e527fbc 2005-02-13 devnull user = nil;
167 6e527fbc 2005-02-13 devnull resp = nil;
168 6e527fbc 2005-02-13 devnull memset(&s, 0, sizeof s);
169 6e527fbc 2005-02-13 devnull s.asfd = -1;
170 6e527fbc 2005-02-13 devnull
171 6e527fbc 2005-02-13 devnull if(c->proto == &apop)
172 6e527fbc 2005-02-13 devnull astype = AuthApop;
173 6e527fbc 2005-02-13 devnull else if(c->proto == &cram)
174 6e527fbc 2005-02-13 devnull astype = AuthCram;
175 6e527fbc 2005-02-13 devnull else{
176 6e527fbc 2005-02-13 devnull werrstr("bad proto");
177 6e527fbc 2005-02-13 devnull goto out;
178 6e527fbc 2005-02-13 devnull }
179 6e527fbc 2005-02-13 devnull
180 6e527fbc 2005-02-13 devnull c->state = "find key";
181 6e527fbc 2005-02-13 devnull if((s.k = plan9authkey(c->attr)) == nil)
182 6e527fbc 2005-02-13 devnull goto out;
183 6e527fbc 2005-02-13 devnull
184 6e527fbc 2005-02-13 devnull a = copyattr(s.k->attr);
185 6e527fbc 2005-02-13 devnull a = delattr(a, "proto");
186 6e527fbc 2005-02-13 devnull c->attr = addattrs(c->attr, a);
187 6e527fbc 2005-02-13 devnull freeattr(a);
188 6e527fbc 2005-02-13 devnull
189 6e527fbc 2005-02-13 devnull c->state = "authdial";
190 6e527fbc 2005-02-13 devnull s.hostid = strfindattr(s.k->attr, "user");
191 6e527fbc 2005-02-13 devnull s.dom = strfindattr(s.k->attr, "dom");
192 6e527fbc 2005-02-13 devnull if((s.asfd = xioauthdial(nil, s.dom)) < 0){
193 6e527fbc 2005-02-13 devnull werrstr("authdial %s: %r", s.dom);
194 6e527fbc 2005-02-13 devnull goto out;
195 6e527fbc 2005-02-13 devnull }
196 6e527fbc 2005-02-13 devnull
197 6e527fbc 2005-02-13 devnull c->state = "authchal";
198 6e527fbc 2005-02-13 devnull if(apopchal(&s, astype, chal) < 0)
199 6e527fbc 2005-02-13 devnull goto out;
200 6e527fbc 2005-02-13 devnull
201 6e527fbc 2005-02-13 devnull c->state = "write challenge";
202 6e527fbc 2005-02-13 devnull if(convprint(c, "%s", chal) < 0)
203 6e527fbc 2005-02-13 devnull goto out;
204 6e527fbc 2005-02-13 devnull
205 6e527fbc 2005-02-13 devnull for(;;){
206 6e527fbc 2005-02-13 devnull c->state = "read user";
207 6e527fbc 2005-02-13 devnull if(convreadm(c, &user) < 0)
208 6e527fbc 2005-02-13 devnull goto out;
209 6e527fbc 2005-02-13 devnull
210 6e527fbc 2005-02-13 devnull c->state = "read response";
211 6e527fbc 2005-02-13 devnull if(convreadm(c, &resp) < 0)
212 6e527fbc 2005-02-13 devnull goto out;
213 6e527fbc 2005-02-13 devnull
214 6e527fbc 2005-02-13 devnull c->state = "authwrite";
215 6e527fbc 2005-02-13 devnull switch(apopresp(&s, user, resp)){
216 6e527fbc 2005-02-13 devnull case -1:
217 6e527fbc 2005-02-13 devnull goto out;
218 6e527fbc 2005-02-13 devnull case 0:
219 6e527fbc 2005-02-13 devnull c->state = "write status";
220 6e527fbc 2005-02-13 devnull if(convprint(c, "bad authentication failed") < 0)
221 6e527fbc 2005-02-13 devnull goto out;
222 6e527fbc 2005-02-13 devnull break;
223 6e527fbc 2005-02-13 devnull case 1:
224 6e527fbc 2005-02-13 devnull c->state = "write status";
225 6e527fbc 2005-02-13 devnull if(convprint(c, "ok") < 0)
226 6e527fbc 2005-02-13 devnull goto out;
227 6e527fbc 2005-02-13 devnull goto ok;
228 6e527fbc 2005-02-13 devnull }
229 6e527fbc 2005-02-13 devnull free(user);
230 6e527fbc 2005-02-13 devnull free(resp);
231 6e527fbc 2005-02-13 devnull user = nil;
232 6e527fbc 2005-02-13 devnull resp = nil;
233 6e527fbc 2005-02-13 devnull }
234 6e527fbc 2005-02-13 devnull
235 6e527fbc 2005-02-13 devnull ok:
236 6e527fbc 2005-02-13 devnull ret = 0;
237 6e527fbc 2005-02-13 devnull c->attr = addcap(c->attr, c->sysuser, &s.t);
238 6e527fbc 2005-02-13 devnull
239 6e527fbc 2005-02-13 devnull out:
240 6e527fbc 2005-02-13 devnull keyclose(s.k);
241 6e527fbc 2005-02-13 devnull free(user);
242 6e527fbc 2005-02-13 devnull free(resp);
243 1757e76a 2005-02-13 devnull xioclose(s.asfd);
244 6e527fbc 2005-02-13 devnull return ret;
245 6e527fbc 2005-02-13 devnull }
246 6e527fbc 2005-02-13 devnull
247 6e527fbc 2005-02-13 devnull static int
248 6e527fbc 2005-02-13 devnull apopchal(ServerState *s, int astype, char chal[APOPCHALLEN])
249 6e527fbc 2005-02-13 devnull {
250 6e527fbc 2005-02-13 devnull char trbuf[TICKREQLEN];
251 6e527fbc 2005-02-13 devnull Ticketreq tr;
252 6e527fbc 2005-02-13 devnull
253 6e527fbc 2005-02-13 devnull memset(&tr, 0, sizeof tr);
254 6e527fbc 2005-02-13 devnull
255 6e527fbc 2005-02-13 devnull tr.type = astype;
256 6e527fbc 2005-02-13 devnull
257 6e527fbc 2005-02-13 devnull if(strlen(s->hostid) >= sizeof tr.hostid){
258 6e527fbc 2005-02-13 devnull werrstr("hostid too long");
259 6e527fbc 2005-02-13 devnull return -1;
260 6e527fbc 2005-02-13 devnull }
261 6e527fbc 2005-02-13 devnull strcpy(tr.hostid, s->hostid);
262 6e527fbc 2005-02-13 devnull
263 6e527fbc 2005-02-13 devnull if(strlen(s->dom) >= sizeof tr.authdom){
264 6e527fbc 2005-02-13 devnull werrstr("domain too long");
265 6e527fbc 2005-02-13 devnull return -1;
266 6e527fbc 2005-02-13 devnull }
267 6e527fbc 2005-02-13 devnull strcpy(tr.authdom, s->dom);
268 6e527fbc 2005-02-13 devnull
269 6e527fbc 2005-02-13 devnull convTR2M(&tr, trbuf);
270 6e527fbc 2005-02-13 devnull if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
271 6e527fbc 2005-02-13 devnull return -1;
272 6e527fbc 2005-02-13 devnull
273 6e527fbc 2005-02-13 devnull if(xioasrdresp(s->asfd, chal, APOPCHALLEN) <= 5)
274 6e527fbc 2005-02-13 devnull return -1;
275 6e527fbc 2005-02-13 devnull
276 6e527fbc 2005-02-13 devnull s->tr = tr;
277 6e527fbc 2005-02-13 devnull return 0;
278 6e527fbc 2005-02-13 devnull }
279 6e527fbc 2005-02-13 devnull
280 6e527fbc 2005-02-13 devnull static int
281 6e527fbc 2005-02-13 devnull apopresp(ServerState *s, char *user, char *resp)
282 6e527fbc 2005-02-13 devnull {
283 6e527fbc 2005-02-13 devnull char tabuf[TICKETLEN+AUTHENTLEN];
284 6e527fbc 2005-02-13 devnull char trbuf[TICKREQLEN];
285 6e527fbc 2005-02-13 devnull int len;
286 6e527fbc 2005-02-13 devnull Authenticator a;
287 6e527fbc 2005-02-13 devnull Ticket t;
288 6e527fbc 2005-02-13 devnull Ticketreq tr;
289 6e527fbc 2005-02-13 devnull
290 6e527fbc 2005-02-13 devnull tr = s->tr;
291 6e527fbc 2005-02-13 devnull if(memrandom(tr.chal, CHALLEN) < 0)
292 6e527fbc 2005-02-13 devnull return -1;
293 6e527fbc 2005-02-13 devnull
294 6e527fbc 2005-02-13 devnull if(strlen(user) >= sizeof tr.uid){
295 6e527fbc 2005-02-13 devnull werrstr("uid too long");
296 6e527fbc 2005-02-13 devnull return -1;
297 6e527fbc 2005-02-13 devnull }
298 6e527fbc 2005-02-13 devnull strcpy(tr.uid, user);
299 6e527fbc 2005-02-13 devnull
300 6e527fbc 2005-02-13 devnull convTR2M(&tr, trbuf);
301 6e527fbc 2005-02-13 devnull if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
302 6e527fbc 2005-02-13 devnull return -1;
303 6e527fbc 2005-02-13 devnull
304 6e527fbc 2005-02-13 devnull len = strlen(resp);
305 6e527fbc 2005-02-13 devnull if(xiowrite(s->asfd, resp, len) != len)
306 6e527fbc 2005-02-13 devnull return -1;
307 6e527fbc 2005-02-13 devnull
308 6e527fbc 2005-02-13 devnull if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
309 6e527fbc 2005-02-13 devnull return 0;
310 6e527fbc 2005-02-13 devnull
311 6e527fbc 2005-02-13 devnull convM2T(tabuf, &t, s->k->priv);
312 6e527fbc 2005-02-13 devnull if(t.num != AuthTs
313 6e527fbc 2005-02-13 devnull || memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
314 6e527fbc 2005-02-13 devnull werrstr("key mismatch with auth server");
315 6e527fbc 2005-02-13 devnull return -1;
316 6e527fbc 2005-02-13 devnull }
317 6e527fbc 2005-02-13 devnull
318 6e527fbc 2005-02-13 devnull convM2A(tabuf+TICKETLEN, &a, t.key);
319 6e527fbc 2005-02-13 devnull if(a.num != AuthAc
320 6e527fbc 2005-02-13 devnull || memcmp(a.chal, tr.chal, sizeof a.chal) != 0
321 6e527fbc 2005-02-13 devnull || a.id != 0){
322 6e527fbc 2005-02-13 devnull werrstr("key2 mismatch with auth server");
323 6e527fbc 2005-02-13 devnull return -1;
324 6e527fbc 2005-02-13 devnull }
325 6e527fbc 2005-02-13 devnull
326 6e527fbc 2005-02-13 devnull s->t = t;
327 6e527fbc 2005-02-13 devnull return 1;
328 6e527fbc 2005-02-13 devnull }
329 6e527fbc 2005-02-13 devnull
330 6e527fbc 2005-02-13 devnull static Role
331 6e527fbc 2005-02-13 devnull apoproles[] =
332 6e527fbc 2005-02-13 devnull {
333 6e527fbc 2005-02-13 devnull "client", apopclient,
334 6e527fbc 2005-02-13 devnull "server", apopserver,
335 6e527fbc 2005-02-13 devnull 0
336 6e527fbc 2005-02-13 devnull };
337 6e527fbc 2005-02-13 devnull
338 6e527fbc 2005-02-13 devnull Proto apop = {
339 1757e76a 2005-02-13 devnull "apop",
340 1757e76a 2005-02-13 devnull apoproles,
341 1757e76a 2005-02-13 devnull "user? !password?",
342 1757e76a 2005-02-13 devnull apopcheck,
343 1757e76a 2005-02-13 devnull nil
344 6e527fbc 2005-02-13 devnull };
345 6e527fbc 2005-02-13 devnull
346 6e527fbc 2005-02-13 devnull Proto cram = {
347 1757e76a 2005-02-13 devnull "cram",
348 1757e76a 2005-02-13 devnull apoproles,
349 1757e76a 2005-02-13 devnull "user? !password?",
350 1757e76a 2005-02-13 devnull apopcheck,
351 1757e76a 2005-02-13 devnull nil
352 6e527fbc 2005-02-13 devnull };
353 1757e76a 2005-02-13 devnull