xref: /inferno-os/os/port/devssl.c (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
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 char** dsname;
80 
81 enum
82 {
83 	Maxdmsg=	1<<16,
84 	Maxdstate=	1<<10,
85 };
86 
87 enum{
88 	Qtopdir		= 1,	/* top level directory */
89 	Qclonus,
90 	Qconvdir,			/* directory for a conversation */
91 	Qdata,
92 	Qctl,
93 	Qsecretin,
94 	Qsecretout,
95 	Qencalgs,
96 	Qhashalgs
97 };
98 
99 #define TYPE(x) 	((ulong)(x).path & 0xf)
100 #define CONV(x) 	(((ulong)(x).path >> 4)&(Maxdstate-1))
101 #define QID(c, y) 	(((c)<<4) | (y))
102 
103 /* for generating random fill */
104 ulong badlong;
105 uchar *badarray = (uchar*)&badlong;
106 static char*	encalgs;
107 static char*	hashalgs;
108 
109 void producerand(void);
110 
111 static void alglistinit(void);
112 static void	ensure(Dstate*, Block**, int);
113 static void	consume(Block**, uchar*, int);
114 static void	setsecret(OneWay*, uchar*, int);
115 static Block*	encryptb(Dstate*, Block*, int);
116 static Block*	decryptb(Dstate*, Block*);
117 static Block*	digestb(Dstate*, Block*, int);
118 static void	checkdigestb(Dstate*, Block*);
119 static Chan*	buftochan(char*);
120 static void	sslhangup(Dstate*);
121 static Dstate*	dsclone(Chan *c);
122 static void	dsnew(Chan *c, Dstate **);
123 
124 static int
125 sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
126 {
127 	Qid q;
128 	Dstate *ds;
129 	char name[16], *p, *nm;
130 
131 	USED(nd);
132 	USED(d);
133 	q.type = QTFILE;
134 	q.vers = 0;
135 	if(s == DEVDOTDOT){
136 		q.path = QID(0, Qtopdir);
137 		q.type = QTDIR;
138 		devdir(c, q, "#D", 0, eve, 0555, dp);
139 		return 1;
140 	}
141 	switch(TYPE(c->qid)) {
142 	case Qtopdir:
143 		if(s < dshiwat) {
144 			q.path = QID(s, Qconvdir);
145 			q.type = QTDIR;
146 			ds = dstate[s];
147 			if(ds != 0)
148  				nm = ds->user;
149  			else
150  				nm = eve;
151 			if(dsname[s] == nil){
152 				sprint(name, "%d", s);
153 				kstrdup(&dsname[s], name);
154 			}
155 			devdir(c, q, dsname[s], 0, nm, DMDIR|0555, dp);
156 			return 1;
157 		}
158 		if(s > dshiwat)
159 			return -1;
160 		/* fall through */
161 	case Qclonus:
162 		q.path = QID(0, Qclonus);
163 		devdir(c, q, "clone", 0, eve, 0666, dp);
164 		return 1;
165 	case Qconvdir:
166 		ds = dstate[CONV(c->qid)];
167 		if(ds != 0)
168 			nm = ds->user;
169 		else
170 			nm = eve;
171 		switch(s) {
172 		default:
173 			return -1;
174 		case 0:
175 			q.path = QID(CONV(c->qid), Qctl);
176 			p = "ctl";
177 			break;
178 		case 1:
179 			q.path = QID(CONV(c->qid), Qdata);
180 			p = "data";
181 			break;
182 		case 2:
183 			q.path = QID(CONV(c->qid), Qsecretin);
184 			p = "secretin";
185 			break;
186 		case 3:
187 			q.path = QID(CONV(c->qid), Qsecretout);
188 			p = "secretout";
189 			break;
190 		case 4:
191 			q.path = QID(CONV(c->qid), Qencalgs);
192 			p = "encalgs";
193 			break;
194 		case 5:
195 			q.path = QID(CONV(c->qid), Qhashalgs);
196 			p = "hashalgs";
197 			break;
198 		}
199 		devdir(c, q, p, 0, nm, 0660, dp);
200 		return 1;
201 	}
202 	return -1;
203 }
204 
205 static void
206 sslinit(void)
207 {
208 	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
209 		panic("sslinit");
210 	if((dsname = malloc(sizeof(*dsname) * maxdstate)) == 0)
211 		panic("sslinit");
212 	alglistinit();
213 }
214 
215 static Chan *
216 sslattach(char *spec)
217 {
218 	Chan *c;
219 
220 	c = devattach('D', spec);
221 	c->qid.path = QID(0, Qtopdir);
222 	c->qid.vers = 0;
223 	c->qid.type = QTDIR;
224 	return c;
225 }
226 
227 static Walkqid*
228 sslwalk(Chan *c, Chan *nc, char **name, int nname)
229 {
230 	return devwalk(c, nc, name, nname, 0, 0, sslgen);
231 }
232 
233 static int
234 sslstat(Chan *c, uchar *db, int n)
235 {
236 	return devstat(c, db, n, 0, 0, sslgen);
237 }
238 
239 static Chan*
240 sslopen(Chan *c, int omode)
241 {
242 	Dstate *s, **pp;
243 	int perm;
244 
245 	perm = 0;
246 	omode &= 3;
247 	switch(omode) {
248 	case OREAD:
249 		perm = 4;
250 		break;
251 	case OWRITE:
252 		perm = 2;
253 		break;
254 	case ORDWR:
255 		perm = 6;
256 		break;
257 	}
258 
259 	switch(TYPE(c->qid)) {
260 	default:
261 		panic("sslopen");
262 	case Qtopdir:
263 	case Qconvdir:
264 		if(omode != OREAD)
265 			error(Eperm);
266 		break;
267 	case Qclonus:
268 		s = dsclone(c);
269 		if(s == 0)
270 			error(Enodev);
271 		break;
272 	case Qctl:
273 	case Qdata:
274 	case Qsecretin:
275 	case Qsecretout:
276 		if(waserror()) {
277 			unlock(&dslock);
278 			nexterror();
279 		}
280 		lock(&dslock);
281 		pp = &dstate[CONV(c->qid)];
282 		s = *pp;
283 		if(s == 0)
284 			dsnew(c, pp);
285 		else {
286 			if((perm & (s->perm>>6)) != perm
287 			   && (strcmp(up->env->user, s->user) != 0
288 			     || (perm & s->perm) != perm))
289 				error(Eperm);
290 
291 			s->ref++;
292 		}
293 		unlock(&dslock);
294 		poperror();
295 		break;
296 	case Qencalgs:
297 	case Qhashalgs:
298 		if(omode != OREAD)
299 			error(Eperm);
300 		break;
301 	}
302 	c->mode = openmode(omode);
303 	c->flag |= COPEN;
304 	c->offset = 0;
305 	return c;
306 }
307 
308 static int
309 sslwstat(Chan *c, uchar *dp, int n)
310 {
311 	Dir d;
312 	Dstate *s;
313 
314 	n = convM2D(dp, n, &d, nil);
315 	if(n == 0)
316 		error(Eshortstat);
317 	s = dstate[CONV(c->qid)];
318 	if(s == 0)
319 		error(Ebadusefd);
320 	if(strcmp(s->user, up->env->user) != 0)
321 		error(Eperm);
322 	if(!emptystr(d.uid))
323 		kstrdup(&s->user, d.uid);
324 	if(d.mode != ~0UL)
325 		s->perm = d.mode;
326 	return n;
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 Dstate*
1375 dsclone(Chan *ch)
1376 {
1377 	Dstate **pp, **ep, **np;
1378 	int newmax;
1379 
1380 	if(waserror()) {
1381 		unlock(&dslock);
1382 		nexterror();
1383 	}
1384 	lock(&dslock);
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 			unlock(&dslock);
1395 			poperror();
1396 			return 0;
1397 		}
1398 		newmax = 2 * maxdstate;
1399 		if(newmax > Maxdstate)
1400 			newmax = Maxdstate;
1401 		np = realloc(dstate, sizeof(Dstate*) * newmax);
1402 		if(np == 0)
1403 			error(Enomem);
1404 		dstate = np;
1405 		pp = &dstate[maxdstate];
1406 		memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate));
1407 		maxdstate = newmax;
1408 		dsnew(ch, pp);
1409 	}
1410 	unlock(&dslock);
1411 	poperror();
1412 	return *pp;
1413 }
1414 
1415 static void
1416 dsnew(Chan *ch, Dstate **pp)
1417 {
1418 	Dstate *s;
1419 	int t;
1420 
1421 	*pp = s = malloc(sizeof(*s));
1422 	if(!s)
1423 		error(Enomem);
1424 	if(pp - dstate >= dshiwat)
1425 		dshiwat++;
1426 	s->state = Sincomplete;
1427 	s->ref = 1;
1428 	kstrdup(&s->user, up->env->user);
1429 	s->perm = 0660;
1430 	t = TYPE(ch->qid);
1431 	if(t == Qclonus)
1432 		t = Qctl;
1433 	ch->qid.path = QID(pp - dstate, t);
1434 	ch->qid.vers = 0;
1435 	ch->qid.type = QTFILE;
1436 }
1437