xref: /inferno-os/os/port/devssl.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
1 /*
2  *  devssl - secure sockets layer
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "../port/error.h"
7 #include "mem.h"
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"kernel.h"
11 
12 #include	"mp.h"
13 #include	"libsec.h"
14 
15 typedef struct OneWay OneWay;
16 struct OneWay
17 {
18 	QLock	q;
19 	QLock	ctlq;
20 
21 	void	*state;		/* encryption state */
22 	int	slen;			/* secret data length */
23 	uchar	*secret;		/* secret */
24 	ulong	mid;		/* message id */
25 };
26 
27 enum
28 {
29 	/* connection states */
30 	Sincomplete=	0,
31 	Sclear=		1,
32 	Sencrypting=	2,
33 	Sdigesting=	4,
34 	Sdigenc=	Sencrypting|Sdigesting,
35 
36 	/* encryption algorithms */
37 	Noencryption=	0,
38 	DESCBC=		1,
39 	DESECB=		2,
40 	RC4=		3,
41 	IDEACBC=	4,
42 	IDEAECB=		5
43 };
44 
45 typedef struct Dstate Dstate;
46 struct Dstate
47 {
48 	Chan	*c;			/* io channel */
49 	uchar	state;		/* state of connection */
50 	int	ref;			/* serialized by dslock for atomic destroy */
51 
52 	uchar	encryptalg;	/* encryption algorithm */
53 	ushort	blocklen;	/* blocking length */
54 
55 	ushort	diglen;		/* length of digest */
56 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */
57 
58 	/* for SSL format */
59 	int	max;			/* maximum unpadded data per msg */
60 	int	maxpad;			/* maximum padded data per msg */
61 
62 	/* input side */
63 	OneWay	in;
64 	Block	*processed;
65 	Block	*unprocessed;
66 
67 	/* output side */
68 	OneWay	out;
69 
70 	/* protections */
71 	char*	user;
72 	int	perm;
73 };
74 
75 Lock	dslock;
76 int	dshiwat;
77 int	maxdstate = 20;
78 Dstate** dstate;
79 
80 enum
81 {
82 	Maxdmsg=	1<<16,
83 	Maxdstate=	1<<10,
84 };
85 
86 enum{
87 	Qtopdir		= 1,	/* top level directory */
88 	Qclonus,
89 	Qconvdir,			/* directory for a conversation */
90 	Qdata,
91 	Qctl,
92 	Qsecretin,
93 	Qsecretout,
94 	Qencalgs,
95 	Qhashalgs
96 };
97 
98 #define TYPE(x) 	((ulong)(x).path & 0xf)
99 #define CONV(x) 	(((ulong)(x).path >> 4)&(Maxdstate-1))
100 #define QID(c, y) 	(((c)<<4) | (y))
101 
102 /* for generating random fill */
103 ulong badlong;
104 uchar *badarray = (uchar*)&badlong;
105 static char*	encalgs;
106 static char*	hashalgs;
107 
108 void producerand(void);
109 
110 static void alglistinit(void);
111 static void	ensure(Dstate*, Block**, int);
112 static void	consume(Block**, uchar*, int);
113 static void	setsecret(OneWay*, uchar*, int);
114 static Block*	encryptb(Dstate*, Block*, int);
115 static Block*	decryptb(Dstate*, Block*);
116 static Block*	digestb(Dstate*, Block*, int);
117 static void	checkdigestb(Dstate*, Block*);
118 static Chan*	buftochan(char*);
119 static void	sslhangup(Dstate*);
120 static void	dsclone(Chan *c);
121 static void	dsnew(Chan *c, Dstate **);
122 
123 static int
124 sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
125 {
126 	Qid q;
127 	Dstate *ds;
128 	char *p, *nm;
129 
130 	USED(nd);
131 	USED(d);
132 	q.type = QTFILE;
133 	q.vers = 0;
134 	if(s == DEVDOTDOT){
135 		q.path = QID(0, Qtopdir);
136 		q.type = QTDIR;
137 		devdir(c, q, "#D", 0, eve, 0555, dp);
138 		return 1;
139 	}
140 	switch(TYPE(c->qid)) {
141 	case Qtopdir:
142 		if(s < dshiwat) {
143 			q.path = QID(s, Qconvdir);
144 			q.type = QTDIR;
145 			ds = dstate[s];
146 			if(ds != 0)
147  				nm = ds->user;
148  			else
149  				nm = eve;
150 			snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
151 			devdir(c, q, up->genbuf, 0, nm, DMDIR|0555, dp);
152 			return 1;
153 		}
154 		if(s > dshiwat)
155 			return -1;
156 		/* fall through */
157 	case Qclonus:
158 		q.path = QID(0, Qclonus);
159 		devdir(c, q, "clone", 0, eve, 0666, dp);
160 		return 1;
161 	case Qconvdir:
162 		ds = dstate[CONV(c->qid)];
163 		if(ds != 0)
164 			nm = ds->user;
165 		else
166 			nm = eve;
167 		switch(s) {
168 		default:
169 			return -1;
170 		case 0:
171 			q.path = QID(CONV(c->qid), Qctl);
172 			p = "ctl";
173 			break;
174 		case 1:
175 			q.path = QID(CONV(c->qid), Qdata);
176 			p = "data";
177 			break;
178 		case 2:
179 			q.path = QID(CONV(c->qid), Qsecretin);
180 			p = "secretin";
181 			break;
182 		case 3:
183 			q.path = QID(CONV(c->qid), Qsecretout);
184 			p = "secretout";
185 			break;
186 		case 4:
187 			q.path = QID(CONV(c->qid), Qencalgs);
188 			p = "encalgs";
189 			break;
190 		case 5:
191 			q.path = QID(CONV(c->qid), Qhashalgs);
192 			p = "hashalgs";
193 			break;
194 		}
195 		devdir(c, q, p, 0, nm, 0660, dp);
196 		return 1;
197 	}
198 	return -1;
199 }
200 
201 static void
202 sslinit(void)
203 {
204 	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
205 		panic("sslinit");
206 	alglistinit();
207 }
208 
209 static Chan *
210 sslattach(char *spec)
211 {
212 	Chan *c;
213 
214 	c = devattach('D', spec);
215 	c->qid.path = QID(0, Qtopdir);
216 	c->qid.vers = 0;
217 	c->qid.type = QTDIR;
218 	return c;
219 }
220 
221 static Walkqid*
222 sslwalk(Chan *c, Chan *nc, char **name, int nname)
223 {
224 	return devwalk(c, nc, name, nname, 0, 0, sslgen);
225 }
226 
227 static int
228 sslstat(Chan *c, uchar *db, int n)
229 {
230 	return devstat(c, db, n, 0, 0, sslgen);
231 }
232 
233 static Chan*
234 sslopen(Chan *c, int omode)
235 {
236 	Dstate *s, **pp;
237 	int perm;
238 
239 	perm = 0;
240 	omode &= 3;
241 	switch(omode) {
242 	case OREAD:
243 		perm = 4;
244 		break;
245 	case OWRITE:
246 		perm = 2;
247 		break;
248 	case ORDWR:
249 		perm = 6;
250 		break;
251 	}
252 
253 	switch(TYPE(c->qid)) {
254 	default:
255 		panic("sslopen");
256 	case Qtopdir:
257 	case Qconvdir:
258 		if(omode != OREAD)
259 			error(Eperm);
260 		break;
261 	case Qclonus:
262 		dsclone(c);
263 		break;
264 	case Qctl:
265 	case Qdata:
266 	case Qsecretin:
267 	case Qsecretout:
268 		if(waserror()) {
269 			unlock(&dslock);
270 			nexterror();
271 		}
272 		lock(&dslock);
273 		pp = &dstate[CONV(c->qid)];
274 		s = *pp;
275 		if(s == 0)
276 			dsnew(c, pp);
277 		else {
278 			if((perm & (s->perm>>6)) != perm
279 			   && (strcmp(up->env->user, s->user) != 0
280 			     || (perm & s->perm) != perm))
281 				error(Eperm);
282 
283 			s->ref++;
284 		}
285 		unlock(&dslock);
286 		poperror();
287 		break;
288 	case Qencalgs:
289 	case Qhashalgs:
290 		if(omode != OREAD)
291 			error(Eperm);
292 		break;
293 	}
294 	c->mode = openmode(omode);
295 	c->flag |= COPEN;
296 	c->offset = 0;
297 	return c;
298 }
299 
300 static int
301 sslwstat(Chan *c, uchar *db, int n)
302 {
303 	Dir *dir;
304 	Dstate *s;
305 	int m;
306 
307 	s = dstate[CONV(c->qid)];
308 	if(s == 0)
309 		error(Ebadusefd);
310 	if(strcmp(s->user, up->env->user) != 0)
311 		error(Eperm);
312 
313 	dir = smalloc(sizeof(Dir)+n);
314 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
315 	if(m == 0){
316 		free(dir);
317 		error(Eshortstat);
318 	}
319 
320 	if(!emptystr(dir->uid))
321 		kstrdup(&s->user, dir->uid);
322 	if(dir->mode != ~0UL)
323 		s->perm = dir->mode;
324 
325 	free(dir);
326 	return m;
327 }
328 
329 static void
330 sslclose(Chan *c)
331 {
332 	Dstate *s;
333 
334 	switch(TYPE(c->qid)) {
335 	case Qctl:
336 	case Qdata:
337 	case Qsecretin:
338 	case Qsecretout:
339 		if((c->flag & COPEN) == 0)
340 			break;
341 
342 		s = dstate[CONV(c->qid)];
343 		if(s == 0)
344 			break;
345 
346 		lock(&dslock);
347 		if(--s->ref > 0) {
348 			unlock(&dslock);
349 			break;
350 		}
351 		dstate[CONV(c->qid)] = 0;
352 		unlock(&dslock);
353 
354 		sslhangup(s);
355 		if(s->c)
356 			cclose(s->c);
357 		free(s->user);
358 		free(s->in.secret);
359 		free(s->out.secret);
360 		free(s->in.state);
361 		free(s->out.state);
362 		free(s);
363 	}
364 }
365 
366 /*
367  *  make sure we have at least 'n' bytes in list 'l'
368  */
369 static void
370 ensure(Dstate *s, Block **l, int n)
371 {
372 	int sofar, i;
373 	Block *b, *bl;
374 
375 	sofar = 0;
376 	for(b = *l; b; b = b->next){
377 		sofar += BLEN(b);
378 		if(sofar >= n)
379 			return;
380 		l = &b->next;
381 	}
382 
383 	while(sofar < n){
384 		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
385 		if(bl == 0)
386 			error(Ehungup);
387 		*l = bl;
388 		i = 0;
389 		for(b = bl; b; b = b->next){
390 			i += BLEN(b);
391 			l = &b->next;
392 		}
393 		if(i == 0)
394 			error(Ehungup);
395 
396 		sofar += i;
397 	}
398 }
399 
400 /*
401  *  copy 'n' bytes from 'l' into 'p' and free
402  *  the bytes in 'l'
403  */
404 static void
405 consume(Block **l, uchar *p, int n)
406 {
407 	Block *b;
408 	int i;
409 
410 	for(; *l && n > 0; n -= i){
411 		b = *l;
412 		i = BLEN(b);
413 		if(i > n)
414 			i = n;
415 		memmove(p, b->rp, i);
416 		b->rp += i;
417 		p += i;
418 		if(BLEN(b) < 0)
419 			panic("consume");
420 		if(BLEN(b))
421 			break;
422 		*l = b->next;
423 		freeb(b);
424 	}
425 }
426 
427 /*
428  *  remove at most n bytes from the queue, if discard is set
429  *  dump the remainder
430  */
431 static Block*
432 qtake(Block **l, int n, int discard)
433 {
434 	Block *nb, *b, *first;
435 	int i;
436 
437 	first = *l;
438 	for(b = first; b; b = b->next){
439 		i = BLEN(b);
440 		if(i == n){
441 			if(discard){
442 				freeblist(b->next);
443 				*l = 0;
444 			} else
445 				*l = b->next;
446 			b->next = 0;
447 			return first;
448 		} else if(i > n){
449 			i -= n;
450 			if(discard){
451 				freeblist(b->next);
452 				*l = 0;
453 			} else {
454 				nb = allocb(i);
455 				memmove(nb->wp, b->rp+n, i);
456 				nb->wp += i;
457 				nb->next = b->next;
458 				*l = nb;
459 			}
460 			b->wp -= i;
461 			b->next = 0;
462 			if(BLEN(b) < 0)
463 				panic("qtake");
464 			return first;
465 		} else
466 			n -= i;
467 		if(BLEN(b) < 0)
468 			panic("qtake");
469 	}
470 	*l = 0;
471 	return first;
472 }
473 
474 static Block*
475 sslbread(Chan *c, long n, ulong offset)
476 {
477 	volatile struct { Dstate *s; } s;
478 	Block *b;
479 	uchar count[2];
480 	int len, pad;
481 
482 	USED(offset);
483 
484 	s.s = dstate[CONV(c->qid)];
485 	if(s.s == 0)
486 		panic("sslbread");
487 	if(s.s->state == Sincomplete)
488 		error(Ebadusefd);
489 
490 	if(waserror()){
491 		qunlock(&s.s->in.q);
492 		sslhangup(s.s);
493 		nexterror();
494 	}
495 	qlock(&s.s->in.q);
496 
497 	if(s.s->processed == 0){
498 		/* read in the whole message */
499 		ensure(s.s, &s.s->unprocessed, 2);
500 		consume(&s.s->unprocessed, count, 2);
501 		if(count[0] & 0x80){
502 			len = ((count[0] & 0x7f)<<8) | count[1];
503 			ensure(s.s, &s.s->unprocessed, len);
504 			pad = 0;
505 		} else {
506 			len = ((count[0] & 0x3f)<<8) | count[1];
507 			ensure(s.s, &s.s->unprocessed, len+1);
508 			consume(&s.s->unprocessed, count, 1);
509 			pad = count[0];
510 			if(pad > len){
511 				print("pad %d buf len %d\n", pad, len);
512 				error("bad pad in ssl message");
513 			}
514 		}
515 
516 		/* put extra on unprocessed queue */
517 		s.s->processed = qtake(&s.s->unprocessed, len, 0);
518 
519 		if(waserror()){
520 			qunlock(&s.s->in.ctlq);
521 			nexterror();
522 		}
523 		qlock(&s.s->in.ctlq);
524 		switch(s.s->state){
525 		case Sencrypting:
526 			s.s->processed = decryptb(s.s, s.s->processed);
527 			break;
528 		case Sdigesting:
529 			s.s->processed = pullupblock(s.s->processed, s.s->diglen);
530 			if(s.s->processed == 0)
531 				error("ssl message too short");
532 			checkdigestb(s.s, s.s->processed);
533 			s.s->processed->rp += s.s->diglen;
534 			break;
535 		case Sdigenc:
536 			s.s->processed = decryptb(s.s, s.s->processed);
537 			s.s->processed = pullupblock(s.s->processed, s.s->diglen);
538 			if(s.s->processed == 0)
539 				error("ssl message too short");
540 			checkdigestb(s.s, s.s->processed);
541 			s.s->processed->rp += s.s->diglen;
542 			len -= s.s->diglen;
543 			break;
544 		}
545 		s.s->in.mid++;
546 		qunlock(&s.s->in.ctlq);
547 		poperror();
548 
549 		/* remove pad */
550 		if(pad)
551 			s.s->processed = qtake(&s.s->processed, len - pad, 1);
552 	}
553 
554 	/* return at most what was asked for */
555 	b = qtake(&s.s->processed, n, 0);
556 
557 	qunlock(&s.s->in.q);
558 	poperror();
559 
560 	return b;
561 }
562 
563 static long
564 sslread(Chan *c, void *a, long n, vlong offset)
565 {
566 	volatile struct { Block *b; } b;
567 	Block *nb;
568 	uchar *va;
569 	int i;
570 	char buf[128];
571 
572 	if(c->qid.type & QTDIR)
573 		return devdirread(c, a, n, 0, 0, sslgen);
574 
575 	switch(TYPE(c->qid)) {
576 	default:
577 		error(Ebadusefd);
578 	case Qctl:
579 		sprint(buf, "%ld", CONV(c->qid));
580 		return readstr(offset, a, n, buf);
581 	case Qdata:
582 		b.b = sslbread(c, n, offset);
583 		break;
584 	case Qencalgs:
585 		return readstr(offset, a, n, encalgs);
586 	case Qhashalgs:
587 		return readstr(offset, a, n, hashalgs);
588 	}
589 
590 	n = 0;
591 	va = a;
592 	for(nb = b.b; nb; nb = nb->next){
593 		i = BLEN(nb);
594 		memmove(va+n, nb->rp, i);
595 		n += i;
596 	}
597 
598 	freeblist(b.b);
599 
600 	return n;
601 }
602 
603 /*
604  *  this algorithm doesn't have to be great since we're just
605  *  trying to obscure the block fill
606  */
607 static void
608 randfill(uchar *buf, int len)
609 {
610 	while(len-- > 0)
611 		*buf++ = nrand(256);
612 }
613 
614 /*
615  *  use SSL record format, add in count and digest or encrypt
616  */
617 static long
618 sslbwrite(Chan *c, Block *b, ulong offset)
619 {
620 	volatile struct { Dstate *s; } s;
621 	volatile struct { Block *b; } bb;
622 	Block *nb;
623 	int h, n, m, pad, rv;
624 	uchar *p;
625 
626 	bb.b = b;
627 
628 	s.s = dstate[CONV(c->qid)];
629 	if(s.s == 0)
630 		panic("sslbwrite");
631 	if(s.s->state == Sincomplete){
632 		freeb(b);
633 		error(Ebadusefd);
634 	}
635 
636 	if(waserror()){
637 		qunlock(&s.s->out.q);
638 		if(bb.b)
639 			freeb(bb.b);
640 		sslhangup(s.s);
641 		nexterror();
642 	}
643 	qlock(&s.s->out.q);
644 
645 	rv = 0;
646 	while(bb.b){
647 		m = n = BLEN(bb.b);
648 		h = s.s->diglen + 2;
649 
650 		/* trim to maximum block size */
651 		pad = 0;
652 		if(m > s.s->max){
653 			m = s.s->max;
654 		} else if(s.s->blocklen != 1){
655 			pad = (m + s.s->diglen)%s.s->blocklen;
656 			if(pad){
657 				if(m > s.s->maxpad){
658 					pad = 0;
659 					m = s.s->maxpad;
660 				} else {
661 					pad = s.s->blocklen - pad;
662 					h++;
663 				}
664 			}
665 		}
666 
667 		rv += m;
668 		if(m != n){
669 			nb = allocb(m + h + pad);
670 			memmove(nb->wp + h, bb.b->rp, m);
671 			nb->wp += m + h;
672 			bb.b->rp += m;
673 		} else {
674 			/* add header space */
675 			nb = padblock(bb.b, h);
676 			bb.b = 0;
677 		}
678 		m += s.s->diglen;
679 
680 		/* SSLv2 style count */
681 		if(pad){
682 			nb = padblock(nb, -pad);
683 			randfill(nb->wp, pad);
684 			nb->wp += pad;
685 			m += pad;
686 
687 			p = nb->rp;
688 			p[0] = (m>>8);
689 			p[1] = m;
690 			p[2] = pad;
691 			offset = 3;
692 		} else {
693 			p = nb->rp;
694 			p[0] = (m>>8) | 0x80;
695 			p[1] = m;
696 			offset = 2;
697 		}
698 
699 		switch(s.s->state){
700 		case Sencrypting:
701 			nb = encryptb(s.s, nb, offset);
702 			break;
703 		case Sdigesting:
704 			nb = digestb(s.s, nb, offset);
705 			break;
706 		case Sdigenc:
707 			nb = digestb(s.s, nb, offset);
708 			nb = encryptb(s.s, nb, offset);
709 			break;
710 		}
711 
712 		s.s->out.mid++;
713 
714 		m = BLEN(nb);
715 		devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset);
716 		s.s->c->offset += m;
717 	}
718 	qunlock(&s.s->out.q);
719 	poperror();
720 
721 	return rv;
722 }
723 
724 static void
725 setsecret(OneWay *w, uchar *secret, int n)
726 {
727 	free(w->secret);
728 	w->secret = mallocz(n, 0);
729 	if(w->secret == nil)
730 		error(Enomem);
731 	memmove(w->secret, secret, n);
732 	w->slen = n;
733 }
734 
735 static void
736 initIDEAkey(OneWay *w)
737 {
738 	free(w->state);
739 	w->state = malloc(sizeof(IDEAstate));
740 	if(w->state == nil)
741 		error(Enomem);
742 	if(w->slen >= 24)
743 		setupIDEAstate(w->state, w->secret, w->secret+16);
744 	else if(w->slen >= 16)
745 		setupIDEAstate(w->state, w->secret, 0);
746 	else
747 		error("secret too short");
748 }
749 
750 static void
751 initDESkey(OneWay *w)
752 {
753 	free(w->state);
754 	w->state = malloc(sizeof(DESstate));
755 	if (!w->state)
756 		error(Enomem);
757 	if(w->slen >= 16)
758 		setupDESstate(w->state, w->secret, w->secret+8);
759 	else if(w->slen >= 8)
760 		setupDESstate(w->state, w->secret, 0);
761 	else
762 		error("secret too short");
763 }
764 
765 /*
766  *  40 bit DES is the same as 56 bit DES.  However,
767  *  16 bits of the key are masked to zero.
768  */
769 static void
770 initDESkey_40(OneWay *w)
771 {
772 	uchar key[8];
773 
774 	if(w->slen >= 8) {
775 		memmove(key, w->secret, 8);
776 		key[0] &= 0x0f;
777 		key[2] &= 0x0f;
778 		key[4] &= 0x0f;
779 		key[6] &= 0x0f;
780 	}
781 
782 	free(w->state);
783 	w->state = malloc(sizeof(DESstate));
784 	if (!w->state)
785 		error(Enomem);
786 	if(w->slen >= 16)
787 		setupDESstate(w->state, key, w->secret+8);
788 	else if(w->slen >= 8)
789 		setupDESstate(w->state, key, 0);
790 	else
791 		error("secret too short");
792 }
793 
794 static void
795 initRC4key(OneWay *w)
796 {
797 	free(w->state);
798 	w->state = malloc(sizeof(RC4state));
799 	if (!w->state)
800 		error(Enomem);
801 	setupRC4state(w->state, w->secret, w->slen);
802 }
803 
804 /*
805  *  40 bit RC4 is the same as n-bit RC4.  However,
806  *  we ignore all but the first 40 bits of the key.
807  */
808 static void
809 initRC4key_40(OneWay *w)
810 {
811 	int slen = w->slen;
812 
813 	if(slen > 5)
814 		slen = 5;
815 
816 	free(w->state);
817 	w->state = malloc(sizeof(RC4state));
818 	if (!w->state)
819 		error(Enomem);
820 	setupRC4state(w->state, w->secret, slen);
821 }
822 
823 /*
824  *  128 bit RC4 is the same as n-bit RC4.  However,
825  *  we ignore all but the first 128 bits of the key.
826  */
827 static void
828 initRC4key_128(OneWay *w)
829 {
830 	int slen = w->slen;
831 
832 	if(slen > 16)
833 		slen = 16;
834 
835 	free(w->state);
836 	w->state = malloc(sizeof(RC4state));
837 	if (!w->state)
838 		error(Enomem);
839 	setupRC4state(w->state, w->secret, slen);
840 }
841 
842 typedef struct Hashalg Hashalg;
843 struct Hashalg
844 {
845 	char	*name;
846 	int	diglen;
847 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
848 };
849 
850 Hashalg hashtab[] =
851 {
852 	{ "md4", MD4dlen, md4, },
853 	{ "md5", MD5dlen, md5, },
854 	{ "sha1", SHA1dlen, sha1, },
855 	{ "sha", SHA1dlen, sha1, },
856 	{ 0 }
857 };
858 
859 static int
860 parsehashalg(char *p, Dstate *s)
861 {
862 	Hashalg *ha;
863 
864 	for(ha = hashtab; ha->name; ha++){
865 		if(strcmp(p, ha->name) == 0){
866 			s->hf = ha->hf;
867 			s->diglen = ha->diglen;
868 			s->state &= ~Sclear;
869 			s->state |= Sdigesting;
870 			return 0;
871 		}
872 	}
873 	return -1;
874 }
875 
876 typedef struct Encalg Encalg;
877 struct Encalg
878 {
879 	char	*name;
880 	int	blocklen;
881 	int	alg;
882 	void	(*keyinit)(OneWay*);
883 };
884 
885 Encalg encrypttab[] =
886 {
887 	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
888 	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
889 	{ "des_56_cbc", 8, DESCBC, initDESkey, },
890 	{ "des_56_ecb", 8, DESECB, initDESkey, },
891 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
892 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
893 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
894 	{ "rc4_256", 1, RC4, initRC4key, },
895 	{ "rc4_128", 1, RC4, initRC4key_128, },
896 	{ "rc4_40", 1, RC4, initRC4key_40, },
897 	{ "ideacbc", 8, IDEACBC, initIDEAkey, },
898 	{ "ideaecb", 8, IDEAECB, initIDEAkey, },
899 	{ 0 }
900 };
901 
902 static int
903 parseencryptalg(char *p, Dstate *s)
904 {
905 	Encalg *ea;
906 
907 	for(ea = encrypttab; ea->name; ea++){
908 		if(strcmp(p, ea->name) == 0){
909 			s->encryptalg = ea->alg;
910 			s->blocklen = ea->blocklen;
911 			(*ea->keyinit)(&s->in);
912 			(*ea->keyinit)(&s->out);
913 			s->state &= ~Sclear;
914 			s->state |= Sencrypting;
915 			return 0;
916 		}
917 	}
918 	return -1;
919 }
920 
921 static void
922 alglistinit(void)
923 {
924 	Hashalg *h;
925 	Encalg *e;
926 	int n;
927 
928 	n = 1;
929 	for(e = encrypttab; e->name != nil; e++)
930 		n += strlen(e->name) + 1;
931 	encalgs = malloc(n);
932 	if(encalgs == nil)
933 		panic("sslinit");
934 	n = 0;
935 	for(e = encrypttab; e->name != nil; e++){
936 		strcpy(encalgs+n, e->name);
937 		n += strlen(e->name);
938 		if(e[1].name == nil)
939 			break;
940 		encalgs[n++] = ' ';
941 	}
942 	encalgs[n] = 0;
943 
944 	n = 1;
945 	for(h = hashtab; h->name != nil; h++)
946 		n += strlen(h->name) + 1;
947 	hashalgs = malloc(n);
948 	if(hashalgs == nil)
949 		panic("sslinit");
950 	n = 0;
951 	for(h = hashtab; h->name != nil; h++){
952 		strcpy(hashalgs+n, h->name);
953 		n += strlen(h->name);
954 		if(h[1].name == nil)
955 			break;
956 		hashalgs[n++] = ' ';
957 	}
958 	hashalgs[n] = 0;
959 }
960 
961 static long
962 sslwrite(Chan *c, void *a, long n, vlong offset)
963 {
964 	volatile struct { Dstate *s; } s;
965 	volatile struct { Block *b; } b;
966 	int m, t;
967 	char *p, *np, *e, buf[32];
968 	uchar *x;
969 
970 	s.s = dstate[CONV(c->qid)];
971 	if(s.s == 0)
972 		panic("sslwrite");
973 
974 	t = TYPE(c->qid);
975 	if(t == Qdata){
976 		if(s.s->state == Sincomplete)
977 			error(Ebadusefd);
978 
979 		p = a;
980 		e = p + n;
981 		do {
982 			m = e - p;
983 			if(m > s.s->max)
984 				m = s.s->max;
985 
986 			b.b = allocb(m);
987 			memmove(b.b->wp, p, m);
988 			b.b->wp += m;
989 
990 			sslbwrite(c, b.b, offset);
991 
992 			p += m;
993 		} while(p < e);
994 		return n;
995 	}
996 
997 	/* mutex with operations using what we're about to change */
998 	if(waserror()){
999 		qunlock(&s.s->in.ctlq);
1000 		qunlock(&s.s->out.q);
1001 		nexterror();
1002 	}
1003 	qlock(&s.s->in.ctlq);
1004 	qlock(&s.s->out.q);
1005 
1006 	switch(t){
1007 	default:
1008 		panic("sslwrite");
1009 	case Qsecretin:
1010 		setsecret(&s.s->in, a, n);
1011 		goto out;
1012 	case Qsecretout:
1013 		setsecret(&s.s->out, a, n);
1014 		goto out;
1015 	case Qctl:
1016 		break;
1017 	}
1018 
1019 	if(n >= sizeof(buf))
1020 		error(Ebadarg);
1021 	strncpy(buf, a, n);
1022 	buf[n] = 0;
1023 	p = strchr(buf, '\n');
1024 	if(p)
1025 		*p = 0;
1026 	p = strchr(buf, ' ');
1027 	if(p)
1028 		*p++ = 0;
1029 
1030 	if(strcmp(buf, "fd") == 0){
1031 		s.s->c = buftochan(p);
1032 
1033 		/* default is clear (msg delimiters only) */
1034 		s.s->state = Sclear;
1035 		s.s->blocklen = 1;
1036 		s.s->diglen = 0;
1037 		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
1038 		s.s->in.mid = 0;
1039 		s.s->out.mid = 0;
1040 	} else if(strcmp(buf, "alg") == 0 && p != 0){
1041 		s.s->blocklen = 1;
1042 		s.s->diglen = 0;
1043 
1044 		if(s.s->c == 0)
1045 			error("must set fd before algorithm");
1046 
1047 		if(strcmp(p, "clear") == 0){
1048 			s.s->state = Sclear;
1049 			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
1050 			goto out;
1051 		}
1052 
1053 		if(s.s->in.secret && s.s->out.secret == 0)
1054 			setsecret(&s.s->out, s.s->in.secret, s.s->in.slen);
1055 		if(s.s->out.secret && s.s->in.secret == 0)
1056 			setsecret(&s.s->in, s.s->out.secret, s.s->out.slen);
1057 		if(s.s->in.secret == 0 || s.s->out.secret == 0)
1058 			error("algorithm but no secret");
1059 
1060 		s.s->hf = 0;
1061 		s.s->encryptalg = Noencryption;
1062 		s.s->blocklen = 1;
1063 
1064 		for(;;){
1065 			np = strchr(p, ' ');
1066 			if(np)
1067 				*np++ = 0;
1068 			else{
1069 				np = strchr(p, '/');
1070 				if(np)
1071 					*np++ = 0;
1072 			}
1073 			if(parsehashalg(p, s.s) < 0)
1074 			if(parseencryptalg(p, s.s) < 0)
1075 				error(Ebadarg);
1076 
1077 			if(np == 0)
1078 				break;
1079 			p = np;
1080 		}
1081 
1082 		if(s.s->hf == 0 && s.s->encryptalg == Noencryption)
1083 			error(Ebadarg);
1084 
1085 		if(s.s->blocklen != 1){
1086 			/* make multiple of blocklen */
1087 			s.s->max = (1<<15) - s.s->diglen - 1;
1088 			s.s->max -= s.s->max % s.s->blocklen;
1089 			s.s->maxpad = (1<<14) - s.s->diglen - 1;
1090 			s.s->maxpad -= s.s->maxpad % s.s->blocklen;
1091 		} else
1092 			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
1093 	} else if(strcmp(buf, "secretin") == 0 && p != 0) {
1094 		m = (strlen(p)*3)/2;
1095 		x = smalloc(m);
1096 		if(waserror()){
1097 			free(x);
1098 			nexterror();
1099 		}
1100 		t = dec64(x, m, p, strlen(p));
1101 		setsecret(&s.s->in, x, t);
1102 		poperror();
1103 		free(x);
1104 	} else if(strcmp(buf, "secretout") == 0 && p != 0) {
1105 		m = (strlen(p)*3)/2;
1106 		x = smalloc(m);
1107 		if(waserror()){
1108 			free(x);
1109 			nexterror();
1110 		}
1111 		t = dec64(x, m, p, strlen(p));
1112 		setsecret(&s.s->out, x, t);
1113 		poperror();
1114 		free(x);
1115 	} else
1116 		error(Ebadarg);
1117 
1118 out:
1119 	qunlock(&s.s->in.ctlq);
1120 	qunlock(&s.s->out.q);
1121 	poperror();
1122 	return n;
1123 }
1124 
1125 Dev ssldevtab = {
1126 	'D',
1127 	"ssl",
1128 
1129 	devreset,
1130 	sslinit,
1131 	devshutdown,
1132 	sslattach,
1133 	sslwalk,
1134 	sslstat,
1135 	sslopen,
1136 	devcreate,
1137 	sslclose,
1138 	sslread,
1139 	sslbread,
1140 	sslwrite,
1141 	sslbwrite,
1142 	devremove,
1143 	sslwstat,
1144 };
1145 
1146 static Block*
1147 encryptb(Dstate *s, Block *b, int offset)
1148 {
1149 	uchar *p, *ep, *p2, *ip, *eip;
1150 	DESstate *ds;
1151 	IDEAstate *is;
1152 
1153 	switch(s->encryptalg){
1154 	case DESECB:
1155 		ds = s->out.state;
1156 		ep = b->rp + BLEN(b);
1157 		for(p = b->rp + offset; p < ep; p += 8)
1158 			block_cipher(ds->expanded, p, 0);
1159 		break;
1160 	case DESCBC:
1161 		ds = s->out.state;
1162 		ep = b->rp + BLEN(b);
1163 		for(p = b->rp + offset; p < ep; p += 8){
1164 			p2 = p;
1165 			ip = ds->ivec;
1166 			for(eip = ip+8; ip < eip; )
1167 				*p2++ ^= *ip++;
1168 			block_cipher(ds->expanded, p, 0);
1169 			memmove(ds->ivec, p, 8);
1170 		}
1171 		break;
1172 	case IDEAECB:
1173 		is = s->out.state;
1174 		ep = b->rp + BLEN(b);
1175 		for(p = b->rp + offset; p < ep; p += 8)
1176 			idea_cipher(is->edkey, p, 0);
1177 		break;
1178 	case IDEACBC:
1179 		is = s->out.state;
1180 		ep = b->rp + BLEN(b);
1181 		for(p = b->rp + offset; p < ep; p += 8){
1182 			p2 = p;
1183 			ip = is->ivec;
1184 			for(eip = ip+8; ip < eip; )
1185 				*p2++ ^= *ip++;
1186 			idea_cipher(is->edkey, p, 0);
1187 			memmove(is->ivec, p, 8);
1188 		}
1189 		break;
1190 	case RC4:
1191 		rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
1192 		break;
1193 	}
1194 	return b;
1195 }
1196 
1197 static Block*
1198 decryptb(Dstate *s, Block *inb)
1199 {
1200 	Block *b, **l;
1201 	uchar *p, *ep, *tp, *ip, *eip;
1202 	DESstate *ds;
1203 	IDEAstate *is;
1204 	uchar tmp[8];
1205 	int i;
1206 
1207 	l = &inb;
1208 	for(b = inb; b; b = b->next){
1209 		/* make sure we have a multiple of s->blocklen */
1210 		if(s->blocklen > 1){
1211 			i = BLEN(b);
1212 			if(i % s->blocklen){
1213 				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
1214 				if(b == 0)
1215 					error("ssl encrypted message too short");
1216 			}
1217 		}
1218 		l = &b->next;
1219 
1220 		/* decrypt */
1221 		switch(s->encryptalg){
1222 		case DESECB:
1223 			ds = s->in.state;
1224 			ep = b->rp + BLEN(b);
1225 			for(p = b->rp; p < ep; p += 8)
1226 				block_cipher(ds->expanded, p, 1);
1227 			break;
1228 		case DESCBC:
1229 			ds = s->in.state;
1230 			ep = b->rp + BLEN(b);
1231 			for(p = b->rp; p < ep;){
1232 				memmove(tmp, p, 8);
1233 				block_cipher(ds->expanded, p, 1);
1234 				tp = tmp;
1235 				ip = ds->ivec;
1236 				for(eip = ip+8; ip < eip; ){
1237 					*p++ ^= *ip;
1238 					*ip++ = *tp++;
1239 				}
1240 			}
1241 			break;
1242 		case IDEAECB:
1243 			is = s->in.state;
1244 			ep = b->rp + BLEN(b);
1245 			for(p = b->rp; p < ep; p += 8)
1246 				idea_cipher(is->edkey, p, 1);
1247 			break;
1248 		case IDEACBC:
1249 			is = s->in.state;
1250 			ep = b->rp + BLEN(b);
1251 			for(p = b->rp; p < ep;){
1252 				memmove(tmp, p, 8);
1253 				idea_cipher(is->edkey, p, 1);
1254 				tp = tmp;
1255 				ip = is->ivec;
1256 				for(eip = ip+8; ip < eip; ){
1257 					*p++ ^= *ip;
1258 					*ip++ = *tp++;
1259 				}
1260 			}
1261 			break;
1262 		case RC4:
1263 			rc4(s->in.state, b->rp, BLEN(b));
1264 			break;
1265 		}
1266 	}
1267 	return inb;
1268 }
1269 
1270 static Block*
1271 digestb(Dstate *s, Block *b, int offset)
1272 {
1273 	uchar *p;
1274 	DigestState ss;
1275 	uchar msgid[4];
1276 	ulong n, h;
1277 	OneWay *w;
1278 
1279 	w = &s->out;
1280 
1281 	memset(&ss, 0, sizeof(ss));
1282 	h = s->diglen + offset;
1283 	n = BLEN(b) - h;
1284 
1285 	/* hash secret + message */
1286 	(*s->hf)(w->secret, w->slen, 0, &ss);
1287 	(*s->hf)(b->rp + h, n, 0, &ss);
1288 
1289 	/* hash message id */
1290 	p = msgid;
1291 	n = w->mid;
1292 	*p++ = n>>24;
1293 	*p++ = n>>16;
1294 	*p++ = n>>8;
1295 	*p = n;
1296 	(*s->hf)(msgid, 4, b->rp + offset, &ss);
1297 
1298 	return b;
1299 }
1300 
1301 static void
1302 checkdigestb(Dstate *s, Block *inb)
1303 {
1304 	uchar *p;
1305 	DigestState ss;
1306 	uchar msgid[4];
1307 	int n, h;
1308 	OneWay *w;
1309 	uchar digest[128];
1310 	Block *b;
1311 
1312 	w = &s->in;
1313 
1314 	memset(&ss, 0, sizeof(ss));
1315 
1316 	/* hash secret */
1317 	(*s->hf)(w->secret, w->slen, 0, &ss);
1318 
1319 	/* hash message */
1320 	h = s->diglen;
1321 	for(b = inb; b; b = b->next){
1322 		n = BLEN(b) - h;
1323 		if(n < 0)
1324 			panic("checkdigestb");
1325 		(*s->hf)(b->rp + h, n, 0, &ss);
1326 		h = 0;
1327 	}
1328 
1329 	/* hash message id */
1330 	p = msgid;
1331 	n = w->mid;
1332 	*p++ = n>>24;
1333 	*p++ = n>>16;
1334 	*p++ = n>>8;
1335 	*p = n;
1336 	(*s->hf)(msgid, 4, digest, &ss);
1337 
1338 	/* requires pullupblock */
1339 	if(memcmp(digest, inb->rp, s->diglen) != 0)
1340 		error("bad digest");
1341 }
1342 
1343 /* get channel associated with an fd */
1344 static Chan*
1345 buftochan(char *p)
1346 {
1347 	Chan *c;
1348 	int fd;
1349 
1350 	if(p == 0)
1351 		error(Ebadarg);
1352 	fd = strtoul(p, 0, 0);
1353 	if(fd < 0)
1354 		error(Ebadarg);
1355 	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);	/* error check and inc ref */
1356 	return c;
1357 }
1358 
1359 /* hang up a digest connection */
1360 static void
1361 sslhangup(Dstate *s)
1362 {
1363 	qlock(&s->in.q);
1364 	freeblist(s->processed);
1365 	s->processed = 0;
1366 	freeblist(s->unprocessed);
1367 	s->unprocessed = 0;
1368 	s->state = Sincomplete;
1369 	qunlock(&s->in.q);
1370 }
1371 
1372 extern void rbcheck(char*);
1373 
1374 static void
1375 dsclone(Chan *ch)
1376 {
1377 	Dstate **pp, **ep, **np;
1378 	int newmax;
1379 
1380 	lock(&dslock);
1381 	if(waserror()) {
1382 		unlock(&dslock);
1383 		nexterror();
1384 	}
1385 	ep = &dstate[maxdstate];
1386 	for(pp = dstate; pp < ep; pp++) {
1387 		if(*pp == 0) {
1388 			dsnew(ch, pp);
1389 			break;
1390 		}
1391 	}
1392 	if(pp >= ep) {
1393 		if(maxdstate >= Maxdstate)
1394 			error(Enodev);
1395 		newmax = 2 * maxdstate;
1396 		if(newmax > Maxdstate)
1397 			newmax = Maxdstate;
1398 		np = realloc(dstate, sizeof(Dstate*) * newmax);
1399 		if(np == 0)
1400 			error(Enomem);
1401 		dstate = np;
1402 		pp = &dstate[maxdstate];
1403 		memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate));
1404 		maxdstate = newmax;
1405 		dsnew(ch, pp);
1406 	}
1407 	poperror();
1408 	unlock(&dslock);
1409 }
1410 
1411 static void
1412 dsnew(Chan *ch, Dstate **pp)
1413 {
1414 	Dstate *s;
1415 	int t;
1416 
1417 	*pp = s = mallocz(sizeof(*s), 1);
1418 	if(s == nil)
1419 		error(Enomem);
1420 	if(pp - dstate >= dshiwat)
1421 		dshiwat++;
1422 	s->state = Sincomplete;
1423 	s->ref = 1;
1424 	kstrdup(&s->user, up->env->user);
1425 	s->perm = 0660;
1426 	t = TYPE(ch->qid);
1427 	if(t == Qclonus)
1428 		t = Qctl;
1429 	ch->qid.path = QID(pp - dstate, t);
1430 	ch->qid.vers = 0;
1431 	ch->qid.type = QTFILE;
1432 }
1433