Blame


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