1 /*
2 * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
3 * Nigel Roles (nigel@9fs.org) 2003
4 */
5
6 #include <plan9.h>
7 #include <fcall.h>
8 #include <u9fs.h>
9 #include <stdlib.h> /* for random stuff */
10
11 typedef struct Ticket Ticket;
12 typedef struct Ticketreq Ticketreq;
13 typedef struct Authenticator Authenticator;
14
15 enum
16 {
17 DOMLEN= 48, /* length of an authentication domain name */
18 CHALLEN= 8 /* length of a challenge */
19 };
20
21 enum {
22 HaveProtos,
23 NeedProto,
24 NeedChal,
25 HaveTreq,
26 NeedTicket,
27 HaveAuth,
28 Established,
29 };
30
31 /* encryption numberings (anti-replay) */
32 enum
33 {
34 AuthTreq=1, /* ticket request */
35 AuthChal=2, /* challenge box request */
36 AuthPass=3, /* change password */
37 AuthOK=4, /* fixed length reply follows */
38 AuthErr=5, /* error follows */
39 AuthMod=6, /* modify user */
40 AuthApop=7, /* apop authentication for pop3 */
41 AuthOKvar=9, /* variable length reply follows */
42 AuthChap=10, /* chap authentication for ppp */
43 AuthMSchap=11, /* MS chap authentication for ppp */
44 AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
45 AuthHttp=13, /* http domain login */
46 AuthVNC=14, /* http domain login */
47
48
49 AuthTs=64, /* ticket encrypted with server's key */
50 AuthTc, /* ticket encrypted with client's key */
51 AuthAs, /* server generated authenticator */
52 AuthAc, /* client generated authenticator */
53 AuthTp, /* ticket encrypted with client's key for password change */
54 AuthHr /* http reply */
55 };
56
57 struct Ticketreq
58 {
59 char type;
60 char authid[NAMELEN]; /* server's encryption id */
61 char authdom[DOMLEN]; /* server's authentication domain */
62 char chal[CHALLEN]; /* challenge from server */
63 char hostid[NAMELEN]; /* host's encryption id */
64 char uid[NAMELEN]; /* uid of requesting user on host */
65 };
66 #define TICKREQLEN (3*NAMELEN+CHALLEN+DOMLEN+1)
67
68 struct Ticket
69 {
70 char num; /* replay protection */
71 char chal[CHALLEN]; /* server challenge */
72 char cuid[NAMELEN]; /* uid on client */
73 char suid[NAMELEN]; /* uid on server */
74 char key[DESKEYLEN]; /* nonce DES key */
75 };
76 #define TICKETLEN (CHALLEN+2*NAMELEN+DESKEYLEN+1)
77
78 struct Authenticator
79 {
80 char num; /* replay protection */
81 char chal[CHALLEN];
82 ulong id; /* authenticator id, ++'d with each auth */
83 };
84 #define AUTHENTLEN (CHALLEN+4+1)
85
86 extern int chatty9p;
87
88 static int convT2M(Ticket*, char*, char*);
89 static void convM2T(char*, Ticket*, char*);
90 static void convM2Tnoenc(char*, Ticket*);
91 static int convA2M(Authenticator*, char*, char*);
92 static void convM2A(char*, Authenticator*, char*);
93 static int convTR2M(Ticketreq*, char*);
94 static void convM2TR(char*, Ticketreq*);
95 static int passtokey(char*, char*);
96
97 /*
98 * destructively encrypt the buffer, which
99 * must be at least 8 characters long.
100 */
101 static int
encrypt9p(void * key,void * vbuf,int n)102 encrypt9p(void *key, void *vbuf, int n)
103 {
104 char ekey[128], *buf;
105 int i, r;
106
107 if(n < 8)
108 return 0;
109 key_setup(key, ekey);
110 buf = vbuf;
111 n--;
112 r = n % 7;
113 n /= 7;
114 for(i = 0; i < n; i++){
115 block_cipher(ekey, buf, 0);
116 buf += 7;
117 }
118 if(r)
119 block_cipher(ekey, buf - 7 + r, 0);
120 return 1;
121 }
122
123 /*
124 * destructively decrypt the buffer, which
125 * must be at least 8 characters long.
126 */
127 static int
decrypt9p(void * key,void * vbuf,int n)128 decrypt9p(void *key, void *vbuf, int n)
129 {
130 char ekey[128], *buf;
131 int i, r;
132
133 if(n < 8)
134 return 0;
135 key_setup(key, ekey);
136 buf = vbuf;
137 n--;
138 r = n % 7;
139 n /= 7;
140 buf += n * 7;
141 if(r)
142 block_cipher(ekey, buf - 7 + r, 1);
143 for(i = 0; i < n; i++){
144 buf -= 7;
145 block_cipher(ekey, buf, 1);
146 }
147 return 1;
148 }
149
150 #define CHAR(x) *p++ = f->x
151 #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
152 #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
153 #define LONG(x) VLONG(f->x)
154 #define STRING(x,n) memmove(p, f->x, n); p += n
155
156 static int
convTR2M(Ticketreq * f,char * ap)157 convTR2M(Ticketreq *f, char *ap)
158 {
159 int n;
160 uchar *p;
161
162 p = (uchar*)ap;
163 CHAR(type);
164 STRING(authid, NAMELEN);
165 STRING(authdom, DOMLEN);
166 STRING(chal, CHALLEN);
167 STRING(hostid, NAMELEN);
168 STRING(uid, NAMELEN);
169 n = p - (uchar*)ap;
170 return n;
171 }
172
173 static int
convT2M(Ticket * f,char * ap,char * key)174 convT2M(Ticket *f, char *ap, char *key)
175 {
176 int n;
177 uchar *p;
178
179 p = (uchar*)ap;
180 CHAR(num);
181 STRING(chal, CHALLEN);
182 STRING(cuid, NAMELEN);
183 STRING(suid, NAMELEN);
184 STRING(key, DESKEYLEN);
185 n = p - (uchar*)ap;
186 if(key)
187 encrypt9p(key, ap, n);
188 return n;
189 }
190
191 int
convA2M(Authenticator * f,char * ap,char * key)192 convA2M(Authenticator *f, char *ap, char *key)
193 {
194 int n;
195 uchar *p;
196
197 p = (uchar*)ap;
198 CHAR(num);
199 STRING(chal, CHALLEN);
200 LONG(id);
201 n = p - (uchar*)ap;
202 if(key)
203 encrypt9p(key, ap, n);
204 return n;
205 }
206
207 #undef CHAR
208 #undef SHORT
209 #undef VLONG
210 #undef LONG
211 #undef STRING
212
213 #define CHAR(x) f->x = *p++
214 #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
215 #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
216 #define LONG(x) VLONG(f->x)
217 #define STRING(x,n) memmove(f->x, p, n); p += n
218
219 void
convM2A(char * ap,Authenticator * f,char * key)220 convM2A(char *ap, Authenticator *f, char *key)
221 {
222 uchar *p;
223
224 if(key)
225 decrypt9p(key, ap, AUTHENTLEN);
226 p = (uchar*)ap;
227 CHAR(num);
228 STRING(chal, CHALLEN);
229 LONG(id);
230 USED(p);
231 }
232
233 void
convM2T(char * ap,Ticket * f,char * key)234 convM2T(char *ap, Ticket *f, char *key)
235 {
236 uchar *p;
237
238 if(key)
239 decrypt9p(key, ap, TICKETLEN);
240 p = (uchar*)ap;
241 CHAR(num);
242 STRING(chal, CHALLEN);
243 STRING(cuid, NAMELEN);
244 f->cuid[NAMELEN-1] = 0;
245 STRING(suid, NAMELEN);
246 f->suid[NAMELEN-1] = 0;
247 STRING(key, DESKEYLEN);
248 USED(p);
249 }
250
251 #undef CHAR
252 #undef SHORT
253 #undef LONG
254 #undef VLONG
255 #undef STRING
256
257 static int
passtokey(char * key,char * p)258 passtokey(char *key, char *p)
259 {
260 uchar buf[NAMELEN], *t;
261 int i, n;
262
263 n = strlen(p);
264 if(n >= NAMELEN)
265 n = NAMELEN-1;
266 memset(buf, ' ', 8);
267 t = buf;
268 strncpy((char*)t, p, n);
269 t[n] = 0;
270 memset(key, 0, DESKEYLEN);
271 for(;;){
272 for(i = 0; i < DESKEYLEN; i++)
273 key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
274 if(n <= 8)
275 return 1;
276 n -= 8;
277 t += 8;
278 if(n < 8){
279 t -= 8 - n;
280 n = 8;
281 }
282 encrypt9p(key, t, 8);
283 }
284 return 1; /* not reached */
285 }
286
287 static char authkey[DESKEYLEN];
288 static char *authid;
289 static char *authdom;
290 static char *haveprotosmsg;
291 static char *needprotomsg;
292
293 static void
p9anyinit(void)294 p9anyinit(void)
295 {
296 int n, fd;
297 char abuf[200];
298 char *af, *f[4];
299
300 af = autharg;
301 if(af == nil)
302 af = "/etc/u9fs.key";
303
304 if((fd = open(af, OREAD)) < 0)
305 sysfatal("can't open key file '%s'", af);
306
307 if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
308 sysfatal("can't read key file '%s'", af);
309 if (n > 0 && abuf[n - 1] == '\n')
310 n--;
311 abuf[n] = '\0';
312
313 if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
314 sysfatal("key file '%s' not exactly 3 lines", af);
315
316 passtokey(authkey, f[0]);
317 authid = strdup(f[1]);
318 authdom = strdup(f[2]);
319 haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
320 sprint(haveprotosmsg, "p9sk1@%s", authdom);
321 needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
322 sprint(needprotomsg, "p9sk1 %s", authdom);
323 }
324
325 typedef struct AuthSession {
326 int state;
327 char *uname;
328 char *aname;
329 char cchal[CHALLEN];
330 Ticketreq tr;
331 Ticket t;
332 } AuthSession;
333
334 static char*
p9anyauth(Fcall * rx,Fcall * tx)335 p9anyauth(Fcall *rx, Fcall *tx)
336 {
337 AuthSession *sp;
338 Fid *f;
339 char *ep;
340
341 sp = malloc(sizeof(AuthSession));
342 f = newauthfid(rx->afid, sp, &ep);
343 if (f == nil) {
344 free(sp);
345 return ep;
346 }
347 if (chatty9p)
348 fprint(2, "p9anyauth: afid %d\n", rx->afid);
349 sp->state = HaveProtos;
350 sp->uname = strdup(rx->uname);
351 sp->aname = strdup(rx->aname);
352 tx->aqid.type = QTAUTH;
353 tx->aqid.path = 1;
354 tx->aqid.vers = 0;
355 return nil;
356 }
357
358 static char *
p9anyattach(Fcall * rx,Fcall * tx)359 p9anyattach(Fcall *rx, Fcall *tx)
360 {
361 AuthSession *sp;
362 Fid *f;
363 char *ep;
364
365 f = oldauthfid(rx->afid, (void **)&sp, &ep);
366 if (f == nil)
367 return ep;
368 if (chatty9p)
369 fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
370 if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
371 && strcmp(rx->aname, sp->aname) == 0)
372 return nil;
373 return "authentication failed";
374 }
375
376 static int
readstr(Fcall * rx,Fcall * tx,char * s,int len)377 readstr(Fcall *rx, Fcall *tx, char *s, int len)
378 {
379 if (rx->offset >= len)
380 return 0;
381 tx->count = len - rx->offset;
382 if (tx->count > rx->count)
383 tx->count = rx->count;
384 memcpy(tx->data, s + rx->offset, tx->count);
385 return tx->count;
386 }
387
388 static char *
p9anyread(Fcall * rx,Fcall * tx)389 p9anyread(Fcall *rx, Fcall *tx)
390 {
391 AuthSession *sp;
392 char *ep;
393
394 Fid *f;
395 f = oldauthfid(rx->afid, (void **)&sp, &ep);
396 if (f == nil)
397 return ep;
398 if (chatty9p)
399 fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
400 switch (sp->state) {
401 case HaveProtos:
402 readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
403 if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
404 sp->state = NeedProto;
405 return nil;
406 case HaveTreq:
407 if (rx->count != TICKREQLEN)
408 goto botch;
409 convTR2M(&sp->tr, tx->data);
410 tx->count = TICKREQLEN;
411 sp->state = NeedTicket;
412 return nil;
413 case HaveAuth: {
414 Authenticator a;
415 if (rx->count != AUTHENTLEN)
416 goto botch;
417 a.num = AuthAs;
418 memmove(a.chal, sp->cchal, CHALLEN);
419 a.id = 0;
420 convA2M(&a, (char*)tx->data, sp->t.key);
421 memset(sp->t.key, 0, sizeof(sp->t.key));
422 tx->count = rx->count;
423 sp->state = Established;
424 return nil;
425 }
426 default:
427 botch:
428 return "protocol botch";
429 }
430 }
431
432 static char *
p9anywrite(Fcall * rx,Fcall * tx)433 p9anywrite(Fcall *rx, Fcall *tx)
434 {
435 AuthSession *sp;
436 char *ep;
437
438 Fid *f;
439
440 f = oldauthfid(rx->afid, (void **)&sp, &ep);
441 if (f == nil)
442 return ep;
443 if (chatty9p)
444 fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
445 switch (sp->state) {
446 case NeedProto:
447 if (rx->count != strlen(needprotomsg) + 1)
448 return "protocol response wrong length";
449 if (memcmp(rx->data, needprotomsg, rx->count) != 0)
450 return "unacceptable protocol";
451 sp->state = NeedChal;
452 tx->count = rx->count;
453 return nil;
454 case NeedChal:
455 if (rx->count != CHALLEN)
456 goto botch;
457 memmove(sp->cchal, rx->data, CHALLEN);
458 sp->tr.type = AuthTreq;
459 safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
460 safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
461 randombytes((uchar *)sp->tr.chal, CHALLEN);
462 safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
463 safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
464 tx->count = rx->count;
465 sp->state = HaveTreq;
466 return nil;
467 case NeedTicket: {
468 Authenticator a;
469
470 if (rx->count != TICKETLEN + AUTHENTLEN) {
471 fprint(2, "bad length in attach");
472 goto botch;
473 }
474 convM2T((char*)rx->data, &sp->t, authkey);
475 if (sp->t.num != AuthTs) {
476 fprint(2, "bad AuthTs in attach\n");
477 goto botch;
478 }
479 if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
480 fprint(2, "bad challenge in attach\n");
481 goto botch;
482 }
483 convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
484 if (a.num != AuthAc) {
485 fprint(2, "bad AuthAs in attach\n");
486 goto botch;
487 }
488 if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
489 fprint(2, "bad challenge in attach 2\n");
490 goto botch;
491 }
492 sp->state = HaveAuth;
493 tx->count = rx->count;
494 return nil;
495 }
496 default:
497 botch:
498 return "protocol botch";
499 }
500 }
501
502 static void
safefree(char * p)503 safefree(char *p)
504 {
505 if (p) {
506 memset(p, 0, strlen(p));
507 free(p);
508 }
509 }
510
511 static char *
p9anyclunk(Fcall * rx,Fcall * tx)512 p9anyclunk(Fcall *rx, Fcall *tx)
513 {
514 Fid *f;
515 AuthSession *sp;
516 char *ep;
517
518 f = oldauthfid(rx->afid, (void **)&sp, &ep);
519 if (f == nil)
520 return ep;
521 if (chatty9p)
522 fprint(2, "p9anyclunk: afid %d\n", rx->fid);
523 safefree(sp->uname);
524 safefree(sp->aname);
525 memset(sp, 0, sizeof(sp));
526 free(sp);
527 return nil;
528 }
529
530 Auth authp9any = {
531 "p9any",
532 p9anyauth,
533 p9anyattach,
534 p9anyinit,
535 p9anyread,
536 p9anywrite,
537 p9anyclunk,
538 };
539