1465 lines · 24.8 KB · C
RawDownload
/* *  devssl - secure sockets layer */#include	"u.h"#include	"lib.h"#include	"dat.h"#include	"fns.h"#include	"error.h" #include	<libsec.h> #define NOSPOOKS 1 typedef struct OneWay OneWay;struct OneWay{	QLock	q;	QLock	ctlq; 	void	*state;		/* encryption state */	int	slen;		/* hash 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}; 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=	512,	/* max. open ssl conn's; must be a power of 2 */}; static	Lock	dslock;static	int	dshiwat;static	char	*dsname[Maxdstate];static	Dstate	*dstate[Maxdstate];static	char	*encalgs;static	char	*hashalgs; enum{	Qtopdir		= 1,	/* top level directory */	Qprotodir,	Qclonus,	Qconvdir,		/* directory for a conversation */	Qdata,	Qctl,	Qsecretin,	Qsecretout,	Qencalgs,	Qhashalgs,}; #define TYPE(x) 	((x).path & 0xf)#define CONV(x) 	(((x).path >> 5)&(Maxdstate-1))#define QID(c, y) 	(((c)<<5) | (y)) 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 Dstate*	dsclone(Chan *c);static void	dsnew(Chan *c, Dstate **);static long	sslput(Dstate *s, Block * volatile b); char *sslnames[] = {[Qclonus]	"clone",[Qdata]		"data",[Qctl]		"ctl",[Qsecretin]	"secretin",[Qsecretout]	"secretout",[Qencalgs]	"encalgs",[Qhashalgs]	"hashalgs",}; static intsslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp){	Qid q;	Dstate *ds;	char name[16], *p, *nm;	int ft; 	USED(n);	USED(nd);	USED(d); 	q.type = QTFILE;	q.vers = 0; 	ft = TYPE(c->qid);	switch(ft) {	case Qtopdir:		if(s == DEVDOTDOT){			q.path = QID(0, Qtopdir);			q.type = QTDIR;			devdir(c, q, "#D", 0, eve, 0555, dp);			return 1;		}		if(s > 0)			return -1;		q.path = QID(0, Qprotodir);		q.type = QTDIR;		devdir(c, q, "ssl", 0, eve, 0555, dp);		return 1;	case Qprotodir:		if(s == DEVDOTDOT){			q.path = QID(0, Qtopdir);			q.type = QTDIR;			devdir(c, q, ".", 0, eve, 0555, dp);			return 1;		}		if(s < dshiwat) {			q.path = QID(s, Qconvdir);			q.type = QTDIR;			ds = dstate[s];			if(ds != 0)				nm = ds->user;			else				nm = eve;			if(dsname[s] == nil){				sprint(name, "%d", s);				kstrdup(&dsname[s], name);			}			devdir(c, q, dsname[s], 0, nm, 0555, dp);			return 1;		}		if(s > dshiwat)			return -1;		q.path = QID(0, Qclonus);		devdir(c, q, "clone", 0, eve, 0555, dp);		return 1;	case Qconvdir:		if(s == DEVDOTDOT){			q.path = QID(0, Qprotodir);			q.type = QTDIR;			devdir(c, q, "ssl", 0, eve, 0555, dp);			return 1;		}		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;	case Qclonus:		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);		return 1;	default:		ds = dstate[CONV(c->qid)];		if(ds != 0)			nm = ds->user;		else			nm = eve;		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);		return 1;	}} 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, nil, 0, sslgen);} static intsslstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, nil, 0, sslgen);} static Chan*sslopen(Chan *c, int omode){	Dstate *s, **pp;	int ft; 	ft = TYPE(c->qid);	switch(ft) {	default:		panic("sslopen");	case Qtopdir:	case Qprotodir:	case Qconvdir:		if(omode != OREAD)			error(Eperm);		break;	case Qclonus:		s = dsclone(c);		if(s == 0)			error(Enodev);		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 {			devpermcheck(s->user, s->perm, omode);			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->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 != -1)		s->perm = dir->mode; 	free(dir);	return m;} static voidsslclose(Chan *c){	Dstate *s;	int ft; 	ft = TYPE(c->qid);	switch(ft) {	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); 		if(s->user != nil)			free(s->user);		sslhangup(s);		if(s->c)			cclose(s->c);		secfree(s->in.secret);		secfree(s->out.secret);		secfree(s->in.state);		secfree(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)			nexterror();		*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);	}} /* *  give back n bytesstatic voidregurgitate(Dstate *s, uchar *p, int n){	Block *b; 	if(n <= 0)		return;	b = s->unprocessed;	if(s->unprocessed == nil || b->rp - b->base < n) {		b = allocb(n);		memmove(b->wp, p, n);		b->wp += n;		b->next = s->unprocessed;		s->unprocessed = b;	} else {		b->rp -= n;		memmove(b->rp, p, n);	}} */ /* *  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);				b->wp -= i;				*l = 0;			} else {				nb = allocb(i);				memmove(nb->wp, b->rp+n, i);				nb->wp += i;				b->wp -= i;				nb->next = b->next;

Lines 1–500 of 1465.