xref: /inferno-os/emu/port/devssl.c (revision ad01d857a3ec149074830330005eb4c786d3330c)
137da2899SCharles.Forsyth /*
237da2899SCharles.Forsyth  *  devssl - secure sockets layer
337da2899SCharles.Forsyth  */
437da2899SCharles.Forsyth #include	"dat.h"
537da2899SCharles.Forsyth #include	"fns.h"
637da2899SCharles.Forsyth #include	"error.h"
737da2899SCharles.Forsyth 
837da2899SCharles.Forsyth #include	"mp.h"
937da2899SCharles.Forsyth #include	"libsec.h"
1037da2899SCharles.Forsyth 
1137da2899SCharles.Forsyth typedef struct OneWay OneWay;
1237da2899SCharles.Forsyth struct OneWay
1337da2899SCharles.Forsyth {
1437da2899SCharles.Forsyth 	QLock	q;
1537da2899SCharles.Forsyth 	QLock	ctlq;
1637da2899SCharles.Forsyth 
1737da2899SCharles.Forsyth 	void	*state;		/* encryption state */
1837da2899SCharles.Forsyth 	int	slen;			/* secret data length */
1937da2899SCharles.Forsyth 	uchar	*secret;	/* secret */
2037da2899SCharles.Forsyth 	ulong	mid;		/* message id */
2137da2899SCharles.Forsyth };
2237da2899SCharles.Forsyth 
2337da2899SCharles.Forsyth enum
2437da2899SCharles.Forsyth {
2537da2899SCharles.Forsyth 	/* connection states */
2637da2899SCharles.Forsyth 	Sincomplete=	0,
2737da2899SCharles.Forsyth 	Sclear=		1,
2837da2899SCharles.Forsyth 	Sencrypting=	2,
2937da2899SCharles.Forsyth 	Sdigesting=	4,
3037da2899SCharles.Forsyth 	Sdigenc=	Sencrypting|Sdigesting,
3137da2899SCharles.Forsyth 
3237da2899SCharles.Forsyth 	/* encryption algorithms */
3337da2899SCharles.Forsyth 	Noencryption=	0,
3437da2899SCharles.Forsyth 	DESCBC=		1,
3537da2899SCharles.Forsyth 	DESECB=		2,
3637da2899SCharles.Forsyth 	RC4=		3,
3737da2899SCharles.Forsyth 	IDEACBC=	4,
3837da2899SCharles.Forsyth 	IDEAECB=		5
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth 
4137da2899SCharles.Forsyth typedef struct Dstate Dstate;
4237da2899SCharles.Forsyth struct Dstate
4337da2899SCharles.Forsyth {
4437da2899SCharles.Forsyth 	Chan	*c;			/* io channel */
4537da2899SCharles.Forsyth 	uchar	state;		/* state of connection */
4637da2899SCharles.Forsyth 	int	ref;			/* serialized by dslock for atomic destroy */
4737da2899SCharles.Forsyth 
4837da2899SCharles.Forsyth 	uchar	encryptalg;	/* encryption algorithm */
4937da2899SCharles.Forsyth 	ushort	blocklen;	/* blocking length */
5037da2899SCharles.Forsyth 
5137da2899SCharles.Forsyth 	ushort	diglen;		/* length of digest */
5237da2899SCharles.Forsyth 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */
5337da2899SCharles.Forsyth 
5437da2899SCharles.Forsyth 	/* for SSL format */
5537da2899SCharles.Forsyth 	int	max;			/* maximum unpadded data per msg */
5637da2899SCharles.Forsyth 	int	maxpad;			/* maximum padded data per msg */
5737da2899SCharles.Forsyth 
5837da2899SCharles.Forsyth 	/* input side */
5937da2899SCharles.Forsyth 	OneWay	in;
6037da2899SCharles.Forsyth 	Block	*processed;
6137da2899SCharles.Forsyth 	Block	*unprocessed;
6237da2899SCharles.Forsyth 
6337da2899SCharles.Forsyth 	/* output side */
6437da2899SCharles.Forsyth 	OneWay	out;
6537da2899SCharles.Forsyth 
6637da2899SCharles.Forsyth 	/* protections */
6737da2899SCharles.Forsyth 	char*	user;
6837da2899SCharles.Forsyth 	int	perm;
6937da2899SCharles.Forsyth };
7037da2899SCharles.Forsyth 
7137da2899SCharles.Forsyth enum
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth 	Maxdmsg=	1<<16,
7437da2899SCharles.Forsyth 	Maxdstate=	1<<10,
7537da2899SCharles.Forsyth };
7637da2899SCharles.Forsyth 
7737da2899SCharles.Forsyth Lock	dslock;
7837da2899SCharles.Forsyth int	dshiwat;
7937da2899SCharles.Forsyth int	maxdstate = 20;
8037da2899SCharles.Forsyth Dstate** dstate;
8137da2899SCharles.Forsyth 
8237da2899SCharles.Forsyth enum{
8337da2899SCharles.Forsyth 	Qtopdir		= 1,	/* top level directory */
8437da2899SCharles.Forsyth 	Qclonus,
8537da2899SCharles.Forsyth 	Qconvdir,			/* directory for a conversation */
8637da2899SCharles.Forsyth 	Qdata,
8737da2899SCharles.Forsyth 	Qctl,
8837da2899SCharles.Forsyth 	Qsecretin,
8937da2899SCharles.Forsyth 	Qsecretout,
9037da2899SCharles.Forsyth 	Qencalgs,
9137da2899SCharles.Forsyth 	Qhashalgs
9237da2899SCharles.Forsyth };
9337da2899SCharles.Forsyth 
9437da2899SCharles.Forsyth #define TYPE(x) 	((ulong)(x).path & 0xf)
9537da2899SCharles.Forsyth #define CONV(x) 	(((ulong)(x).path >> 4)&(Maxdstate-1))
9637da2899SCharles.Forsyth #define QID(c, y) 	(((c)<<4) | (y))
9737da2899SCharles.Forsyth 
9837da2899SCharles.Forsyth static char*	encalgs;
9937da2899SCharles.Forsyth static char*	hashalgs;
10037da2899SCharles.Forsyth 
10137da2899SCharles.Forsyth void producerand(void);
10237da2899SCharles.Forsyth 
10337da2899SCharles.Forsyth static void alglistinit(void);
10437da2899SCharles.Forsyth static void	ensure(Dstate*, Block**, int);
10537da2899SCharles.Forsyth static void	consume(Block**, uchar*, int);
10637da2899SCharles.Forsyth static void	setsecret(OneWay*, uchar*, int);
10737da2899SCharles.Forsyth static Block*	encryptb(Dstate*, Block*, int);
10837da2899SCharles.Forsyth static Block*	decryptb(Dstate*, Block*);
10937da2899SCharles.Forsyth static Block*	digestb(Dstate*, Block*, int);
11037da2899SCharles.Forsyth static void	checkdigestb(Dstate*, Block*);
11137da2899SCharles.Forsyth static Chan*	buftochan(char*);
11237da2899SCharles.Forsyth static void	sslhangup(Dstate*);
113*ad01d857SCharles.Forsyth static void dsclone(Chan *c);
11437da2899SCharles.Forsyth static void	dsnew(Chan *c, Dstate **);
11537da2899SCharles.Forsyth 
11637da2899SCharles.Forsyth static int
sslgen(Chan * c,char * dname,Dirtab * d,int nd,int s,Dir * dp)11737da2899SCharles.Forsyth sslgen(Chan *c, char *dname, Dirtab *d, int nd, int s, Dir *dp)
11837da2899SCharles.Forsyth {
11937da2899SCharles.Forsyth 	Qid q;
12037da2899SCharles.Forsyth 	Dstate *ds;
121*ad01d857SCharles.Forsyth 	char *p, *nm;
12237da2899SCharles.Forsyth 
12337da2899SCharles.Forsyth 	USED(dname);
12437da2899SCharles.Forsyth 	USED(nd);
12537da2899SCharles.Forsyth 	USED(d);
12637da2899SCharles.Forsyth 	q.type = QTFILE;
12737da2899SCharles.Forsyth 	q.vers = 0;
12837da2899SCharles.Forsyth 	if(s == DEVDOTDOT){
12937da2899SCharles.Forsyth 		q.path = QID(0, Qtopdir);
13037da2899SCharles.Forsyth 		q.type = QTDIR;
13137da2899SCharles.Forsyth 		devdir(c, q, "#D", 0, eve, 0555, dp);
13237da2899SCharles.Forsyth 		return 1;
13337da2899SCharles.Forsyth 	}
13437da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
13537da2899SCharles.Forsyth 	case Qtopdir:
13637da2899SCharles.Forsyth 		if(s < dshiwat) {
13737da2899SCharles.Forsyth 			q.path = QID(s, Qconvdir);
13837da2899SCharles.Forsyth 			q.type = QTDIR;
13937da2899SCharles.Forsyth 			ds = dstate[s];
14037da2899SCharles.Forsyth 			if(ds != 0)
14137da2899SCharles.Forsyth  				nm = ds->user;
14237da2899SCharles.Forsyth  			else
14337da2899SCharles.Forsyth  				nm = eve;
144*ad01d857SCharles.Forsyth 			snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
145*ad01d857SCharles.Forsyth 			devdir(c, q, up->genbuf, 0, nm, DMDIR|0555, dp);
14637da2899SCharles.Forsyth 			return 1;
14737da2899SCharles.Forsyth 		}
14837da2899SCharles.Forsyth 		if(s > dshiwat)
14937da2899SCharles.Forsyth 			return -1;
15037da2899SCharles.Forsyth 		/* fall through */
15137da2899SCharles.Forsyth 	case Qclonus:
15237da2899SCharles.Forsyth 		q.path = QID(0, Qclonus);
15337da2899SCharles.Forsyth 		devdir(c, q, "clone", 0, eve, 0666, dp);
15437da2899SCharles.Forsyth 		return 1;
15537da2899SCharles.Forsyth 	case Qconvdir:
15637da2899SCharles.Forsyth 		ds = dstate[CONV(c->qid)];
15737da2899SCharles.Forsyth 		if(ds != 0)
15837da2899SCharles.Forsyth 			nm = ds->user;
15937da2899SCharles.Forsyth 		else
16037da2899SCharles.Forsyth 			nm = eve;
16137da2899SCharles.Forsyth 		switch(s) {
16237da2899SCharles.Forsyth 		default:
16337da2899SCharles.Forsyth 			return -1;
16437da2899SCharles.Forsyth 		case 0:
16537da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qctl);
16637da2899SCharles.Forsyth 			p = "ctl";
16737da2899SCharles.Forsyth 			break;
16837da2899SCharles.Forsyth 		case 1:
16937da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qdata);
17037da2899SCharles.Forsyth 			p = "data";
17137da2899SCharles.Forsyth 			break;
17237da2899SCharles.Forsyth 		case 2:
17337da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qsecretin);
17437da2899SCharles.Forsyth 			p = "secretin";
17537da2899SCharles.Forsyth 			break;
17637da2899SCharles.Forsyth 		case 3:
17737da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qsecretout);
17837da2899SCharles.Forsyth 			p = "secretout";
17937da2899SCharles.Forsyth 			break;
18037da2899SCharles.Forsyth 		case 4:
18137da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qencalgs);
18237da2899SCharles.Forsyth 			p = "encalgs";
18337da2899SCharles.Forsyth 			break;
18437da2899SCharles.Forsyth 		case 5:
18537da2899SCharles.Forsyth 			q.path = QID(CONV(c->qid), Qhashalgs);
18637da2899SCharles.Forsyth 			p = "hashalgs";
18737da2899SCharles.Forsyth 			break;
18837da2899SCharles.Forsyth 		}
18937da2899SCharles.Forsyth 		devdir(c, q, p, 0, nm, 0660, dp);
19037da2899SCharles.Forsyth 		return 1;
19137da2899SCharles.Forsyth 	}
19237da2899SCharles.Forsyth 	return -1;
19337da2899SCharles.Forsyth }
19437da2899SCharles.Forsyth 
19537da2899SCharles.Forsyth static void
sslinit(void)19637da2899SCharles.Forsyth sslinit(void)
19737da2899SCharles.Forsyth {
19837da2899SCharles.Forsyth 	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
19937da2899SCharles.Forsyth 		panic("sslinit");
20037da2899SCharles.Forsyth 	alglistinit();
20137da2899SCharles.Forsyth }
20237da2899SCharles.Forsyth 
20337da2899SCharles.Forsyth static Chan *
sslattach(char * spec)20437da2899SCharles.Forsyth sslattach(char *spec)
20537da2899SCharles.Forsyth {
20637da2899SCharles.Forsyth 	Chan *c;
20737da2899SCharles.Forsyth 
20837da2899SCharles.Forsyth 	c = devattach('D', spec);
20937da2899SCharles.Forsyth 	c->qid.path = QID(0, Qtopdir);
21037da2899SCharles.Forsyth 	c->qid.vers = 0;
21137da2899SCharles.Forsyth 	c->qid.type = QTDIR;
21237da2899SCharles.Forsyth 	return c;
21337da2899SCharles.Forsyth }
21437da2899SCharles.Forsyth 
21537da2899SCharles.Forsyth static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)21637da2899SCharles.Forsyth sslwalk(Chan *c, Chan *nc, char **name, int nname)
21737da2899SCharles.Forsyth {
21837da2899SCharles.Forsyth 	return devwalk(c, nc, name, nname, 0, 0, sslgen);
21937da2899SCharles.Forsyth }
22037da2899SCharles.Forsyth 
22137da2899SCharles.Forsyth static int
sslstat(Chan * c,uchar * db,int n)22237da2899SCharles.Forsyth sslstat(Chan *c, uchar *db, int n)
22337da2899SCharles.Forsyth {
22437da2899SCharles.Forsyth 	return devstat(c, db, n, 0, 0, sslgen);
22537da2899SCharles.Forsyth }
22637da2899SCharles.Forsyth 
22737da2899SCharles.Forsyth static Chan*
sslopen(Chan * c,int omode)22837da2899SCharles.Forsyth sslopen(Chan *c, int omode)
22937da2899SCharles.Forsyth {
23037da2899SCharles.Forsyth 	Dstate *s, **pp;
23137da2899SCharles.Forsyth 	int perm;
23237da2899SCharles.Forsyth 
23337da2899SCharles.Forsyth 	perm = 0;
23437da2899SCharles.Forsyth 	omode &= 3;
23537da2899SCharles.Forsyth 	switch(omode) {
23637da2899SCharles.Forsyth 	case OREAD:
23737da2899SCharles.Forsyth 		perm = 4;
23837da2899SCharles.Forsyth 		break;
23937da2899SCharles.Forsyth 	case OWRITE:
24037da2899SCharles.Forsyth 		perm = 2;
24137da2899SCharles.Forsyth 		break;
24237da2899SCharles.Forsyth 	case ORDWR:
24337da2899SCharles.Forsyth 		perm = 6;
24437da2899SCharles.Forsyth 		break;
24537da2899SCharles.Forsyth 	}
24637da2899SCharles.Forsyth 
24737da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
24837da2899SCharles.Forsyth 	default:
24937da2899SCharles.Forsyth 		panic("sslopen");
25037da2899SCharles.Forsyth 	case Qtopdir:
25137da2899SCharles.Forsyth 	case Qconvdir:
25237da2899SCharles.Forsyth 		if(omode != OREAD)
25337da2899SCharles.Forsyth 			error(Eperm);
25437da2899SCharles.Forsyth 		break;
25537da2899SCharles.Forsyth 	case Qclonus:
256*ad01d857SCharles.Forsyth 		dsclone(c);
25737da2899SCharles.Forsyth 		break;
25837da2899SCharles.Forsyth 	case Qctl:
25937da2899SCharles.Forsyth 	case Qdata:
26037da2899SCharles.Forsyth 	case Qsecretin:
26137da2899SCharles.Forsyth 	case Qsecretout:
26237da2899SCharles.Forsyth 		if(waserror()) {
26337da2899SCharles.Forsyth 			unlock(&dslock);
26437da2899SCharles.Forsyth 			nexterror();
26537da2899SCharles.Forsyth 		}
26637da2899SCharles.Forsyth 		lock(&dslock);
26737da2899SCharles.Forsyth 		pp = &dstate[CONV(c->qid)];
26837da2899SCharles.Forsyth 		s = *pp;
26937da2899SCharles.Forsyth 		if(s == 0)
27037da2899SCharles.Forsyth 			dsnew(c, pp);
27137da2899SCharles.Forsyth 		else {
27237da2899SCharles.Forsyth 			if((perm & (s->perm>>6)) != perm
27337da2899SCharles.Forsyth 			   && (strcmp(up->env->user, s->user) != 0
27437da2899SCharles.Forsyth 			     || (perm & s->perm) != perm))
27537da2899SCharles.Forsyth 				error(Eperm);
27637da2899SCharles.Forsyth 
27737da2899SCharles.Forsyth 			s->ref++;
27837da2899SCharles.Forsyth 		}
27937da2899SCharles.Forsyth 		unlock(&dslock);
28037da2899SCharles.Forsyth 		poperror();
28137da2899SCharles.Forsyth 		break;
28237da2899SCharles.Forsyth 	case Qencalgs:
28337da2899SCharles.Forsyth 	case Qhashalgs:
28437da2899SCharles.Forsyth 		if(omode != OREAD)
28537da2899SCharles.Forsyth 			error(Eperm);
28637da2899SCharles.Forsyth 		break;
28737da2899SCharles.Forsyth 	}
28837da2899SCharles.Forsyth 	c->mode = openmode(omode);
28937da2899SCharles.Forsyth 	c->flag |= COPEN;
29037da2899SCharles.Forsyth 	c->offset = 0;
29137da2899SCharles.Forsyth 	return c;
29237da2899SCharles.Forsyth }
29337da2899SCharles.Forsyth 
29437da2899SCharles.Forsyth static int
sslwstat(Chan * c,uchar * db,int n)295*ad01d857SCharles.Forsyth sslwstat(Chan *c, uchar *db, int n)
29637da2899SCharles.Forsyth {
297*ad01d857SCharles.Forsyth 	Dir *dir;
29837da2899SCharles.Forsyth 	Dstate *s;
299*ad01d857SCharles.Forsyth 	int m;
30037da2899SCharles.Forsyth 
30137da2899SCharles.Forsyth 	s = dstate[CONV(c->qid)];
30237da2899SCharles.Forsyth 	if(s == 0)
30337da2899SCharles.Forsyth 		error(Ebadusefd);
30437da2899SCharles.Forsyth 	if(strcmp(s->user, up->env->user) != 0)
30537da2899SCharles.Forsyth 		error(Eperm);
306*ad01d857SCharles.Forsyth 
307*ad01d857SCharles.Forsyth 	dir = smalloc(sizeof(Dir)+n);
308*ad01d857SCharles.Forsyth 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
309*ad01d857SCharles.Forsyth 	if(m == 0){
310*ad01d857SCharles.Forsyth 		free(dir);
311*ad01d857SCharles.Forsyth 		error(Eshortstat);
312*ad01d857SCharles.Forsyth 	}
313*ad01d857SCharles.Forsyth 
314*ad01d857SCharles.Forsyth 	if(!emptystr(dir->uid))
315*ad01d857SCharles.Forsyth 		kstrdup(&s->user, dir->uid);
316*ad01d857SCharles.Forsyth 	if(dir->mode != ~0UL)
317*ad01d857SCharles.Forsyth 		s->perm = dir->mode;
318*ad01d857SCharles.Forsyth 
319*ad01d857SCharles.Forsyth 	free(dir);
320*ad01d857SCharles.Forsyth 	return m;
32137da2899SCharles.Forsyth }
32237da2899SCharles.Forsyth 
32337da2899SCharles.Forsyth static void
sslclose(Chan * c)32437da2899SCharles.Forsyth sslclose(Chan *c)
32537da2899SCharles.Forsyth {
32637da2899SCharles.Forsyth 	Dstate *s;
32737da2899SCharles.Forsyth 
32837da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
32937da2899SCharles.Forsyth 	case Qctl:
33037da2899SCharles.Forsyth 	case Qdata:
33137da2899SCharles.Forsyth 	case Qsecretin:
33237da2899SCharles.Forsyth 	case Qsecretout:
33337da2899SCharles.Forsyth 		if((c->flag & COPEN) == 0)
33437da2899SCharles.Forsyth 			break;
33537da2899SCharles.Forsyth 
33637da2899SCharles.Forsyth 		s = dstate[CONV(c->qid)];
33737da2899SCharles.Forsyth 		if(s == 0)
33837da2899SCharles.Forsyth 			break;
33937da2899SCharles.Forsyth 
34037da2899SCharles.Forsyth 		lock(&dslock);
34137da2899SCharles.Forsyth 		if(--s->ref > 0) {
34237da2899SCharles.Forsyth 			unlock(&dslock);
34337da2899SCharles.Forsyth 			break;
34437da2899SCharles.Forsyth 		}
34537da2899SCharles.Forsyth 		dstate[CONV(c->qid)] = 0;
34637da2899SCharles.Forsyth 		unlock(&dslock);
34737da2899SCharles.Forsyth 
34837da2899SCharles.Forsyth 		sslhangup(s);
34937da2899SCharles.Forsyth 		if(s->c)
35037da2899SCharles.Forsyth 			cclose(s->c);
35137da2899SCharles.Forsyth 		free(s->user);
35237da2899SCharles.Forsyth 		free(s->in.secret);
35337da2899SCharles.Forsyth 		free(s->out.secret);
35437da2899SCharles.Forsyth 		free(s->in.state);
35537da2899SCharles.Forsyth 		free(s->out.state);
35637da2899SCharles.Forsyth 		free(s);
35737da2899SCharles.Forsyth 	}
35837da2899SCharles.Forsyth }
35937da2899SCharles.Forsyth 
36037da2899SCharles.Forsyth /*
36137da2899SCharles.Forsyth  *  make sure we have at least 'n' bytes in list 'l'
36237da2899SCharles.Forsyth  */
36337da2899SCharles.Forsyth static void
ensure(Dstate * s,Block ** l,int n)36437da2899SCharles.Forsyth ensure(Dstate *s, Block **l, int n)
36537da2899SCharles.Forsyth {
36637da2899SCharles.Forsyth 	int sofar, i;
36737da2899SCharles.Forsyth 	Block *b, *bl;
36837da2899SCharles.Forsyth 
36937da2899SCharles.Forsyth 	sofar = 0;
37037da2899SCharles.Forsyth 	for(b = *l; b; b = b->next){
37137da2899SCharles.Forsyth 		sofar += BLEN(b);
37237da2899SCharles.Forsyth 		if(sofar >= n)
37337da2899SCharles.Forsyth 			return;
37437da2899SCharles.Forsyth 		l = &b->next;
37537da2899SCharles.Forsyth 	}
37637da2899SCharles.Forsyth 
37737da2899SCharles.Forsyth 	while(sofar < n){
37837da2899SCharles.Forsyth 		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
37937da2899SCharles.Forsyth 		if(bl == 0)
38037da2899SCharles.Forsyth 			error(Ehungup);
38137da2899SCharles.Forsyth 		*l = bl;
38237da2899SCharles.Forsyth 		i = 0;
38337da2899SCharles.Forsyth 		for(b = bl; b; b = b->next){
38437da2899SCharles.Forsyth 			i += BLEN(b);
38537da2899SCharles.Forsyth 			l = &b->next;
38637da2899SCharles.Forsyth 		}
38737da2899SCharles.Forsyth 		if(i == 0)
38837da2899SCharles.Forsyth 			error(Ehungup);
38937da2899SCharles.Forsyth 
39037da2899SCharles.Forsyth 		sofar += i;
39137da2899SCharles.Forsyth 	}
39237da2899SCharles.Forsyth }
39337da2899SCharles.Forsyth 
39437da2899SCharles.Forsyth /*
39537da2899SCharles.Forsyth  *  copy 'n' bytes from 'l' into 'p' and free
39637da2899SCharles.Forsyth  *  the bytes in 'l'
39737da2899SCharles.Forsyth  */
39837da2899SCharles.Forsyth static void
consume(Block ** l,uchar * p,int n)39937da2899SCharles.Forsyth consume(Block **l, uchar *p, int n)
40037da2899SCharles.Forsyth {
40137da2899SCharles.Forsyth 	Block *b;
40237da2899SCharles.Forsyth 	int i;
40337da2899SCharles.Forsyth 
40437da2899SCharles.Forsyth 	for(; *l && n > 0; n -= i){
40537da2899SCharles.Forsyth 		b = *l;
40637da2899SCharles.Forsyth 		i = BLEN(b);
40737da2899SCharles.Forsyth 		if(i > n)
40837da2899SCharles.Forsyth 			i = n;
40937da2899SCharles.Forsyth 		memmove(p, b->rp, i);
41037da2899SCharles.Forsyth 		b->rp += i;
41137da2899SCharles.Forsyth 		p += i;
41237da2899SCharles.Forsyth 		if(BLEN(b) < 0)
41337da2899SCharles.Forsyth 			panic("consume");
41437da2899SCharles.Forsyth 		if(BLEN(b))
41537da2899SCharles.Forsyth 			break;
41637da2899SCharles.Forsyth 		*l = b->next;
41737da2899SCharles.Forsyth 		freeb(b);
41837da2899SCharles.Forsyth 	}
41937da2899SCharles.Forsyth }
42037da2899SCharles.Forsyth 
42137da2899SCharles.Forsyth /*
42237da2899SCharles.Forsyth  *  remove at most n bytes from the queue, if discard is set
42337da2899SCharles.Forsyth  *  dump the remainder
42437da2899SCharles.Forsyth  */
42537da2899SCharles.Forsyth static Block*
qtake(Block ** l,int n,int discard)42637da2899SCharles.Forsyth qtake(Block **l, int n, int discard)
42737da2899SCharles.Forsyth {
42837da2899SCharles.Forsyth 	Block *nb, *b, *first;
42937da2899SCharles.Forsyth 	int i;
43037da2899SCharles.Forsyth 
43137da2899SCharles.Forsyth 	first = *l;
43237da2899SCharles.Forsyth 	for(b = first; b; b = b->next){
43337da2899SCharles.Forsyth 		i = BLEN(b);
43437da2899SCharles.Forsyth 		if(i == n){
43537da2899SCharles.Forsyth 			if(discard){
43637da2899SCharles.Forsyth 				freeblist(b->next);
43737da2899SCharles.Forsyth 				*l = 0;
43837da2899SCharles.Forsyth 			} else
43937da2899SCharles.Forsyth 				*l = b->next;
44037da2899SCharles.Forsyth 			b->next = 0;
44137da2899SCharles.Forsyth 			return first;
44237da2899SCharles.Forsyth 		} else if(i > n){
44337da2899SCharles.Forsyth 			i -= n;
44437da2899SCharles.Forsyth 			if(discard){
44537da2899SCharles.Forsyth 				freeblist(b->next);
44637da2899SCharles.Forsyth 				*l = 0;
44737da2899SCharles.Forsyth 			} else {
44837da2899SCharles.Forsyth 				nb = allocb(i);
44937da2899SCharles.Forsyth 				memmove(nb->wp, b->rp+n, i);
45037da2899SCharles.Forsyth 				nb->wp += i;
45137da2899SCharles.Forsyth 				nb->next = b->next;
45237da2899SCharles.Forsyth 				*l = nb;
45337da2899SCharles.Forsyth 			}
45437da2899SCharles.Forsyth 			b->wp -= i;
45537da2899SCharles.Forsyth 			b->next = 0;
45637da2899SCharles.Forsyth 			if(BLEN(b) < 0)
45737da2899SCharles.Forsyth 				panic("qtake");
45837da2899SCharles.Forsyth 			return first;
45937da2899SCharles.Forsyth 		} else
46037da2899SCharles.Forsyth 			n -= i;
46137da2899SCharles.Forsyth 		if(BLEN(b) < 0)
46237da2899SCharles.Forsyth 			panic("qtake");
46337da2899SCharles.Forsyth 	}
46437da2899SCharles.Forsyth 	*l = 0;
46537da2899SCharles.Forsyth 	return first;
46637da2899SCharles.Forsyth }
46737da2899SCharles.Forsyth 
46837da2899SCharles.Forsyth static Block*
sslbread(Chan * c,long n,ulong offset)46937da2899SCharles.Forsyth sslbread(Chan *c, long n, ulong offset)
47037da2899SCharles.Forsyth {
47137da2899SCharles.Forsyth 	volatile struct { Dstate *s; } s;
47237da2899SCharles.Forsyth 	volatile struct { int nc; } nc;
47337da2899SCharles.Forsyth 	Block *b;
47437da2899SCharles.Forsyth 	uchar count[3];
47537da2899SCharles.Forsyth 	int len, pad;
47637da2899SCharles.Forsyth 
47737da2899SCharles.Forsyth 	USED(offset);
47837da2899SCharles.Forsyth 	s.s = dstate[CONV(c->qid)];
47937da2899SCharles.Forsyth 	if(s.s == 0)
48037da2899SCharles.Forsyth 		panic("sslbread");
48137da2899SCharles.Forsyth 	if(s.s->state == Sincomplete)
48237da2899SCharles.Forsyth 		error(Ebadusefd);
48337da2899SCharles.Forsyth 
48437da2899SCharles.Forsyth 	nc.nc = 0;
48537da2899SCharles.Forsyth 	if(waserror()){
48637da2899SCharles.Forsyth 		qunlock(&s.s->in.q);
48737da2899SCharles.Forsyth 		if(strcmp(up->env->errstr, "interrupted") == 0){
48837da2899SCharles.Forsyth 			if(nc.nc > 0){
48937da2899SCharles.Forsyth 				b = allocb(nc.nc);
49037da2899SCharles.Forsyth 				memmove(b->wp, count, nc.nc);
49137da2899SCharles.Forsyth 				b->wp += nc.nc;
49237da2899SCharles.Forsyth 				b->next = s.s->unprocessed;
49337da2899SCharles.Forsyth 				s.s->unprocessed = b;
49437da2899SCharles.Forsyth 			}
49537da2899SCharles.Forsyth 		} else
49637da2899SCharles.Forsyth 			sslhangup(s.s);
49737da2899SCharles.Forsyth 		nexterror();
49837da2899SCharles.Forsyth 	}
49937da2899SCharles.Forsyth 	qlock(&s.s->in.q);
50037da2899SCharles.Forsyth 
50137da2899SCharles.Forsyth 	if(s.s->processed == 0){
50237da2899SCharles.Forsyth 		/* read in the whole message */
50337da2899SCharles.Forsyth 		ensure(s.s, &s.s->unprocessed, 2);
50437da2899SCharles.Forsyth 
50537da2899SCharles.Forsyth 		consume(&s.s->unprocessed, count, 2);
50637da2899SCharles.Forsyth 		nc.nc += 2;
50737da2899SCharles.Forsyth 		if(count[0] & 0x80){
50837da2899SCharles.Forsyth 			len = ((count[0] & 0x7f)<<8) | count[1];
50937da2899SCharles.Forsyth 			ensure(s.s, &s.s->unprocessed, len);
51037da2899SCharles.Forsyth 			pad = 0;
51137da2899SCharles.Forsyth 		} else {
51237da2899SCharles.Forsyth 			len = ((count[0] & 0x3f)<<8) | count[1];
51337da2899SCharles.Forsyth 			ensure(s.s, &s.s->unprocessed, len+1);
51437da2899SCharles.Forsyth 			consume(&s.s->unprocessed, count + nc.nc, 1);
51537da2899SCharles.Forsyth 			pad = count[nc.nc];
51637da2899SCharles.Forsyth 			nc.nc++;
51737da2899SCharles.Forsyth 			if(pad > len){
51837da2899SCharles.Forsyth 				print("pad %d buf len %d\n", pad, len);
51937da2899SCharles.Forsyth 				error("bad pad in ssl message");
52037da2899SCharles.Forsyth 			}
52137da2899SCharles.Forsyth 		}
52237da2899SCharles.Forsyth 		nc.nc = 0;
52337da2899SCharles.Forsyth 
52437da2899SCharles.Forsyth 		/* put extra on unprocessed queue */
52537da2899SCharles.Forsyth 		s.s->processed = qtake(&s.s->unprocessed, len, 0);
52637da2899SCharles.Forsyth 
52737da2899SCharles.Forsyth 		if(waserror()){
52837da2899SCharles.Forsyth 			qunlock(&s.s->in.ctlq);
52937da2899SCharles.Forsyth 			nexterror();
53037da2899SCharles.Forsyth 		}
53137da2899SCharles.Forsyth 		qlock(&s.s->in.ctlq);
53237da2899SCharles.Forsyth 		switch(s.s->state){
53337da2899SCharles.Forsyth 		case Sencrypting:
53437da2899SCharles.Forsyth 			s.s->processed = decryptb(s.s, s.s->processed);
53537da2899SCharles.Forsyth 			break;
53637da2899SCharles.Forsyth 		case Sdigesting:
53737da2899SCharles.Forsyth 			s.s->processed = pullupblock(s.s->processed, s.s->diglen);
53837da2899SCharles.Forsyth 			if(s.s->processed == 0)
53937da2899SCharles.Forsyth 				error("ssl message too short");
54037da2899SCharles.Forsyth 			checkdigestb(s.s, s.s->processed);
54137da2899SCharles.Forsyth 			s.s->processed->rp += s.s->diglen;
54237da2899SCharles.Forsyth 			break;
54337da2899SCharles.Forsyth 		case Sdigenc:
54437da2899SCharles.Forsyth 			s.s->processed = decryptb(s.s, s.s->processed);
54537da2899SCharles.Forsyth 			s.s->processed = pullupblock(s.s->processed, s.s->diglen);
54637da2899SCharles.Forsyth 			if(s.s->processed == 0)
54737da2899SCharles.Forsyth 				error("ssl message too short");
54837da2899SCharles.Forsyth 			checkdigestb(s.s, s.s->processed);
54937da2899SCharles.Forsyth 			s.s->processed->rp += s.s->diglen;
55037da2899SCharles.Forsyth 			len -= s.s->diglen;
55137da2899SCharles.Forsyth 			break;
55237da2899SCharles.Forsyth 		}
55337da2899SCharles.Forsyth 		s.s->in.mid++;
55437da2899SCharles.Forsyth 		qunlock(&s.s->in.ctlq);
55537da2899SCharles.Forsyth 		poperror();
55637da2899SCharles.Forsyth 
55737da2899SCharles.Forsyth 		/* remove pad */
55837da2899SCharles.Forsyth 		if(pad)
55937da2899SCharles.Forsyth 			s.s->processed = qtake(&s.s->processed, len - pad, 1);
56037da2899SCharles.Forsyth 	}
56137da2899SCharles.Forsyth 
56237da2899SCharles.Forsyth 	/* return at most what was asked for */
56337da2899SCharles.Forsyth 	b = qtake(&s.s->processed, n, 0);
56437da2899SCharles.Forsyth 
56537da2899SCharles.Forsyth 	qunlock(&s.s->in.q);
56637da2899SCharles.Forsyth 	poperror();
56737da2899SCharles.Forsyth 
56837da2899SCharles.Forsyth 	return b;
56937da2899SCharles.Forsyth }
57037da2899SCharles.Forsyth 
57137da2899SCharles.Forsyth static long
sslread(Chan * c,void * a,long n,vlong offset)57237da2899SCharles.Forsyth sslread(Chan *c, void *a, long n, vlong offset)
57337da2899SCharles.Forsyth {
57437da2899SCharles.Forsyth 	volatile struct { Block *b; } b;
57537da2899SCharles.Forsyth 	Block *nb;
57637da2899SCharles.Forsyth 	uchar *va;
57737da2899SCharles.Forsyth 	int i;
57837da2899SCharles.Forsyth 	char buf[128];
57937da2899SCharles.Forsyth 
58037da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
58137da2899SCharles.Forsyth 		return devdirread(c, a, n, 0, 0, sslgen);
58237da2899SCharles.Forsyth 
58337da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
58437da2899SCharles.Forsyth 	default:
58537da2899SCharles.Forsyth 		error(Ebadusefd);
58637da2899SCharles.Forsyth 	case Qctl:
58737da2899SCharles.Forsyth 		sprint(buf, "%ld", CONV(c->qid));
58837da2899SCharles.Forsyth 		return readstr(offset, a, n, buf);
58937da2899SCharles.Forsyth 	case Qdata:
59037da2899SCharles.Forsyth 		b.b = sslbread(c, n, offset);
59137da2899SCharles.Forsyth 		break;
59237da2899SCharles.Forsyth 	case Qencalgs:
59337da2899SCharles.Forsyth 		return readstr(offset, a, n, encalgs);
59437da2899SCharles.Forsyth 	case Qhashalgs:
59537da2899SCharles.Forsyth 		return readstr(offset, a, n, hashalgs);
59637da2899SCharles.Forsyth 	}
59737da2899SCharles.Forsyth 
59837da2899SCharles.Forsyth 	n = 0;
59937da2899SCharles.Forsyth 	va = a;
60037da2899SCharles.Forsyth 	for(nb = b.b; nb; nb = nb->next){
60137da2899SCharles.Forsyth 		i = BLEN(nb);
60237da2899SCharles.Forsyth 		memmove(va+n, nb->rp, i);
60337da2899SCharles.Forsyth 		n += i;
60437da2899SCharles.Forsyth 	}
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth 	freeblist(b.b);
60737da2899SCharles.Forsyth 
60837da2899SCharles.Forsyth 	return n;
60937da2899SCharles.Forsyth }
61037da2899SCharles.Forsyth 
61137da2899SCharles.Forsyth /*
61237da2899SCharles.Forsyth  *  this algorithm doesn't have to be great since we're just
61337da2899SCharles.Forsyth  *  trying to obscure the block fill
61437da2899SCharles.Forsyth  */
61537da2899SCharles.Forsyth static void
randfill(uchar * buf,int len)61637da2899SCharles.Forsyth randfill(uchar *buf, int len)
61737da2899SCharles.Forsyth {
61837da2899SCharles.Forsyth 	while(len-- > 0)
61937da2899SCharles.Forsyth 		*buf++ = nrand(256);
62037da2899SCharles.Forsyth }
62137da2899SCharles.Forsyth 
62237da2899SCharles.Forsyth /*
62337da2899SCharles.Forsyth  *  use SSL record format, add in count and digest or encrypt
62437da2899SCharles.Forsyth  */
62537da2899SCharles.Forsyth static long
sslbwrite(Chan * c,Block * b,ulong offset)62637da2899SCharles.Forsyth sslbwrite(Chan *c, Block *b, ulong offset)
62737da2899SCharles.Forsyth {
62837da2899SCharles.Forsyth 	volatile struct { Dstate *s; } s;
62937da2899SCharles.Forsyth 	volatile struct { Block *b; } bb;
63037da2899SCharles.Forsyth 	Block *nb;
63137da2899SCharles.Forsyth 	int h, n, m, pad, rv;
63237da2899SCharles.Forsyth 	uchar *p;
63337da2899SCharles.Forsyth 
63437da2899SCharles.Forsyth 	bb.b = b;
63537da2899SCharles.Forsyth 	s.s = dstate[CONV(c->qid)];
63637da2899SCharles.Forsyth 	if(s.s == 0)
63737da2899SCharles.Forsyth 		panic("sslbwrite");
63837da2899SCharles.Forsyth 	if(s.s->state == Sincomplete){
63937da2899SCharles.Forsyth 		freeb(b);
64037da2899SCharles.Forsyth 		error(Ebadusefd);
64137da2899SCharles.Forsyth 	}
64237da2899SCharles.Forsyth 
64337da2899SCharles.Forsyth 	if(waserror()){
64437da2899SCharles.Forsyth 		qunlock(&s.s->out.q);
64537da2899SCharles.Forsyth 		if(bb.b)
64637da2899SCharles.Forsyth 			freeb(bb.b);
64737da2899SCharles.Forsyth 		sslhangup(s.s);
64837da2899SCharles.Forsyth 		nexterror();
64937da2899SCharles.Forsyth 	}
65037da2899SCharles.Forsyth 	qlock(&s.s->out.q);
65137da2899SCharles.Forsyth 
65237da2899SCharles.Forsyth 	rv = 0;
65337da2899SCharles.Forsyth 	while(bb.b){
65437da2899SCharles.Forsyth 		m = n = BLEN(bb.b);
65537da2899SCharles.Forsyth 		h = s.s->diglen + 2;
65637da2899SCharles.Forsyth 
65737da2899SCharles.Forsyth 		/* trim to maximum block size */
65837da2899SCharles.Forsyth 		pad = 0;
65937da2899SCharles.Forsyth 		if(m > s.s->max){
66037da2899SCharles.Forsyth 			m = s.s->max;
66137da2899SCharles.Forsyth 		} else if(s.s->blocklen != 1){
66237da2899SCharles.Forsyth 			pad = (m + s.s->diglen)%s.s->blocklen;
66337da2899SCharles.Forsyth 			if(pad){
66437da2899SCharles.Forsyth 				if(m > s.s->maxpad){
66537da2899SCharles.Forsyth 					pad = 0;
66637da2899SCharles.Forsyth 					m = s.s->maxpad;
66737da2899SCharles.Forsyth 				} else {
66837da2899SCharles.Forsyth 					pad = s.s->blocklen - pad;
66937da2899SCharles.Forsyth 					h++;
67037da2899SCharles.Forsyth 				}
67137da2899SCharles.Forsyth 			}
67237da2899SCharles.Forsyth 		}
67337da2899SCharles.Forsyth 
67437da2899SCharles.Forsyth 		rv += m;
67537da2899SCharles.Forsyth 		if(m != n){
67637da2899SCharles.Forsyth 			nb = allocb(m + h + pad);
67737da2899SCharles.Forsyth 			memmove(nb->wp + h, bb.b->rp, m);
67837da2899SCharles.Forsyth 			nb->wp += m + h;
67937da2899SCharles.Forsyth 			bb.b->rp += m;
68037da2899SCharles.Forsyth 		} else {
68137da2899SCharles.Forsyth 			/* add header space */
68237da2899SCharles.Forsyth 			nb = padblock(bb.b, h);
68337da2899SCharles.Forsyth 			bb.b = 0;
68437da2899SCharles.Forsyth 		}
68537da2899SCharles.Forsyth 		m += s.s->diglen;
68637da2899SCharles.Forsyth 
68737da2899SCharles.Forsyth 		/* SSLv2 style count */
68837da2899SCharles.Forsyth 		if(pad){
68937da2899SCharles.Forsyth 			nb = padblock(nb, -pad);
69037da2899SCharles.Forsyth 			randfill(nb->wp, pad);
69137da2899SCharles.Forsyth 			nb->wp += pad;
69237da2899SCharles.Forsyth 			m += pad;
69337da2899SCharles.Forsyth 
69437da2899SCharles.Forsyth 			p = nb->rp;
69537da2899SCharles.Forsyth 			p[0] = (m>>8);
69637da2899SCharles.Forsyth 			p[1] = m;
69737da2899SCharles.Forsyth 			p[2] = pad;
69837da2899SCharles.Forsyth 			offset = 3;
69937da2899SCharles.Forsyth 		} else {
70037da2899SCharles.Forsyth 			p = nb->rp;
70137da2899SCharles.Forsyth 			p[0] = (m>>8) | 0x80;
70237da2899SCharles.Forsyth 			p[1] = m;
70337da2899SCharles.Forsyth 			offset = 2;
70437da2899SCharles.Forsyth 		}
70537da2899SCharles.Forsyth 
70637da2899SCharles.Forsyth 		switch(s.s->state){
70737da2899SCharles.Forsyth 		case Sencrypting:
70837da2899SCharles.Forsyth 			nb = encryptb(s.s, nb, offset);
70937da2899SCharles.Forsyth 			break;
71037da2899SCharles.Forsyth 		case Sdigesting:
71137da2899SCharles.Forsyth 			nb = digestb(s.s, nb, offset);
71237da2899SCharles.Forsyth 			break;
71337da2899SCharles.Forsyth 		case Sdigenc:
71437da2899SCharles.Forsyth 			nb = digestb(s.s, nb, offset);
71537da2899SCharles.Forsyth 			nb = encryptb(s.s, nb, offset);
71637da2899SCharles.Forsyth 			break;
71737da2899SCharles.Forsyth 		}
71837da2899SCharles.Forsyth 
71937da2899SCharles.Forsyth 		s.s->out.mid++;
72037da2899SCharles.Forsyth 
72137da2899SCharles.Forsyth 		m = BLEN(nb);
72237da2899SCharles.Forsyth 		devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset);
72337da2899SCharles.Forsyth 		s.s->c->offset += m;
72437da2899SCharles.Forsyth 	}
72537da2899SCharles.Forsyth 	qunlock(&s.s->out.q);
72637da2899SCharles.Forsyth 	poperror();
72737da2899SCharles.Forsyth 
72837da2899SCharles.Forsyth 	return rv;
72937da2899SCharles.Forsyth }
73037da2899SCharles.Forsyth 
73137da2899SCharles.Forsyth static void
setsecret(OneWay * w,uchar * secret,int n)73237da2899SCharles.Forsyth setsecret(OneWay *w, uchar *secret, int n)
73337da2899SCharles.Forsyth {
73437da2899SCharles.Forsyth 	free(w->secret);
73537da2899SCharles.Forsyth 	w->secret = mallocz(n, 0);
73637da2899SCharles.Forsyth 	if(w->secret == nil)
73737da2899SCharles.Forsyth 		error(Enomem);
73837da2899SCharles.Forsyth 	memmove(w->secret, secret, n);
73937da2899SCharles.Forsyth 	w->slen = n;
74037da2899SCharles.Forsyth }
74137da2899SCharles.Forsyth 
74237da2899SCharles.Forsyth static void
initIDEAkey(OneWay * w)74337da2899SCharles.Forsyth initIDEAkey(OneWay *w)
74437da2899SCharles.Forsyth {
74537da2899SCharles.Forsyth 
74637da2899SCharles.Forsyth 	free(w->state);
74737da2899SCharles.Forsyth 	w->state = malloc(sizeof(IDEAstate));
74837da2899SCharles.Forsyth 	if(w->state == nil)
74937da2899SCharles.Forsyth 		error(Enomem);
75037da2899SCharles.Forsyth 	if(w->slen >= 24)
75137da2899SCharles.Forsyth 		setupIDEAstate(w->state, w->secret, w->secret+16);
75237da2899SCharles.Forsyth 	else if(w->slen >= 16)
75337da2899SCharles.Forsyth 		setupIDEAstate(w->state, w->secret, 0);
75437da2899SCharles.Forsyth 	else
75537da2899SCharles.Forsyth 		error("secret too short");
75637da2899SCharles.Forsyth }
75737da2899SCharles.Forsyth 
75837da2899SCharles.Forsyth static void
initDESkey(OneWay * w)75937da2899SCharles.Forsyth initDESkey(OneWay *w)
76037da2899SCharles.Forsyth {
76137da2899SCharles.Forsyth 
76237da2899SCharles.Forsyth 	free(w->state);
76337da2899SCharles.Forsyth 	w->state = malloc(sizeof(DESstate));
76437da2899SCharles.Forsyth 	if (!w->state)
76537da2899SCharles.Forsyth 		error(Enomem);
76637da2899SCharles.Forsyth 	if(w->slen >= 16)
76737da2899SCharles.Forsyth 		setupDESstate(w->state, w->secret, w->secret+8);
76837da2899SCharles.Forsyth 	else if(w->slen >= 8)
76937da2899SCharles.Forsyth 		setupDESstate(w->state, w->secret, 0);
77037da2899SCharles.Forsyth 	else
77137da2899SCharles.Forsyth 		error("secret too short");
77237da2899SCharles.Forsyth }
77337da2899SCharles.Forsyth 
77437da2899SCharles.Forsyth /*
77537da2899SCharles.Forsyth  *  40 bit DES is the same as 56 bit DES.  However,
77637da2899SCharles.Forsyth  *  16 bits of the key are masked to zero.
77737da2899SCharles.Forsyth  */
77837da2899SCharles.Forsyth static void
initDESkey_40(OneWay * w)77937da2899SCharles.Forsyth initDESkey_40(OneWay *w)
78037da2899SCharles.Forsyth {
78137da2899SCharles.Forsyth 	uchar key[8];
78237da2899SCharles.Forsyth 
78337da2899SCharles.Forsyth 
78437da2899SCharles.Forsyth 	if(w->slen >= 8) {
78537da2899SCharles.Forsyth 		memmove(key, w->secret, 8);
78637da2899SCharles.Forsyth 		key[0] &= 0x0f;
78737da2899SCharles.Forsyth 		key[2] &= 0x0f;
78837da2899SCharles.Forsyth 		key[4] &= 0x0f;
78937da2899SCharles.Forsyth 		key[6] &= 0x0f;
79037da2899SCharles.Forsyth 	}
79137da2899SCharles.Forsyth 
79237da2899SCharles.Forsyth 	free(w->state);
79337da2899SCharles.Forsyth 	w->state = malloc(sizeof(DESstate));
79437da2899SCharles.Forsyth 	if (!w->state)
79537da2899SCharles.Forsyth 		error(Enomem);
79637da2899SCharles.Forsyth 	if(w->slen >= 16)
79737da2899SCharles.Forsyth 		setupDESstate(w->state, key, w->secret+8);
79837da2899SCharles.Forsyth 	else if(w->slen >= 8)
79937da2899SCharles.Forsyth 		setupDESstate(w->state, key, 0);
80037da2899SCharles.Forsyth 	else
80137da2899SCharles.Forsyth 		error("secret too short");
80237da2899SCharles.Forsyth }
80337da2899SCharles.Forsyth 
80437da2899SCharles.Forsyth static void
initRC4key(OneWay * w)80537da2899SCharles.Forsyth initRC4key(OneWay *w)
80637da2899SCharles.Forsyth {
80737da2899SCharles.Forsyth 	free(w->state);
80837da2899SCharles.Forsyth 	w->state = malloc(sizeof(RC4state));
80937da2899SCharles.Forsyth 	if (!w->state)
81037da2899SCharles.Forsyth 		error(Enomem);
81137da2899SCharles.Forsyth 	setupRC4state(w->state, w->secret, w->slen);
81237da2899SCharles.Forsyth }
81337da2899SCharles.Forsyth 
81437da2899SCharles.Forsyth /*
81537da2899SCharles.Forsyth  *  40 bit RC4 is the same as n-bit RC4.  However,
81637da2899SCharles.Forsyth  *  we ignore all but the first 40 bits of the key.
81737da2899SCharles.Forsyth  */
81837da2899SCharles.Forsyth static void
initRC4key_40(OneWay * w)81937da2899SCharles.Forsyth initRC4key_40(OneWay *w)
82037da2899SCharles.Forsyth {
82137da2899SCharles.Forsyth 	int slen = w->slen;
82237da2899SCharles.Forsyth 
82337da2899SCharles.Forsyth 	if(slen > 5)
82437da2899SCharles.Forsyth 		slen = 5;
82537da2899SCharles.Forsyth 
82637da2899SCharles.Forsyth 	free(w->state);
82737da2899SCharles.Forsyth 	w->state = malloc(sizeof(RC4state));
82837da2899SCharles.Forsyth 	if (!w->state)
82937da2899SCharles.Forsyth 		error(Enomem);
83037da2899SCharles.Forsyth 	setupRC4state(w->state, w->secret, slen);
83137da2899SCharles.Forsyth }
83237da2899SCharles.Forsyth 
83337da2899SCharles.Forsyth /*
83437da2899SCharles.Forsyth  *  128 bit RC4 is the same as n-bit RC4.  However,
83537da2899SCharles.Forsyth  *  we ignore all but the first 128 bits of the key.
83637da2899SCharles.Forsyth  */
83737da2899SCharles.Forsyth static void
initRC4key_128(OneWay * w)83837da2899SCharles.Forsyth initRC4key_128(OneWay *w)
83937da2899SCharles.Forsyth {
84037da2899SCharles.Forsyth 	int slen = w->slen;
84137da2899SCharles.Forsyth 
84237da2899SCharles.Forsyth 	if(slen > 16)
84337da2899SCharles.Forsyth 		slen = 16;
84437da2899SCharles.Forsyth 
84537da2899SCharles.Forsyth 	free(w->state);
84637da2899SCharles.Forsyth 	w->state = malloc(sizeof(RC4state));
84737da2899SCharles.Forsyth 	if (!w->state)
84837da2899SCharles.Forsyth 		error(Enomem);
84937da2899SCharles.Forsyth 	setupRC4state(w->state, w->secret, slen);
85037da2899SCharles.Forsyth }
85137da2899SCharles.Forsyth 
85237da2899SCharles.Forsyth typedef struct Hashalg Hashalg;
85337da2899SCharles.Forsyth struct Hashalg
85437da2899SCharles.Forsyth {
85537da2899SCharles.Forsyth 	char	*name;
85637da2899SCharles.Forsyth 	int	diglen;
85737da2899SCharles.Forsyth 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
85837da2899SCharles.Forsyth };
85937da2899SCharles.Forsyth 
86037da2899SCharles.Forsyth Hashalg hashtab[] =
86137da2899SCharles.Forsyth {
86237da2899SCharles.Forsyth 	{ "md4", MD4dlen, md4, },
86337da2899SCharles.Forsyth 	{ "md5", MD5dlen, md5, },
86437da2899SCharles.Forsyth 	{ "sha1", SHA1dlen, sha1, },
86537da2899SCharles.Forsyth 	{ "sha", SHA1dlen, sha1, },
86637da2899SCharles.Forsyth 	{ 0 }
86737da2899SCharles.Forsyth };
86837da2899SCharles.Forsyth 
86937da2899SCharles.Forsyth static int
parsehashalg(char * p,Dstate * s)87037da2899SCharles.Forsyth parsehashalg(char *p, Dstate *s)
87137da2899SCharles.Forsyth {
87237da2899SCharles.Forsyth 	Hashalg *ha;
87337da2899SCharles.Forsyth 
87437da2899SCharles.Forsyth 	for(ha = hashtab; ha->name; ha++){
87537da2899SCharles.Forsyth 		if(strcmp(p, ha->name) == 0){
87637da2899SCharles.Forsyth 			s->hf = ha->hf;
87737da2899SCharles.Forsyth 			s->diglen = ha->diglen;
87837da2899SCharles.Forsyth 			s->state &= ~Sclear;
87937da2899SCharles.Forsyth 			s->state |= Sdigesting;
88037da2899SCharles.Forsyth 			return 0;
88137da2899SCharles.Forsyth 		}
88237da2899SCharles.Forsyth 	}
88337da2899SCharles.Forsyth 	return -1;
88437da2899SCharles.Forsyth }
88537da2899SCharles.Forsyth 
88637da2899SCharles.Forsyth typedef struct Encalg Encalg;
88737da2899SCharles.Forsyth struct Encalg
88837da2899SCharles.Forsyth {
88937da2899SCharles.Forsyth 	char	*name;
89037da2899SCharles.Forsyth 	int	blocklen;
89137da2899SCharles.Forsyth 	int	alg;
89237da2899SCharles.Forsyth 	void	(*keyinit)(OneWay*);
89337da2899SCharles.Forsyth };
89437da2899SCharles.Forsyth 
89537da2899SCharles.Forsyth Encalg encrypttab[] =
89637da2899SCharles.Forsyth {
89737da2899SCharles.Forsyth 	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
89837da2899SCharles.Forsyth 	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
89937da2899SCharles.Forsyth 	{ "des_56_cbc", 8, DESCBC, initDESkey, },
90037da2899SCharles.Forsyth 	{ "des_56_ecb", 8, DESECB, initDESkey, },
90137da2899SCharles.Forsyth 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
90237da2899SCharles.Forsyth 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
90337da2899SCharles.Forsyth 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
90437da2899SCharles.Forsyth 	{ "rc4_256", 1, RC4, initRC4key, },
90537da2899SCharles.Forsyth 	{ "rc4_128", 1, RC4, initRC4key_128, },
90637da2899SCharles.Forsyth 	{ "rc4_40", 1, RC4, initRC4key_40, },
90737da2899SCharles.Forsyth 	{ "ideacbc", 8, IDEACBC, initIDEAkey, },
90837da2899SCharles.Forsyth 	{ "ideaecb", 8, IDEAECB, initIDEAkey, },
90937da2899SCharles.Forsyth 	{ 0 }
91037da2899SCharles.Forsyth };
91137da2899SCharles.Forsyth 
91237da2899SCharles.Forsyth static int
parseencryptalg(char * p,Dstate * s)91337da2899SCharles.Forsyth parseencryptalg(char *p, Dstate *s)
91437da2899SCharles.Forsyth {
91537da2899SCharles.Forsyth 	Encalg *ea;
91637da2899SCharles.Forsyth 
91737da2899SCharles.Forsyth 	for(ea = encrypttab; ea->name; ea++){
91837da2899SCharles.Forsyth 		if(strcmp(p, ea->name) == 0){
91937da2899SCharles.Forsyth 			s->encryptalg = ea->alg;
92037da2899SCharles.Forsyth 			s->blocklen = ea->blocklen;
92137da2899SCharles.Forsyth 			(*ea->keyinit)(&s->in);
92237da2899SCharles.Forsyth 			(*ea->keyinit)(&s->out);
92337da2899SCharles.Forsyth 			s->state &= ~Sclear;
92437da2899SCharles.Forsyth 			s->state |= Sencrypting;
92537da2899SCharles.Forsyth 			return 0;
92637da2899SCharles.Forsyth 		}
92737da2899SCharles.Forsyth 	}
92837da2899SCharles.Forsyth 	return -1;
92937da2899SCharles.Forsyth }
93037da2899SCharles.Forsyth 
93137da2899SCharles.Forsyth static void
alglistinit(void)93237da2899SCharles.Forsyth alglistinit(void)
93337da2899SCharles.Forsyth {
93437da2899SCharles.Forsyth 	Hashalg *h;
93537da2899SCharles.Forsyth 	Encalg *e;
93637da2899SCharles.Forsyth 	int n;
93737da2899SCharles.Forsyth 
93837da2899SCharles.Forsyth 	n = 1;
93937da2899SCharles.Forsyth 	for(e = encrypttab; e->name != nil; e++)
94037da2899SCharles.Forsyth 		n += strlen(e->name) + 1;
94137da2899SCharles.Forsyth 	encalgs = malloc(n);
94237da2899SCharles.Forsyth 	if(encalgs == nil)
94337da2899SCharles.Forsyth 		panic("sslinit");
94437da2899SCharles.Forsyth 	n = 0;
94537da2899SCharles.Forsyth 	for(e = encrypttab; e->name != nil; e++){
94637da2899SCharles.Forsyth 		strcpy(encalgs+n, e->name);
94737da2899SCharles.Forsyth 		n += strlen(e->name);
94837da2899SCharles.Forsyth 		if(e[1].name == nil)
94937da2899SCharles.Forsyth 			break;
95037da2899SCharles.Forsyth 		encalgs[n++] = ' ';
95137da2899SCharles.Forsyth 	}
95237da2899SCharles.Forsyth 	encalgs[n] = 0;
95337da2899SCharles.Forsyth 
95437da2899SCharles.Forsyth 	n = 1;
95537da2899SCharles.Forsyth 	for(h = hashtab; h->name != nil; h++)
95637da2899SCharles.Forsyth 		n += strlen(h->name) + 1;
95737da2899SCharles.Forsyth 	hashalgs = malloc(n);
95837da2899SCharles.Forsyth 	if(hashalgs == nil)
95937da2899SCharles.Forsyth 		panic("sslinit");
96037da2899SCharles.Forsyth 	n = 0;
96137da2899SCharles.Forsyth 	for(h = hashtab; h->name != nil; h++){
96237da2899SCharles.Forsyth 		strcpy(hashalgs+n, h->name);
96337da2899SCharles.Forsyth 		n += strlen(h->name);
96437da2899SCharles.Forsyth 		if(h[1].name == nil)
96537da2899SCharles.Forsyth 			break;
96637da2899SCharles.Forsyth 		hashalgs[n++] = ' ';
96737da2899SCharles.Forsyth 	}
96837da2899SCharles.Forsyth 	hashalgs[n] = 0;
96937da2899SCharles.Forsyth }
97037da2899SCharles.Forsyth 
97137da2899SCharles.Forsyth static long
sslwrite(Chan * c,void * a,long n,vlong offset)97237da2899SCharles.Forsyth sslwrite(Chan *c, void *a, long n, vlong offset)
97337da2899SCharles.Forsyth {
97437da2899SCharles.Forsyth 	volatile struct { Dstate *s; } s;
97537da2899SCharles.Forsyth 	volatile struct { Block *b; } b;
97637da2899SCharles.Forsyth 	int m, t;
97737da2899SCharles.Forsyth 	char *p, *np, *e, buf[32];
97837da2899SCharles.Forsyth 	uchar *x;
97937da2899SCharles.Forsyth 
98037da2899SCharles.Forsyth 	s.s = dstate[CONV(c->qid)];
98137da2899SCharles.Forsyth 	if(s.s == 0)
98237da2899SCharles.Forsyth 		panic("sslwrite");
98337da2899SCharles.Forsyth 
98437da2899SCharles.Forsyth 	t = TYPE(c->qid);
98537da2899SCharles.Forsyth 	if(t == Qdata){
98637da2899SCharles.Forsyth 		if(s.s->state == Sincomplete)
98737da2899SCharles.Forsyth 			error(Ebadusefd);
98837da2899SCharles.Forsyth 
98937da2899SCharles.Forsyth 		p = a;
99037da2899SCharles.Forsyth 		e = p + n;
99137da2899SCharles.Forsyth 		do {
99237da2899SCharles.Forsyth 			m = e - p;
99337da2899SCharles.Forsyth 			if(m > s.s->max)
99437da2899SCharles.Forsyth 				m = s.s->max;
99537da2899SCharles.Forsyth 
99637da2899SCharles.Forsyth 			b.b = allocb(m);
99737da2899SCharles.Forsyth 			memmove(b.b->wp, p, m);
99837da2899SCharles.Forsyth 			b.b->wp += m;
99937da2899SCharles.Forsyth 
100037da2899SCharles.Forsyth 			sslbwrite(c, b.b, offset);
100137da2899SCharles.Forsyth 
100237da2899SCharles.Forsyth 			p += m;
100337da2899SCharles.Forsyth 		} while(p < e);
100437da2899SCharles.Forsyth 		return n;
100537da2899SCharles.Forsyth 	}
100637da2899SCharles.Forsyth 
100737da2899SCharles.Forsyth 	/* mutex with operations using what we're about to change */
100837da2899SCharles.Forsyth 	if(waserror()){
100937da2899SCharles.Forsyth 		qunlock(&s.s->in.ctlq);
101037da2899SCharles.Forsyth 		qunlock(&s.s->out.q);
101137da2899SCharles.Forsyth 		nexterror();
101237da2899SCharles.Forsyth 	}
101337da2899SCharles.Forsyth 	qlock(&s.s->in.ctlq);
101437da2899SCharles.Forsyth 	qlock(&s.s->out.q);
101537da2899SCharles.Forsyth 
101637da2899SCharles.Forsyth 	switch(t){
101737da2899SCharles.Forsyth 	default:
101837da2899SCharles.Forsyth 		panic("sslwrite");
101937da2899SCharles.Forsyth 	case Qsecretin:
102037da2899SCharles.Forsyth 		setsecret(&s.s->in, a, n);
102137da2899SCharles.Forsyth 		goto out;
102237da2899SCharles.Forsyth 	case Qsecretout:
102337da2899SCharles.Forsyth 		setsecret(&s.s->out, a, n);
102437da2899SCharles.Forsyth 		goto out;
102537da2899SCharles.Forsyth 	case Qctl:
102637da2899SCharles.Forsyth 		break;
102737da2899SCharles.Forsyth 	}
102837da2899SCharles.Forsyth 
102937da2899SCharles.Forsyth 	if(n >= sizeof(buf))
103037da2899SCharles.Forsyth 		error(Ebadarg);
103137da2899SCharles.Forsyth 	strncpy(buf, a, n);
103237da2899SCharles.Forsyth 	buf[n] = 0;
103337da2899SCharles.Forsyth 	p = strchr(buf, '\n');
103437da2899SCharles.Forsyth 	if(p)
103537da2899SCharles.Forsyth 		*p = 0;
103637da2899SCharles.Forsyth 	p = strchr(buf, ' ');
103737da2899SCharles.Forsyth 	if(p)
103837da2899SCharles.Forsyth 		*p++ = 0;
103937da2899SCharles.Forsyth 
104037da2899SCharles.Forsyth 	if(strcmp(buf, "fd") == 0){
104137da2899SCharles.Forsyth 		s.s->c = buftochan(p);
104237da2899SCharles.Forsyth 
104337da2899SCharles.Forsyth 		/* default is clear (msg delimiters only) */
104437da2899SCharles.Forsyth 		s.s->state = Sclear;
104537da2899SCharles.Forsyth 		s.s->blocklen = 1;
104637da2899SCharles.Forsyth 		s.s->diglen = 0;
104737da2899SCharles.Forsyth 		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
104837da2899SCharles.Forsyth 		s.s->in.mid = 0;
104937da2899SCharles.Forsyth 		s.s->out.mid = 0;
105037da2899SCharles.Forsyth 	} else if(strcmp(buf, "alg") == 0 && p != 0){
105137da2899SCharles.Forsyth 		s.s->blocklen = 1;
105237da2899SCharles.Forsyth 		s.s->diglen = 0;
105337da2899SCharles.Forsyth 
105437da2899SCharles.Forsyth 		if(s.s->c == 0)
105537da2899SCharles.Forsyth 			error("must set fd before algorithm");
105637da2899SCharles.Forsyth 
105737da2899SCharles.Forsyth 		if(strcmp(p, "clear") == 0){
105837da2899SCharles.Forsyth 			s.s->state = Sclear;
105937da2899SCharles.Forsyth 			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
106037da2899SCharles.Forsyth 			goto out;
106137da2899SCharles.Forsyth 		}
106237da2899SCharles.Forsyth 
106337da2899SCharles.Forsyth 		if(s.s->in.secret && s.s->out.secret == 0)
106437da2899SCharles.Forsyth 			setsecret(&s.s->out, s.s->in.secret, s.s->in.slen);
106537da2899SCharles.Forsyth 		if(s.s->out.secret && s.s->in.secret == 0)
106637da2899SCharles.Forsyth 			setsecret(&s.s->in, s.s->out.secret, s.s->out.slen);
106737da2899SCharles.Forsyth 		if(s.s->in.secret == 0 || s.s->out.secret == 0)
106837da2899SCharles.Forsyth 			error("algorithm but no secret");
106937da2899SCharles.Forsyth 
107037da2899SCharles.Forsyth 		s.s->hf = 0;
107137da2899SCharles.Forsyth 		s.s->encryptalg = Noencryption;
107237da2899SCharles.Forsyth 		s.s->blocklen = 1;
107337da2899SCharles.Forsyth 
107437da2899SCharles.Forsyth 		for(;;){
107537da2899SCharles.Forsyth 			np = strchr(p, ' ');
107637da2899SCharles.Forsyth 			if(np)
107737da2899SCharles.Forsyth 				*np++ = 0;
107837da2899SCharles.Forsyth 			else{
107937da2899SCharles.Forsyth 				np = strchr(p, '/');
108037da2899SCharles.Forsyth 				if(np)
108137da2899SCharles.Forsyth 					*np++ = 0;
108237da2899SCharles.Forsyth 			}
108337da2899SCharles.Forsyth 			if(parsehashalg(p, s.s) < 0)
108437da2899SCharles.Forsyth 			if(parseencryptalg(p, s.s) < 0)
108537da2899SCharles.Forsyth 				error(Ebadarg);
108637da2899SCharles.Forsyth 
108737da2899SCharles.Forsyth 			if(np == 0)
108837da2899SCharles.Forsyth 				break;
108937da2899SCharles.Forsyth 			p = np;
109037da2899SCharles.Forsyth 		}
109137da2899SCharles.Forsyth 
109237da2899SCharles.Forsyth 		if(s.s->hf == 0 && s.s->encryptalg == Noencryption)
109337da2899SCharles.Forsyth 			error(Ebadarg);
109437da2899SCharles.Forsyth 
109537da2899SCharles.Forsyth 		if(s.s->blocklen != 1){
109637da2899SCharles.Forsyth 			/* make multiple of blocklen */
109737da2899SCharles.Forsyth 			s.s->max = (1<<15) - s.s->diglen - 1;
109837da2899SCharles.Forsyth 			s.s->max -= s.s->max % s.s->blocklen;
109937da2899SCharles.Forsyth 			s.s->maxpad = (1<<14) - s.s->diglen - 1;
110037da2899SCharles.Forsyth 			s.s->maxpad -= s.s->maxpad % s.s->blocklen;
110137da2899SCharles.Forsyth 		} else
110237da2899SCharles.Forsyth 			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
110337da2899SCharles.Forsyth 	} else if(strcmp(buf, "secretin") == 0 && p != 0) {
110437da2899SCharles.Forsyth 		m = (strlen(p)*3)/2;
110537da2899SCharles.Forsyth 		x = smalloc(m);
110637da2899SCharles.Forsyth 		if(waserror()){
110737da2899SCharles.Forsyth 			free(x);
110837da2899SCharles.Forsyth 			nexterror();
110937da2899SCharles.Forsyth 		}
111037da2899SCharles.Forsyth 		t = dec64(x, m, p, strlen(p));
111137da2899SCharles.Forsyth 		setsecret(&s.s->in, x, t);
111237da2899SCharles.Forsyth 		poperror();
111337da2899SCharles.Forsyth 		free(x);
111437da2899SCharles.Forsyth 	} else if(strcmp(buf, "secretout") == 0 && p != 0) {
111537da2899SCharles.Forsyth 		m = (strlen(p)*3)/2;
111637da2899SCharles.Forsyth 		x = smalloc(m);
111737da2899SCharles.Forsyth 		if(waserror()){
111837da2899SCharles.Forsyth 			free(x);
111937da2899SCharles.Forsyth 			nexterror();
112037da2899SCharles.Forsyth 		}
112137da2899SCharles.Forsyth 		t = dec64(x, m, p, strlen(p));
112237da2899SCharles.Forsyth 		setsecret(&s.s->out, x, t);
112337da2899SCharles.Forsyth 		poperror();
112437da2899SCharles.Forsyth 		free(x);
112537da2899SCharles.Forsyth 	} else
112637da2899SCharles.Forsyth 		error(Ebadarg);
112737da2899SCharles.Forsyth 
112837da2899SCharles.Forsyth out:
112937da2899SCharles.Forsyth 	qunlock(&s.s->in.ctlq);
113037da2899SCharles.Forsyth 	qunlock(&s.s->out.q);
113137da2899SCharles.Forsyth 	poperror();
113237da2899SCharles.Forsyth 	return n;
113337da2899SCharles.Forsyth }
113437da2899SCharles.Forsyth 
113537da2899SCharles.Forsyth 
113637da2899SCharles.Forsyth static Block*
encryptb(Dstate * s,Block * b,int offset)113737da2899SCharles.Forsyth encryptb(Dstate *s, Block *b, int offset)
113837da2899SCharles.Forsyth {
113937da2899SCharles.Forsyth 	uchar *p, *ep, *p2, *ip, *eip;
114037da2899SCharles.Forsyth 	DESstate *ds;
114137da2899SCharles.Forsyth 	IDEAstate *is;
114237da2899SCharles.Forsyth 
114337da2899SCharles.Forsyth 	switch(s->encryptalg){
114437da2899SCharles.Forsyth 	case DESECB:
114537da2899SCharles.Forsyth 		ds = s->out.state;
114637da2899SCharles.Forsyth 		ep = b->rp + BLEN(b);
114737da2899SCharles.Forsyth 		for(p = b->rp + offset; p < ep; p += 8)
114837da2899SCharles.Forsyth 			block_cipher(ds->expanded, p, 0);
114937da2899SCharles.Forsyth 		break;
115037da2899SCharles.Forsyth 	case DESCBC:
115137da2899SCharles.Forsyth 		ds = s->out.state;
115237da2899SCharles.Forsyth 		ep = b->rp + BLEN(b);
115337da2899SCharles.Forsyth 		for(p = b->rp + offset; p < ep; p += 8){
115437da2899SCharles.Forsyth 			p2 = p;
115537da2899SCharles.Forsyth 			ip = ds->ivec;
115637da2899SCharles.Forsyth 			for(eip = ip+8; ip < eip; )
115737da2899SCharles.Forsyth 				*p2++ ^= *ip++;
115837da2899SCharles.Forsyth 			block_cipher(ds->expanded, p, 0);
115937da2899SCharles.Forsyth 			memmove(ds->ivec, p, 8);
116037da2899SCharles.Forsyth 		}
116137da2899SCharles.Forsyth 		break;
116237da2899SCharles.Forsyth 	case IDEAECB:
116337da2899SCharles.Forsyth 		is = s->out.state;
116437da2899SCharles.Forsyth 		ep = b->rp + BLEN(b);
116537da2899SCharles.Forsyth 		for(p = b->rp + offset; p < ep; p += 8)
116637da2899SCharles.Forsyth 			idea_cipher(is->edkey, p, 0);
116737da2899SCharles.Forsyth 		break;
116837da2899SCharles.Forsyth 	case IDEACBC:
116937da2899SCharles.Forsyth 		is = s->out.state;
117037da2899SCharles.Forsyth 		ep = b->rp + BLEN(b);
117137da2899SCharles.Forsyth 		for(p = b->rp + offset; p < ep; p += 8){
117237da2899SCharles.Forsyth 			p2 = p;
117337da2899SCharles.Forsyth 			ip = is->ivec;
117437da2899SCharles.Forsyth 			for(eip = ip+8; ip < eip; )
117537da2899SCharles.Forsyth 				*p2++ ^= *ip++;
117637da2899SCharles.Forsyth 			idea_cipher(is->edkey, p, 0);
117737da2899SCharles.Forsyth 			memmove(is->ivec, p, 8);
117837da2899SCharles.Forsyth 		}
117937da2899SCharles.Forsyth 		break;
118037da2899SCharles.Forsyth 	case RC4:
118137da2899SCharles.Forsyth 		rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
118237da2899SCharles.Forsyth 		break;
118337da2899SCharles.Forsyth 	}
118437da2899SCharles.Forsyth 	return b;
118537da2899SCharles.Forsyth }
118637da2899SCharles.Forsyth 
118737da2899SCharles.Forsyth static Block*
decryptb(Dstate * s,Block * inb)118837da2899SCharles.Forsyth decryptb(Dstate *s, Block *inb)
118937da2899SCharles.Forsyth {
119037da2899SCharles.Forsyth 	Block *b, **l;
119137da2899SCharles.Forsyth 	uchar *p, *ep, *tp, *ip, *eip;
119237da2899SCharles.Forsyth 	DESstate *ds;
119337da2899SCharles.Forsyth 	IDEAstate *is;
119437da2899SCharles.Forsyth 	uchar tmp[8];
119537da2899SCharles.Forsyth 	int i;
119637da2899SCharles.Forsyth 
119737da2899SCharles.Forsyth 	l = &inb;
119837da2899SCharles.Forsyth 	for(b = inb; b; b = b->next){
119937da2899SCharles.Forsyth 		/* make sure we have a multiple of s->blocklen */
120037da2899SCharles.Forsyth 		if(s->blocklen > 1){
120137da2899SCharles.Forsyth 			i = BLEN(b);
120237da2899SCharles.Forsyth 			if(i % s->blocklen){
120337da2899SCharles.Forsyth 				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
120437da2899SCharles.Forsyth 				if(b == 0)
120537da2899SCharles.Forsyth 					error("ssl encrypted message too short");
120637da2899SCharles.Forsyth 			}
120737da2899SCharles.Forsyth 		}
120837da2899SCharles.Forsyth 		l = &b->next;
120937da2899SCharles.Forsyth 
121037da2899SCharles.Forsyth 		/* decrypt */
121137da2899SCharles.Forsyth 		switch(s->encryptalg){
121237da2899SCharles.Forsyth 		case DESECB:
121337da2899SCharles.Forsyth 			ds = s->in.state;
121437da2899SCharles.Forsyth 			ep = b->rp + BLEN(b);
121537da2899SCharles.Forsyth 			for(p = b->rp; p < ep; p += 8)
121637da2899SCharles.Forsyth 				block_cipher(ds->expanded, p, 1);
121737da2899SCharles.Forsyth 			break;
121837da2899SCharles.Forsyth 		case DESCBC:
121937da2899SCharles.Forsyth 			ds = s->in.state;
122037da2899SCharles.Forsyth 			ep = b->rp + BLEN(b);
122137da2899SCharles.Forsyth 			for(p = b->rp; p < ep;){
122237da2899SCharles.Forsyth 				memmove(tmp, p, 8);
122337da2899SCharles.Forsyth 				block_cipher(ds->expanded, p, 1);
122437da2899SCharles.Forsyth 				tp = tmp;
122537da2899SCharles.Forsyth 				ip = ds->ivec;
122637da2899SCharles.Forsyth 				for(eip = ip+8; ip < eip; ){
122737da2899SCharles.Forsyth 					*p++ ^= *ip;
122837da2899SCharles.Forsyth 					*ip++ = *tp++;
122937da2899SCharles.Forsyth 				}
123037da2899SCharles.Forsyth 			}
123137da2899SCharles.Forsyth 			break;
123237da2899SCharles.Forsyth 		case IDEAECB:
123337da2899SCharles.Forsyth 			is = s->in.state;
123437da2899SCharles.Forsyth 			ep = b->rp + BLEN(b);
123537da2899SCharles.Forsyth 			for(p = b->rp; p < ep; p += 8)
123637da2899SCharles.Forsyth 				idea_cipher(is->edkey, p, 1);
123737da2899SCharles.Forsyth 			break;
123837da2899SCharles.Forsyth 		case IDEACBC:
123937da2899SCharles.Forsyth 			is = s->in.state;
124037da2899SCharles.Forsyth 			ep = b->rp + BLEN(b);
124137da2899SCharles.Forsyth 			for(p = b->rp; p < ep;){
124237da2899SCharles.Forsyth 				memmove(tmp, p, 8);
124337da2899SCharles.Forsyth 				idea_cipher(is->edkey, p, 1);
124437da2899SCharles.Forsyth 				tp = tmp;
124537da2899SCharles.Forsyth 				ip = is->ivec;
124637da2899SCharles.Forsyth 				for(eip = ip+8; ip < eip; ){
124737da2899SCharles.Forsyth 					*p++ ^= *ip;
124837da2899SCharles.Forsyth 					*ip++ = *tp++;
124937da2899SCharles.Forsyth 				}
125037da2899SCharles.Forsyth 			}
125137da2899SCharles.Forsyth 			break;
125237da2899SCharles.Forsyth 		case RC4:
125337da2899SCharles.Forsyth 			rc4(s->in.state, b->rp, BLEN(b));
125437da2899SCharles.Forsyth 			break;
125537da2899SCharles.Forsyth 		}
125637da2899SCharles.Forsyth 	}
125737da2899SCharles.Forsyth 	return inb;
125837da2899SCharles.Forsyth }
125937da2899SCharles.Forsyth 
126037da2899SCharles.Forsyth static Block*
digestb(Dstate * s,Block * b,int offset)126137da2899SCharles.Forsyth digestb(Dstate *s, Block *b, int offset)
126237da2899SCharles.Forsyth {
126337da2899SCharles.Forsyth 	uchar *p;
126437da2899SCharles.Forsyth 	DigestState ss;
126537da2899SCharles.Forsyth 	uchar msgid[4];
126637da2899SCharles.Forsyth 	ulong n, h;
126737da2899SCharles.Forsyth 	OneWay *w;
126837da2899SCharles.Forsyth 
126937da2899SCharles.Forsyth 	w = &s->out;
127037da2899SCharles.Forsyth 
127137da2899SCharles.Forsyth 	memset(&ss, 0, sizeof(ss));
127237da2899SCharles.Forsyth 	h = s->diglen + offset;
127337da2899SCharles.Forsyth 	n = BLEN(b) - h;
127437da2899SCharles.Forsyth 
127537da2899SCharles.Forsyth 	/* hash secret + message */
127637da2899SCharles.Forsyth 	(*s->hf)(w->secret, w->slen, 0, &ss);
127737da2899SCharles.Forsyth 	(*s->hf)(b->rp + h, n, 0, &ss);
127837da2899SCharles.Forsyth 
127937da2899SCharles.Forsyth 	/* hash message id */
128037da2899SCharles.Forsyth 	p = msgid;
128137da2899SCharles.Forsyth 	n = w->mid;
128237da2899SCharles.Forsyth 	*p++ = n>>24;
128337da2899SCharles.Forsyth 	*p++ = n>>16;
128437da2899SCharles.Forsyth 	*p++ = n>>8;
128537da2899SCharles.Forsyth 	*p = n;
128637da2899SCharles.Forsyth 	(*s->hf)(msgid, 4, b->rp + offset, &ss);
128737da2899SCharles.Forsyth 
128837da2899SCharles.Forsyth 	return b;
128937da2899SCharles.Forsyth }
129037da2899SCharles.Forsyth 
129137da2899SCharles.Forsyth static void
checkdigestb(Dstate * s,Block * inb)129237da2899SCharles.Forsyth checkdigestb(Dstate *s, Block *inb)
129337da2899SCharles.Forsyth {
129437da2899SCharles.Forsyth 	uchar *p;
129537da2899SCharles.Forsyth 	DigestState ss;
129637da2899SCharles.Forsyth 	uchar msgid[4];
129737da2899SCharles.Forsyth 	int n, h;
129837da2899SCharles.Forsyth 	OneWay *w;
129937da2899SCharles.Forsyth 	uchar digest[128];
130037da2899SCharles.Forsyth 	Block *b;
130137da2899SCharles.Forsyth 
130237da2899SCharles.Forsyth 	w = &s->in;
130337da2899SCharles.Forsyth 
130437da2899SCharles.Forsyth 	memset(&ss, 0, sizeof(ss));
130537da2899SCharles.Forsyth 
130637da2899SCharles.Forsyth 	/* hash secret */
130737da2899SCharles.Forsyth 	(*s->hf)(w->secret, w->slen, 0, &ss);
130837da2899SCharles.Forsyth 
130937da2899SCharles.Forsyth 	/* hash message */
131037da2899SCharles.Forsyth 	h = s->diglen;
131137da2899SCharles.Forsyth 	for(b = inb; b; b = b->next){
131237da2899SCharles.Forsyth 		n = BLEN(b) - h;
131337da2899SCharles.Forsyth 		if(n < 0)
131437da2899SCharles.Forsyth 			panic("checkdigestb");
131537da2899SCharles.Forsyth 		(*s->hf)(b->rp + h, n, 0, &ss);
131637da2899SCharles.Forsyth 		h = 0;
131737da2899SCharles.Forsyth 	}
131837da2899SCharles.Forsyth 
131937da2899SCharles.Forsyth 	/* hash message id */
132037da2899SCharles.Forsyth 	p = msgid;
132137da2899SCharles.Forsyth 	n = w->mid;
132237da2899SCharles.Forsyth 	*p++ = n>>24;
132337da2899SCharles.Forsyth 	*p++ = n>>16;
132437da2899SCharles.Forsyth 	*p++ = n>>8;
132537da2899SCharles.Forsyth 	*p = n;
132637da2899SCharles.Forsyth 	(*s->hf)(msgid, 4, digest, &ss);
132737da2899SCharles.Forsyth 
132837da2899SCharles.Forsyth 	/* requires pullupblock */
132937da2899SCharles.Forsyth 	if(memcmp(digest, inb->rp, s->diglen) != 0)
133037da2899SCharles.Forsyth 		error("bad digest");
133137da2899SCharles.Forsyth }
133237da2899SCharles.Forsyth 
133337da2899SCharles.Forsyth /* get channel associated with an fd */
133437da2899SCharles.Forsyth static Chan*
buftochan(char * p)133537da2899SCharles.Forsyth buftochan(char *p)
133637da2899SCharles.Forsyth {
133737da2899SCharles.Forsyth 	Chan *c;
133837da2899SCharles.Forsyth 	int fd;
133937da2899SCharles.Forsyth 
134037da2899SCharles.Forsyth 	if(p == 0)
134137da2899SCharles.Forsyth 		error(Ebadarg);
134237da2899SCharles.Forsyth 	fd = strtoul(p, 0, 0);
134337da2899SCharles.Forsyth 	if(fd < 0)
134437da2899SCharles.Forsyth 		error(Ebadarg);
134537da2899SCharles.Forsyth 	c = fdtochan(up->env->fgrp, fd, -1, 0, 1);	/* error check and inc ref */
134637da2899SCharles.Forsyth 	return c;
134737da2899SCharles.Forsyth }
134837da2899SCharles.Forsyth 
134937da2899SCharles.Forsyth /* hang up a digest connection */
135037da2899SCharles.Forsyth static void
sslhangup(Dstate * s)135137da2899SCharles.Forsyth sslhangup(Dstate *s)
135237da2899SCharles.Forsyth {
135337da2899SCharles.Forsyth 	qlock(&s->in.q);
135437da2899SCharles.Forsyth 	freeblist(s->processed);
135537da2899SCharles.Forsyth 	s->processed = 0;
135637da2899SCharles.Forsyth 	freeblist(s->unprocessed);
135737da2899SCharles.Forsyth 	s->unprocessed = 0;
135837da2899SCharles.Forsyth 	s->state = Sincomplete;
135937da2899SCharles.Forsyth 	qunlock(&s->in.q);
136037da2899SCharles.Forsyth }
136137da2899SCharles.Forsyth 
1362*ad01d857SCharles.Forsyth static void
dsclone(Chan * ch)136337da2899SCharles.Forsyth dsclone(Chan *ch)
136437da2899SCharles.Forsyth {
136537da2899SCharles.Forsyth 	Dstate **pp, **ep, **np;
136637da2899SCharles.Forsyth 	int newmax;
136737da2899SCharles.Forsyth 
1368*ad01d857SCharles.Forsyth 	lock(&dslock);
136937da2899SCharles.Forsyth 	if(waserror()) {
137037da2899SCharles.Forsyth 		unlock(&dslock);
137137da2899SCharles.Forsyth 		nexterror();
137237da2899SCharles.Forsyth 	}
137337da2899SCharles.Forsyth 	ep = &dstate[maxdstate];
137437da2899SCharles.Forsyth 	for(pp = dstate; pp < ep; pp++) {
137537da2899SCharles.Forsyth 		if(*pp == 0) {
137637da2899SCharles.Forsyth 			dsnew(ch, pp);
137737da2899SCharles.Forsyth 			break;
137837da2899SCharles.Forsyth 		}
137937da2899SCharles.Forsyth 	}
138037da2899SCharles.Forsyth 	if(pp >= ep) {
1381*ad01d857SCharles.Forsyth 		if(maxdstate >= Maxdstate)
1382*ad01d857SCharles.Forsyth 			error(Enodev);
138337da2899SCharles.Forsyth 		newmax = 2 * maxdstate;
138437da2899SCharles.Forsyth 		if(newmax > Maxdstate)
138537da2899SCharles.Forsyth 			newmax = Maxdstate;
1386*ad01d857SCharles.Forsyth 
138737da2899SCharles.Forsyth 		np = realloc(dstate, sizeof(Dstate*) * newmax);
138837da2899SCharles.Forsyth 		if(np == 0)
138937da2899SCharles.Forsyth 			error(Enomem);
139037da2899SCharles.Forsyth 		dstate = np;
139137da2899SCharles.Forsyth 		pp = &dstate[maxdstate];
139237da2899SCharles.Forsyth 		memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate));
1393*ad01d857SCharles.Forsyth 
139437da2899SCharles.Forsyth 		maxdstate = newmax;
139537da2899SCharles.Forsyth 		dsnew(ch, pp);
139637da2899SCharles.Forsyth 	}
139737da2899SCharles.Forsyth 	poperror();
1398*ad01d857SCharles.Forsyth 	unlock(&dslock);
139937da2899SCharles.Forsyth }
140037da2899SCharles.Forsyth 
140137da2899SCharles.Forsyth static void
dsnew(Chan * ch,Dstate ** pp)140237da2899SCharles.Forsyth dsnew(Chan *ch, Dstate **pp)
140337da2899SCharles.Forsyth {
140437da2899SCharles.Forsyth 	Dstate *s;
140537da2899SCharles.Forsyth 	int t;
140637da2899SCharles.Forsyth 
1407*ad01d857SCharles.Forsyth 	*pp = s = mallocz(sizeof(*s), 1);
1408*ad01d857SCharles.Forsyth 	if(s == nil)
140937da2899SCharles.Forsyth 		error(Enomem);
141037da2899SCharles.Forsyth 	if(pp - dstate >= dshiwat)
141137da2899SCharles.Forsyth 		dshiwat++;
141237da2899SCharles.Forsyth 	s->state = Sincomplete;
141337da2899SCharles.Forsyth 	s->ref = 1;
141437da2899SCharles.Forsyth 	kstrdup(&s->user, up->env->user);
141537da2899SCharles.Forsyth 	s->perm = 0660;
141637da2899SCharles.Forsyth 	t = TYPE(ch->qid);
141737da2899SCharles.Forsyth 	if(t == Qclonus)
141837da2899SCharles.Forsyth 		t = Qctl;
141937da2899SCharles.Forsyth 	ch->qid.path = QID(pp - dstate, t);
142037da2899SCharles.Forsyth 	ch->qid.vers = 0;
142137da2899SCharles.Forsyth 	ch->qid.type = QTFILE;
142237da2899SCharles.Forsyth }
142337da2899SCharles.Forsyth 
142437da2899SCharles.Forsyth Dev ssldevtab = {
142537da2899SCharles.Forsyth 	'D',
142637da2899SCharles.Forsyth 	"ssl",
142737da2899SCharles.Forsyth 
142837da2899SCharles.Forsyth 	sslinit,
142937da2899SCharles.Forsyth 	sslattach,
143037da2899SCharles.Forsyth 	sslwalk,
143137da2899SCharles.Forsyth 	sslstat,
143237da2899SCharles.Forsyth 	sslopen,
143337da2899SCharles.Forsyth 	devcreate,
143437da2899SCharles.Forsyth 	sslclose,
143537da2899SCharles.Forsyth 	sslread,
143637da2899SCharles.Forsyth 	sslbread,
143737da2899SCharles.Forsyth 	sslwrite,
143837da2899SCharles.Forsyth 	sslbwrite,
143937da2899SCharles.Forsyth 	devremove,
144037da2899SCharles.Forsyth 	sslwstat
144137da2899SCharles.Forsyth };
1442