1441 lines · 25.1 KB · C
RawDownload
/* *  devssl - secure sockets layer */#include	"dat.h"#include	"fns.h"#include	"error.h" #include	"mp.h"#include	"libsec.h" typedef struct OneWay OneWay;struct OneWay{	QLock	q;	QLock	ctlq; 	void	*state;		/* encryption state */	int	slen;			/* secret data length */	uchar	*secret;	/* secret */	ulong	mid;		/* message id */}; enum{	/* connection states */	Sincomplete=	0,	Sclear=		1,	Sencrypting=	2,	Sdigesting=	4,	Sdigenc=	Sencrypting|Sdigesting, 	/* encryption algorithms */	Noencryption=	0,	DESCBC=		1,	DESECB=		2,	RC4=		3,	IDEACBC=	4,	IDEAECB=		5}; typedef struct Dstate Dstate;struct Dstate{	Chan	*c;			/* io channel */	uchar	state;		/* state of connection */	int	ref;			/* serialized by dslock for atomic destroy */ 	uchar	encryptalg;	/* encryption algorithm */	ushort	blocklen;	/* blocking length */ 	ushort	diglen;		/* length of digest */	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */ 	/* for SSL format */	int	max;			/* maximum unpadded data per msg */	int	maxpad;			/* maximum padded data per msg */		/* input side */	OneWay	in;	Block	*processed;	Block	*unprocessed; 	/* output side */	OneWay	out; 	/* protections */	char*	user;	int	perm;}; enum{	Maxdmsg=	1<<16,	Maxdstate=	1<<10,}; Lock	dslock;int	dshiwat;int	maxdstate = 20;Dstate** dstate; enum{	Qtopdir		= 1,	/* top level directory */	Qclonus,	Qconvdir,			/* directory for a conversation */	Qdata,	Qctl,	Qsecretin,	Qsecretout,	Qencalgs,	Qhashalgs}; #define TYPE(x) 	((ulong)(x).path & 0xf)#define CONV(x) 	(((ulong)(x).path >> 4)&(Maxdstate-1))#define QID(c, y) 	(((c)<<4) | (y)) static char*	encalgs;static char*	hashalgs; void producerand(void); static void alglistinit(void);static void	ensure(Dstate*, Block**, int);static void	consume(Block**, uchar*, int);static void	setsecret(OneWay*, uchar*, int);static Block*	encryptb(Dstate*, Block*, int);static Block*	decryptb(Dstate*, Block*);static Block*	digestb(Dstate*, Block*, int);static void	checkdigestb(Dstate*, Block*);static Chan*	buftochan(char*);static void	sslhangup(Dstate*);static void dsclone(Chan *c);static void	dsnew(Chan *c, Dstate **); static intsslgen(Chan *c, char *dname, Dirtab *d, int nd, int s, Dir *dp){	Qid q;	Dstate *ds;	char *p, *nm; 	USED(dname);	USED(nd);	USED(d);	q.type = QTFILE;	q.vers = 0;	if(s == DEVDOTDOT){		q.path = QID(0, Qtopdir);		q.type = QTDIR;		devdir(c, q, "#D", 0, eve, 0555, dp);		return 1;	}	switch(TYPE(c->qid)) {	case Qtopdir:		if(s < dshiwat) {			q.path = QID(s, Qconvdir);			q.type = QTDIR;			ds = dstate[s];			if(ds != 0) 				nm = ds->user; 			else 				nm = eve;			snprint(up->genbuf, sizeof(up->genbuf), "%d", s);			devdir(c, q, up->genbuf, 0, nm, DMDIR|0555, dp);			return 1;		}		if(s > dshiwat)			return -1;		/* fall through */	case Qclonus:		q.path = QID(0, Qclonus);		devdir(c, q, "clone", 0, eve, 0666, dp);		return 1;	case Qconvdir:		ds = dstate[CONV(c->qid)];		if(ds != 0)			nm = ds->user;		else			nm = eve;		switch(s) {		default:			return -1;		case 0:			q.path = QID(CONV(c->qid), Qctl);			p = "ctl";			break;		case 1:			q.path = QID(CONV(c->qid), Qdata);			p = "data";			break;		case 2:			q.path = QID(CONV(c->qid), Qsecretin);			p = "secretin";			break;		case 3:			q.path = QID(CONV(c->qid), Qsecretout);			p = "secretout";			break;		case 4:			q.path = QID(CONV(c->qid), Qencalgs);			p = "encalgs";			break;		case 5:			q.path = QID(CONV(c->qid), Qhashalgs);			p = "hashalgs";			break;		}		devdir(c, q, p, 0, nm, 0660, dp);		return 1;	}	return -1;} static voidsslinit(void){	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)		panic("sslinit");	alglistinit();} static Chan *sslattach(char *spec){	Chan *c; 	c = devattach('D', spec);	c->qid.path = QID(0, Qtopdir);	c->qid.vers = 0;	c->qid.type = QTDIR;	return c;} static Walkqid*sslwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, 0, 0, sslgen);} static intsslstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, sslgen);} static Chan*sslopen(Chan *c, int omode){	Dstate *s, **pp;	int perm; 	perm = 0;	omode &= 3;	switch(omode) {	case OREAD:		perm = 4;		break;	case OWRITE:		perm = 2;		break;	case ORDWR:		perm = 6;		break;	} 	switch(TYPE(c->qid)) {	default:		panic("sslopen");	case Qtopdir:	case Qconvdir:		if(omode != OREAD)			error(Eperm);		break;	case Qclonus:		dsclone(c);		break;	case Qctl:	case Qdata:	case Qsecretin:	case Qsecretout:		if(waserror()) {			unlock(&dslock);			nexterror();		}		lock(&dslock);		pp = &dstate[CONV(c->qid)];		s = *pp;		if(s == 0)			dsnew(c, pp);		else {			if((perm & (s->perm>>6)) != perm			   && (strcmp(up->env->user, s->user) != 0			     || (perm & s->perm) != perm))				error(Eperm); 			s->ref++;		}		unlock(&dslock);		poperror();		break;	case Qencalgs:	case Qhashalgs:		if(omode != OREAD)			error(Eperm);		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static intsslwstat(Chan *c, uchar *db, int n){	Dir *dir;	Dstate *s;	int m; 	s = dstate[CONV(c->qid)];	if(s == 0)		error(Ebadusefd);	if(strcmp(s->user, up->env->user) != 0)		error(Eperm); 	dir = smalloc(sizeof(Dir)+n);	m = convM2D(db, n, &dir[0], (char*)&dir[1]);	if(m == 0){		free(dir);		error(Eshortstat);	} 	if(!emptystr(dir->uid))		kstrdup(&s->user, dir->uid);	if(dir->mode != ~0UL)		s->perm = dir->mode; 	free(dir);	return m;} static voidsslclose(Chan *c){	Dstate *s; 	switch(TYPE(c->qid)) {	case Qctl:	case Qdata:	case Qsecretin:	case Qsecretout:		if((c->flag & COPEN) == 0)			break; 		s = dstate[CONV(c->qid)];		if(s == 0)			break; 		lock(&dslock);		if(--s->ref > 0) {			unlock(&dslock);			break;		}		dstate[CONV(c->qid)] = 0;		unlock(&dslock); 		sslhangup(s);		if(s->c)			cclose(s->c);		free(s->user);		free(s->in.secret);		free(s->out.secret);		free(s->in.state);		free(s->out.state);		free(s);	}} /* *  make sure we have at least 'n' bytes in list 'l' */static voidensure(Dstate *s, Block **l, int n){	int sofar, i;	Block *b, *bl; 	sofar = 0;	for(b = *l; b; b = b->next){		sofar += BLEN(b);		if(sofar >= n)			return;		l = &b->next;	} 	while(sofar < n){		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);		if(bl == 0)			error(Ehungup);		*l = bl;		i = 0;		for(b = bl; b; b = b->next){			i += BLEN(b);			l = &b->next;		}		if(i == 0)			error(Ehungup); 		sofar += i;	}} /* *  copy 'n' bytes from 'l' into 'p' and free *  the bytes in 'l' */static voidconsume(Block **l, uchar *p, int n){	Block *b;	int i; 	for(; *l && n > 0; n -= i){		b = *l;		i = BLEN(b);		if(i > n)			i = n;		memmove(p, b->rp, i);		b->rp += i;		p += i;		if(BLEN(b) < 0)			panic("consume");		if(BLEN(b))			break;		*l = b->next;		freeb(b);	}} /* *  remove at most n bytes from the queue, if discard is set *  dump the remainder */static Block*qtake(Block **l, int n, int discard){	Block *nb, *b, *first;	int i; 	first = *l;	for(b = first; b; b = b->next){		i = BLEN(b);		if(i == n){			if(discard){				freeblist(b->next);				*l = 0;			} else				*l = b->next;			b->next = 0;			return first;		} else if(i > n){			i -= n;			if(discard){				freeblist(b->next);				*l = 0;			} else {				nb = allocb(i);				memmove(nb->wp, b->rp+n, i);				nb->wp += i;				nb->next = b->next;				*l = nb;			}			b->wp -= i;			b->next = 0;			if(BLEN(b) < 0)				panic("qtake");			return first;		} else			n -= i;		if(BLEN(b) < 0)			panic("qtake");	}	*l = 0;	return first;} static Block*sslbread(Chan *c, long n, ulong offset){	volatile struct { Dstate *s; } s;	volatile struct { int nc; } nc;	Block *b;	uchar count[3];	int len, pad; 	USED(offset);	s.s = dstate[CONV(c->qid)];	if(s.s == 0)		panic("sslbread");	if(s.s->state == Sincomplete)		error(Ebadusefd); 	nc.nc = 0;	if(waserror()){		qunlock(&s.s->in.q);		if(strcmp(up->env->errstr, "interrupted") == 0){			if(nc.nc > 0){				b = allocb(nc.nc);				memmove(b->wp, count, nc.nc);				b->wp += nc.nc;				b->next = s.s->unprocessed;				s.s->unprocessed = b;			}		} else			sslhangup(s.s);		nexterror();	}	qlock(&s.s->in.q); 

Lines 1–500 of 1441.