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

📄 devtls.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 */#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h"#include "libsec.h"typedef struct OneWay	OneWay;typedef struct Secret		Secret;typedef struct TlsRec	TlsRec;typedef struct TlsErrs	TlsErrs;enum {	Statlen=	1024,		/* max. length of status or stats message */	/* buffer limits */	MaxRecLen		= 1<<14,	/* max payload length of a record layer message */	MaxCipherRecLen	= MaxRecLen + 2048,	RecHdrLen		= 5,	MaxMacLen		= SHA1dlen,	/* protocol versions we can accept */	TLSVersion		= 0x0301,	SSL3Version		= 0x0300,	ProtocolVersion	= 0x0301,	/* maximum version we speak */	MinProtoVersion	= 0x0300,	/* limits on version we accept */	MaxProtoVersion	= 0x03ff,	/* connection states */	SHandshake	= 1 << 0,	/* doing handshake */	SOpen		= 1 << 1,	/* application data can be sent */	SRClose		= 1 << 2,	/* remote side has closed down */	SLClose		= 1 << 3,	/* sent a close notify alert */	SAlert		= 1 << 5,	/* sending or sent a fatal alert */	SError		= 1 << 6,	/* some sort of error has occured */	SClosed		= 1 << 7,	/* it is all over */	/* record types */	RChangeCipherSpec = 20,	RAlert,	RHandshake,	RApplication,	SSL2ClientHello = 1,	HSSL2ClientHello = 9,  /* local convention;  see tlshand.c */	/* alerts */	ECloseNotify 			= 0,	EUnexpectedMessage 	= 10,	EBadRecordMac 		= 20,	EDecryptionFailed 		= 21,	ERecordOverflow 		= 22,	EDecompressionFailure 	= 30,	EHandshakeFailure 		= 40,	ENoCertificate 			= 41,	EBadCertificate 		= 42,	EUnsupportedCertificate 	= 43,	ECertificateRevoked 		= 44,	ECertificateExpired 		= 45,	ECertificateUnknown 	= 46,	EIllegalParameter 		= 47,	EUnknownCa 			= 48,	EAccessDenied 		= 49,	EDecodeError 			= 50,	EDecryptError 			= 51,	EExportRestriction 		= 60,	EProtocolVersion 		= 70,	EInsufficientSecurity 	= 71,	EInternalError 			= 80,	EUserCanceled 			= 90,	ENoRenegotiation 		= 100,	EMAX = 256};struct Secret{	char		*encalg;	/* name of encryption alg */	char		*hashalg;	/* name of hash alg */	int		(*enc)(Secret*, uchar*, int);	int		(*dec)(Secret*, uchar*, int);	int		(*unpad)(uchar*, int, int);	DigestState	*(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);	int		block;		/* encryption block len, 0 if none */	int		maclen;	void		*enckey;	uchar	mackey[MaxMacLen];};struct OneWay{	QLock		io;		/* locks io access */	QLock		seclock;	/* locks secret paramaters */	ulong		seq;	Secret		*sec;		/* cipher in use */	Secret		*new;		/* cipher waiting for enable */};struct TlsRec{	Chan	*c;				/* io channel */	int		ref;				/* serialized by tdlock for atomic destroy */	int		version;			/* version of the protocol we are speaking */	char		verset;			/* version has been set */	char		opened;			/* opened command every issued? */	char		err[ERRMAX];		/* error message to return to handshake requests */	vlong	handin;			/* bytes communicated by the record layer */	vlong	handout;	vlong	datain;	vlong	dataout;	Lock		statelk;	int		state;	int		debug;	/* record layer mac functions for different protocol versions */	void		(*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*);	/* input side -- protected by in.io */	OneWay		in;	Block		*processed;	/* next bunch of application data */	Block		*unprocessed;	/* data read from c but not parsed into records */	/* handshake queue */	Lock		hqlock;			/* protects hqref, alloc & free of handq, hprocessed */	int		hqref;	Queue		*handq;		/* queue of handshake messages */	Block		*hprocessed;	/* remainder of last block read from handq */	QLock		hqread;		/* protects reads for hprocessed, handq */	/* output side */	OneWay		out;	/* protections */	char		*user;	int		perm;};struct TlsErrs{	int	err;	int	sslerr;	int	tlserr;	int	fatal;	char	*msg;};static TlsErrs tlserrs[] = {	{ECloseNotify,			ECloseNotify,			ECloseNotify,			0, 	"close notify"},	{EUnexpectedMessage,	EUnexpectedMessage,	EUnexpectedMessage, 	1, "unexpected message"},	{EBadRecordMac,		EBadRecordMac,		EBadRecordMac, 		1, "bad record mac"},	{EDecryptionFailed,		EIllegalParameter,		EDecryptionFailed,		1, "decryption failed"},	{ERecordOverflow,		EIllegalParameter,		ERecordOverflow,		1, "record too long"},	{EDecompressionFailure,	EDecompressionFailure,	EDecompressionFailure,	1, "decompression failed"},	{EHandshakeFailure,		EHandshakeFailure,		EHandshakeFailure,		1, "could not negotiate acceptable security parameters"},	{ENoCertificate,		ENoCertificate,			ECertificateUnknown,	1, "no appropriate certificate available"},	{EBadCertificate,		EBadCertificate,		EBadCertificate,		1, "corrupted or invalid certificate"},	{EUnsupportedCertificate,	EUnsupportedCertificate,	EUnsupportedCertificate,	1, "unsupported certificate type"},	{ECertificateRevoked,	ECertificateRevoked,		ECertificateRevoked,		1, "revoked certificate"},	{ECertificateExpired,		ECertificateExpired,		ECertificateExpired,		1, "expired certificate"},	{ECertificateUnknown,	ECertificateUnknown,	ECertificateUnknown,	1, "unacceptable certificate"},	{EIllegalParameter,		EIllegalParameter,		EIllegalParameter,		1, "illegal parameter"},	{EUnknownCa,			EHandshakeFailure,		EUnknownCa,			1, "unknown certificate authority"},	{EAccessDenied,		EHandshakeFailure,		EAccessDenied,		1, "access denied"},	{EDecodeError,			EIllegalParameter,		EDecodeError,			1, "error decoding message"},	{EDecryptError,			EIllegalParameter,		EDecryptError,			1, "error decrypting message"},	{EExportRestriction,		EHandshakeFailure,		EExportRestriction,		1, "export restriction violated"},	{EProtocolVersion,		EIllegalParameter,		EProtocolVersion,		1, "protocol version not supported"},	{EInsufficientSecurity,	EHandshakeFailure,		EInsufficientSecurity,	1, "stronger security routines required"},	{EInternalError,			EHandshakeFailure,		EInternalError,			1, "internal error"},	{EUserCanceled,		ECloseNotify,			EUserCanceled,			0, "handshake canceled by user"},	{ENoRenegotiation,		EUnexpectedMessage,	ENoRenegotiation,		0, "no renegotiation"},};enum{	/* max. open tls connections */	MaxTlsDevs	= 1024};static	Lock	tdlock;static	int	tdhiwat;static	int	maxtlsdevs = 128;static	TlsRec	**tlsdevs;static	char	**trnames;static	char	*encalgs;static	char	*hashalgs;enum{	Qtopdir		= 1,	/* top level directory */	Qprotodir,	Qclonus,	Qencalgs,	Qhashalgs,	Qconvdir,		/* directory for a conversation */	Qdata,	Qctl,	Qhand,	Qstatus,	Qstats,};#define TYPE(x) 	((x).path & 0xf)#define CONV(x) 	(((x).path >> 5)&(MaxTlsDevs-1))#define QID(c, y) 	(((c)<<5) | (y))static void	checkstate(TlsRec *, int, int);static void	ensure(TlsRec*, Block**, int);static void	consume(Block**, uchar*, int);static Chan*	buftochan(char*);static void	tlshangup(TlsRec*);static void	tlsError(TlsRec*, char *);static void	alertHand(TlsRec*, char *);static TlsRec	*newtls(Chan *c);static TlsRec	*mktlsrec(void);static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static void	sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);static void	tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);static void	put64(uchar *p, vlong x);static void	put32(uchar *p, u32int);static void	put24(uchar *p, int);static void	put16(uchar *p, int);static int	get16(uchar *p);static void	tlsSetState(TlsRec *tr, int new, int old);static void	rcvAlert(TlsRec *tr, int err);static void	sendAlert(TlsRec *tr, int err);static void	rcvError(TlsRec *tr, int err, char *msg, ...);static int	rc4enc(Secret *sec, uchar *buf, int n);static int	des3enc(Secret *sec, uchar *buf, int n);static int	des3dec(Secret *sec, uchar *buf, int n);static int	noenc(Secret *sec, uchar *buf, int n);static int	sslunpad(uchar *buf, int n, int block);static int	tlsunpad(uchar *buf, int n, int block);static void	freeSec(Secret *sec);static char	*tlsstate(int s);static void	pdump(int, void*, char*);static char *tlsnames[] = {[Qclonus]		"clone",[Qencalgs]	"encalgs",[Qhashalgs]	"hashalgs",[Qdata]		"data",[Qctl]		"ctl",[Qhand]		"hand",[Qstatus]		"status",[Qstats]		"stats",};static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats };static inttlsgen(Chan *c, char *_, Dirtab *__, int ___, int s, Dir *dp){	Qid q;	TlsRec *tr;	char *name, *nm;	int perm, t;	q.vers = 0;	q.type = QTFILE;	t = TYPE(c->qid);	switch(t) {	case Qtopdir:		if(s == DEVDOTDOT){			q.path = QID(0, Qtopdir);			q.type = QTDIR;			devdir(c, q, "#a", 0, eve, 0555, dp);			return 1;		}		if(s > 0)			return -1;		q.path = QID(0, Qprotodir);		q.type = QTDIR;		devdir(c, q, "tls", 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 < 3){			switch(s) {			default:				return -1;			case 0:				q.path = QID(0, Qclonus);				break;			case 1:				q.path = QID(0, Qencalgs);				break;			case 2:				q.path = QID(0, Qhashalgs);				break;			}			perm = 0444;			if(TYPE(q) == Qclonus)				perm = 0555;			devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp);			return 1;		}		s -= 3;		if(s >= tdhiwat)			return -1;		q.path = QID(s, Qconvdir);		q.type = QTDIR;		lock(&tdlock);		tr = tlsdevs[s];		if(tr != nil)			nm = tr->user;		else			nm = eve;		if((name = trnames[s]) == nil){			name = trnames[s] = smalloc(16);			sprint(name, "%d", s);		}		devdir(c, q, name, 0, nm, 0555, dp);		unlock(&tdlock);		return 1;	case Qconvdir:		if(s == DEVDOTDOT){			q.path = QID(0, Qprotodir);			q.type = QTDIR;			devdir(c, q, "tls", 0, eve, 0555, dp);			return 1;		}		if(s < 0 || s >= nelem(convdir))			return -1;		lock(&tdlock);		tr = tlsdevs[CONV(c->qid)];		if(tr != nil){			nm = tr->user;			perm = tr->perm;		}else{			perm = 0;			nm = eve;		}		t = convdir[s];		if(t == Qstatus || t == Qstats)			perm &= 0444;		q.path = QID(CONV(c->qid), t);		devdir(c, q, tlsnames[t], 0, nm, perm, dp);		unlock(&tdlock);		return 1;	case Qclonus:	case Qencalgs:	case Qhashalgs:		perm = 0444;		if(t == Qclonus)			perm = 0555;		devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp);		return 1;	default:		lock(&tdlock);		tr = tlsdevs[CONV(c->qid)];		if(tr != nil){			nm = tr->user;			perm = tr->perm;		}else{			perm = 0;			nm = eve;		}		if(t == Qstatus || t == Qstats)			perm &= 0444;		devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp);		unlock(&tdlock);		return 1;	}}static Chan*tlsattach(char *spec){	Chan *c;	c = devattach('a', spec);	c->qid.path = QID(0, Qtopdir);	c->qid.type = QTDIR;	c->qid.vers = 0;	return c;}static Walkqid*tlswalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, nil, 0, tlsgen);}static inttlsstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, nil, 0, tlsgen);}static Chan*tlsopen(Chan *c, int omode){	TlsRec *tr, **pp;	int t, perm;	perm = 0;	omode &= 3;	switch(omode) {	case OREAD:		perm = 4;		break;	case OWRITE:		perm = 2;		break;	case ORDWR:		perm = 6;		break;	}	t = TYPE(c->qid);	switch(t) {	default:		panic("tlsopen");	case Qtopdir:	case Qprotodir:	case Qconvdir:		if(omode != OREAD)			error(Eperm);		break;	case Qclonus:		tr = newtls(c);		if(tr == nil)			error(Enodev);		break;	case Qctl:	case Qdata:	case Qhand:	case Qstatus:	case Qstats:		if((t == Qstatus || t == Qstats) && omode != OREAD)			error(Eperm);		if(waserror()) {			unlock(&tdlock);			nexterror();		}		lock(&tdlock);		pp = &tlsdevs[CONV(c->qid)];		tr = *pp;		if(tr == nil)			error("must open connection using clone");		if((perm & (tr->perm>>6)) != perm		&& (strcmp(up->user, tr->user) != 0		    || (perm & tr->perm) != perm))			error(Eperm);		if(t == Qhand){			if(waserror()){				unlock(&tr->hqlock);				nexterror();			}			lock(&tr->hqlock);			if(tr->handq != nil)				error(Einuse);			tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil);			if(tr->handq == nil)				error("cannot allocate handshake queue");			tr->hqref = 1;			unlock(&tr->hqlock);			poperror();		}		tr->ref++;		unlock(&tdlock);		poperror();		break;	case Qencalgs:	case Qhashalgs:		if(omode != OREAD)			error(Eperm);		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	c->iounit = qiomaxatomic;	return c;}static inttlswstat(Chan *c, uchar *dp, int n){	Dir *d;	TlsRec *tr;	int rv;	d = nil;	if(waserror()){		free(d);		unlock(&tdlock);		nexterror();	}	lock(&tdlock);	tr = tlsdevs[CONV(c->qid)];	if(tr == nil)		error(Ebadusefd);	if(strcmp(tr->user, up->user) != 0)		error(Eperm);	d = smalloc(n + sizeof *d);	rv = convM2D(dp, n, &d[0], (char*) &d[1]);	if(rv == 0)		error(Eshortstat);	if(!emptystr(d->uid))		kstrdup(&tr->user, d->uid);	if(d->mode != ~0UL)		tr->perm = d->mode;	free(d);	poperror();	unlock(&tdlock);	return rv;}static voiddechandq(TlsRec *tr){	lock(&tr->hqlock);	if(--tr->hqref == 0){		if(tr->handq != nil){			qfree(tr->handq);			tr->handq = nil;		}		if(tr->hprocessed != nil){			freeb(tr->hprocessed);			tr->hprocessed = nil;		}	}	unlock(&tr->hqlock);}static voidtlsclose(Chan *c){	TlsRec *tr;	int t;	t = TYPE(c->qid);	switch(t) {	case Qctl:	case Qdata:	case Qhand:	case Qstatus:	case Qstats:		if((c->flag & COPEN) == 0)			break;		tr = tlsdevs[CONV(c->qid)];		if(tr == nil)			break;		if(t == Qhand)			dechandq(tr);		lock(&tdlock);		if(--tr->ref > 0) {			unlock(&tdlock);			return;		}		tlsdevs[CONV(c->qid)] = nil;		unlock(&tdlock);		if(tr->c != nil && !waserror()){			checkstate(tr, 0, SOpen|SHandshake|SRClose);			sendAlert(tr, ECloseNotify);			poperror();		}		tlshangup(tr);		if(tr->c != nil)			cclose(tr->c);		freeSec(tr->in.sec);		freeSec(tr->in.new);		freeSec(tr->out.sec);		freeSec(tr->out.new);		free(tr->user);		free(tr);		break;	}}/* *  make sure we have at least 'n' bytes in list 'l' */static voidensure(TlsRec *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, MaxCipherRecLen + RecHdrLen, 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;	}if(s->debug) pprint("ensure read %d\n", sofar);}/* *  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 bytes */static voidregurgitate(TlsRec *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 */static Block*qgrab(Block **l, int n){	Block *bb, *b;	int i;	b = *l;	if(BLEN(b) == n){		*l = b->next;		b->next = nil;		return b;	}	i = 0;	for(bb = b; bb != nil && i < n; bb = bb->next)		i += BLEN(bb);	if(i > n)		i = n;	bb = allocb(i);	consume(l, bb->wp, i);	bb->wp += i;	return bb;}static voidtlsclosed(TlsRec *tr, int new){	lock(&tr->statelk);	if(tr->state == SOpen || tr->state == SHandshake)		tr->state = new;	else if((new | tr->state) == (SRClose|SLClose))		tr->state = SClosed;	unlock(&tr->statelk);	alertHand(tr, "close notify");}/* *  read and process one tls record layer message *  must be called with tr->in.io held *  We can't let Eintrs lose data, since doing so will get *  us out of sync with the sender and break the reliablity *  of the channel.  Eintr only happens during the reads in *  consume.  Therefore we put back any bytes consumed before *  the last call to ensure. */static voidtlsrecread(TlsRec *tr)

⌨️ 快捷键说明

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