⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devssl.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  devssl - secure sockets layer */#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h"#include "libsec.h"#define NOSPOOKS 1typedef 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=	128,	/* must be a power of 2 */};Lock	dslock;int	dshiwat;char	*dsname[Maxdstate];Dstate	*dstate[Maxdstate];char	*encalgs;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 *_, Dirtab *d, int nd, int s, Dir *dp){	Qid q;	Dstate *ds;	char name[16], *p, *nm;	int ft;	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 perm;	int ft;	perm = 0;	omode &= 3;	switch(omode) {	case OREAD:		perm = 4;		break;	case OWRITE:		perm = 2;		break;	case ORDWR:		perm = 6;		break;	}	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 {			if((perm & (s->perm>>6)) != perm			   && (strcmp(up->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->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;	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);		if(s->in.secret)			free(s->in.secret);		if(s->out.secret)			free(s->out.secret);		if(s->in.state)			free(s->in.state);		if(s->out.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)			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;				*l = nb;			}			b->next = 0;			if(BLEN(b) < 0)				panic("qtake");			return first;		} else			n -= i;		if(BLEN(b) < 0)			panic("qtake");	}	*l = 0;	return first;}/* *  We can't let Eintr's lose data since the program *  doing the read may be able to handle it.  The only *  places Eintr is possible is during the read's in consume. *  Therefore, we make sure we can always put back the bytes *  consumed before the last ensure. */static Block*sslbread(Chan *c, long n, ulong _){	Dstate * volatile s;	Block *b;	uchar consumed[3], *p;	int toconsume;	int len, pad;	s = dstate[CONV(c->qid)];	if(s == 0)		panic("sslbread");	if(s->state == Sincomplete)		error(Ebadusefd);	qlock(&s->in.q);	if(waserror()){		qunlock(&s->in.q);		nexterror();	}	if(s->processed == 0){		/*		 * Read in the whole message.  Until we've got it all,		 * it stays on s->unprocessed, so that if we get Eintr,		 * we'll pick up where we left off.		 */		ensure(s, &s->unprocessed, 3);		s->unprocessed = pullupblock(s->unprocessed, 2);		p = s->unprocessed->rp;		if(p[0] & 0x80){			len = ((p[0] & 0x7f)<<8) | p[1];			ensure(s, &s->unprocessed, len);			pad = 0;			toconsume = 2;		} else {			s->unprocessed = pullupblock(s->unprocessed, 3);			len = ((p[0] & 0x3f)<<8) | p[1];			pad = p[2];			if(pad > len){				print("pad %d buf len %d\n", pad, len);				error("bad pad in ssl message");			}			toconsume = 3;		}		ensure(s, &s->unprocessed, toconsume+len);		/* skip header */		consume(&s->unprocessed, consumed, toconsume);		/* grab the next message and decode/decrypt it */		b = qtake(&s->unprocessed, len, 0);		if(blocklen(b) != len)			print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);		if(waserror()){			qunlock(&s->in.ctlq);			if(b != nil)				freeb(b);			nexterror();		}		qlock(&s->in.ctlq);		switch(s->state){		case Sencrypting:			if(b == nil)				error("ssl message too short (encrypting)");			b = decryptb(s, b);			break;		case Sdigesting:			b = pullupblock(b, s->diglen);			if(b == nil)				error("ssl message too short (digesting)");			checkdigestb(s, b);			pullblock(&b, s->diglen);			len -= s->diglen;			break;		case Sdigenc:			b = decryptb(s, b);			b = pullupblock(b, s->diglen);			if(b == nil)				error("ssl message too short (dig+enc)");			checkdigestb(s, b);			pullblock(&b, s->diglen);			len -= s->diglen;			break;		}		/* remove pad */		if(pad)			s->processed = qtake(&b, len - pad, 1);		else			s->processed = b;		b = nil;		s->in.mid++;		qunlock(&s->in.ctlq);		poperror();	}	/* return at most what was asked for */	b = qtake(&s->processed, n, 0);	qunlock(&s->in.q);	poperror();	return b;}static longsslread(Chan *c, void *a, long n, vlong off){	Block * volatile b;	Block *nb;	uchar *va;	int i;	char buf[128];	ulong offset = off;	int ft;	if(c->qid.type & QTDIR)		return devdirread(c, a, n, 0, 0, sslgen);	ft = TYPE(c->qid);	switch(ft) {	default:		error(Ebadusefd);	case Qctl:		ft = CONV(c->qid);		sprint(buf, "%d", ft);		return readstr(offset, a, n, buf);	case Qdata:		b = sslbread(c, n, offset);		break;	case Qencalgs:		return readstr(offset, a, n, encalgs);		break;	case Qhashalgs:		return readstr(offset, a, n, hashalgs);		break;	}	if(waserror()){		freeblist(b);		nexterror();	}	n = 0;	va = a;	for(nb = b; nb; nb = nb->next){		i = BLEN(nb);		memmove(va+n, nb->rp, i);		n += i;	}	freeblist(b);	poperror();	return n;}/* *  this algorithm doesn't have to be great since we're just *  trying to obscure the block fill */static voidrandfill(uchar *buf, int len){	while(len-- > 0)		*buf++ = nrand(256);}static longsslbwrite(Chan *c, Block *b, ulong _){	Dstate * volatile s;	long rv;	s = dstate[CONV(c->qid)];	if(s == nil)		panic("sslbwrite");	if(s->state == Sincomplete){		freeb(b);		error(Ebadusefd);	}	/* lock so split writes won't interleave */	if(waserror()){		qunlock(&s->out.q);		nexterror();	}	qlock(&s->out.q);	rv = sslput(s, b);	poperror();	qunlock(&s->out.q);	return rv;}/* *  use SSL record format, add in count, digest and/or encrypt. *  the write is interruptable.  if it is interrupted, we'll *  get out of sync with the far side.  not much we can do about *  it since we don't know if any bytes have been written. */static long

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -