plan 9 kernel history: overview | file list | diff list

1996/1029/port/devssl.c (diff list | history)

1996/0601/sys/src/9/port/devssl.c:10,201996/1029/sys/src/9/port/devssl.c:10,22 (short | long | prev | next)
1995/1213    
 
1996/0531    
#include <libcrypt.h> 
1995/1213    
 
1996/1029    
#define NOSPOOKS 1 
1995/1213    
 
typedef struct OneWay OneWay; 
struct OneWay 
{ 
1996/0531    
	QLock	q; 
1996/1029    
	QLock	ctlq; 
1995/1213    
 
1996/0531    
	void	*state;		/* encryption state */ 
	int	slen;		/* hash data length */ 
1996/0601/sys/src/9/port/devssl.c:25,411996/1029/sys/src/9/port/devssl.c:27,44
1995/1213    
enum 
{ 
	/* connection states */ 
	Algwait=	0,	/* waiting for user to write algorithm */ 
	Fdwait=		1,	/* waiting for user to write fd */ 
	Secretinwait=	2,	/* waiting for user to write input secret */ 
	Secretoutwait=	3,	/* waiting for user to write output secret */ 
	Established=	4, 
	Closed=		5, 
1996/1029    
	Sincomplete=	0, 
	Sclear, 
	Sencrypting, 
	Sdigesting, 
1995/1213    
 
	/* encryption algorithms */ 
1995/1218    
	Noencryption=	0, 
1996/1029    
#ifdef NOSPOOKS 
1995/1213    
	DESCBC=		1, 
1996/0531    
	DESECB=		2 
1996/1029    
	DESECB=		2, 
#endif NOSPOOKS 
	RC4=		3 
1995/1213    
}; 
 
typedef struct Dstate Dstate; 
1996/0601/sys/src/9/port/devssl.c:43,481996/1029/sys/src/9/port/devssl.c:46,53
1995/1213    
{ 
	Chan	*c;		/* io channel */ 
	uchar	state;		/* state of connection */ 
1996/1029    
	int	ref;		/* serialized by dslock for atomic destroy */ 
 
1995/1213    
	uchar	encryptalg;	/* encryption algorithm */ 
1995/1218    
	ushort	blocklen;	/* blocking length */ 
1995/1213    
 
1996/0601/sys/src/9/port/devssl.c:60,1021996/1029/sys/src/9/port/devssl.c:65,112
1995/1213    
 
	/* output side */ 
	OneWay	out; 
1996/1029    
 
	/* protections */ 
	char	user[NAMELEN]; 
	int	perm; 
1995/1213    
}; 
 
1996/1029    
Lock	dslock; 
int	dshiwat; 
int	maxdstate = 20; 
Dstate** dstate; 
 
1995/1213    
enum 
{ 
1996/0531    
	Maxdmsg=	1<<16 
1996/1029    
	Maxdmsg=	1<<16, 
	Maxdstate=	64 
1995/1213    
}; 
 
enum{ 
	Qdir, 
1996/0531    
	Qclone 
1996/1029    
	Qtopdir		= 1,	/* top level directory */ 
	Qclonus, 
	Qconvdir,		/* directory for a conversation */ 
	Qdata, 
	Qctl, 
	Qsecretin, 
	Qsecretout 
1995/1213    
}; 
Dirtab digesttab[]={ 
1996/0103    
	"ssl",		{Qclone, 0},	0,	0666, 
1995/1213    
}; 
#define Ndigesttab (sizeof(digesttab)/sizeof(Dirtab)) 
 
/* a circular list of random numbers */ 
typedef struct 
{ 
	uchar	*rp; 
	uchar	*wp; 
	uchar	buf[1024]; 
	uchar	*ep; 
} Randq; 
Randq randq; 
1996/1029    
#define TYPE(x) 	((x).path & 0xf) 
#define CONV(x) 	(((x).path >> 4)&(Maxdstate-1)) 
#define QID(c, y) 	(((c)<<4) | (y)) 
1995/1213    
 
void producerand(void); 
                 
1995/1217    
static void	ensure(Dstate*, Block**, int); 
static void	consume(Block**, uchar*, int); 
1995/1218    
static void	setsecret(Dstate*, OneWay*, uchar*, int); 
1996/1029    
static void	setsecret(OneWay*, uchar*, int); 
1995/1217    
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*, long); 
static void	dighangup(Dstate*); 
1996/1029    
static Chan*	buftochan(char*); 
static void	sslhangup(Dstate*); 
static Dstate*	dsclone(Chan *c); 
static void	dsnew(Chan *c, Dstate **); 
1995/1217    
 
1995/1213    
void 
sslreset(void) 
1996/0601/sys/src/9/port/devssl.c:103,1191996/1029/sys/src/9/port/devssl.c:113,194
1995/1213    
{ 
} 
 
1996/1029    
int 
sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp) 
{ 
	Qid q; 
	Dstate *ds; 
	char name[16], *p, *nm; 
 
	USED(nd); 
	USED(d); 
	q.vers = 0; 
	switch(TYPE(c->qid)) { 
	case Qtopdir: 
		if(s < dshiwat) { 
			sprint(name, "%d", s); 
			q.path = QID(s, Qconvdir)|CHDIR; 
			ds = dstate[s]; 
			if(ds != 0) 
				nm = ds->user; 
			else 
				nm = eve; 
			devdir(c, q, name, 0, nm, CHDIR|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: 
		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; 
		} 
		devdir(c, q, p, 0, nm, 0660, dp); 
		return 1; 
	} 
	return -1; 
} 
 
1995/1213    
void 
sslinit(void) 
{ 
1996/0531    
	randq.ep = randq.buf + sizeof(randq.buf); 
	randq.rp = randq.wp = randq.buf; 
1996/1029    
	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0) 
		panic("sslinit"); 
1995/1213    
} 
 
Chan * 
1996/0531    
sslattach(void *spec) 
1995/1213    
{ 
	return devattach('D', spec); 
1996/1029    
	Chan *c; 
 
	c = devattach('D', spec); 
	c->qid.path = QID(0, Qtopdir)|CHDIR; 
	c->qid.vers = 0; 
	return c; 
1995/1213    
} 
 
Chan * 
1996/0601/sys/src/9/port/devssl.c:125,1531996/1029/sys/src/9/port/devssl.c:200,276
1995/1213    
int 
sslwalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, digesttab, Ndigesttab, devgen); 
1996/1029    
	return devwalk(c, name, 0, 0, sslgen); 
1995/1213    
} 
 
void 
sslstat(Chan *c, char *db) 
{ 
	devstat(c, db, digesttab, Ndigesttab, devgen); 
1996/1029    
	devstat(c, db, 0, 0, sslgen); 
1995/1213    
} 
 
Chan * 
sslopen(Chan *c, int omode) 
{ 
	Dstate *s; 
1996/1029    
	Dstate *s, **pp; 
	int perm; 
1995/1213    
 
	switch(c->qid.path & ~CHDIR){ 
	case Qclone: 
1996/0531    
		s = malloc(sizeof(Dstate)); 
1995/1213    
		memset(s, 0, sizeof(*s)); 
		s->state = Algwait; 
		c->aux = s; 
1996/1029    
	perm = 0; 
	omode &= 3; 
	switch(omode) { 
	case OREAD: 
		perm = 4; 
1995/1213    
		break; 
1996/1029    
	case OWRITE: 
		perm = 2; 
		break; 
	case ORDWR: 
		perm = 6; 
		break; 
1995/1213    
	} 
	return devopen(c, omode, digesttab, Ndigesttab, devgen); 
1996/1029    
 
	switch(TYPE(c->qid)) { 
	default: 
		panic("sslopen"); 
	case Qtopdir: 
	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; 
	} 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
1995/1213    
} 
 
void 
1996/0601/sys/src/9/port/devssl.c:170,1781996/1029/sys/src/9/port/devssl.c:293,311
1995/1213    
void 
sslwstat(Chan *c, char *dp) 
{ 
1996/0531    
	USED(c); 
	USED(dp); 
1995/1213    
	error(Eperm); 
1996/1029    
	Dir d; 
	Dstate *s; 
 
	convM2D(dp, &d); 
 
	s = dstate[CONV(c->qid)]; 
	if(s == 0) 
		error(Ebadusefd); 
	if(strcmp(s->user, up->user) != 0) 
		error(Eperm); 
 
	memmove(s->user, d.uid, NAMELEN); 
	s->perm = d.mode; 
1995/1213    
} 
 
void 
1996/0601/sys/src/9/port/devssl.c:180,1881996/1029/sys/src/9/port/devssl.c:313,339
1995/1213    
{ 
	Dstate *s; 
 
	if(c->aux){ 
		s = c->aux; 
		dighangup(s); 
1996/1029    
	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); 
1995/1213    
		if(s->c) 
1996/0601    
			close(s->c); 
1995/1213    
		if(s->in.secret) 
1996/0601/sys/src/9/port/devssl.c:189,1981996/1029/sys/src/9/port/devssl.c:340,486
1995/1213    
			free(s->in.secret); 
		if(s->out.secret) 
			free(s->out.secret); 
1996/1029    
		if(s->in.state) 
			free(s->in.state); 
		if(s->out.state) 
			free(s->out.state); 
1995/1213    
		free(s); 
1996/1029    
 
1995/1213    
	} 
} 
 
1996/1029    
static int 
blen(Block *bp) 
{ 
	int i = 0; 
 
	for(; bp; bp = bp->next) 
		i += BLEN(bp); 
	return i; 
} 
 
/* 
 *  make sure we have at least 'n' bytes in list 'l' 
 */ 
static void 
ensure(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 void 
consume(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); 
	} 
} 
 
/*  
 *  free a list of blocks 
 */ 
void 
freeblist(Block *b) 
{ 
	Block *next; 
 
	for(; b != 0; b = next){ 
		next = b->next; 
		freeb(b); 
	} 
} 
 
/* 
 *  remove at most n bytes from the queue, if discard is set 
 *  dump the remainder 
 */ 
static Block* 
qremove(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; 
			break; 
		} 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("qremove"); 
			return first; 
		} else 
			n -= i; 
		if(BLEN(b) < 0) 
			panic("qremove"); 
	} 
	*l = 0; 
	return first; 
} 
 
1995/1217    
Block* 
sslbread(Chan *c, long n, ulong offset) 
1995/1213    
{ 
1996/0601/sys/src/9/port/devssl.c:199,2741996/1029/sys/src/9/port/devssl.c:487,558
1996/0531    
	volatile struct { Dstate *s; } s; 
1995/1218    
	Block *b; 
1995/1217    
	uchar count[2]; 
1995/1218    
	int i, len, pad; 
1996/1029    
	int len, pad; 
1995/1213    
 
1995/1217    
	USED(offset); 
 
1996/0531    
	s.s = c->aux; 
	if(s.s == 0 || s.s->state != Established) 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslbread"); 
	if(s.s->state == Sincomplete) 
1995/1217    
		error(Ebadusefd); 
 
	if(waserror()){ 
1996/0531    
		qunlock(&s.s->in.q); 
		dighangup(s.s); 
1996/1029    
		sslhangup(s.s); 
1995/1217    
		nexterror(); 
1995/1213    
	} 
1996/0531    
	qlock(&s.s->in.q); 
1995/1217    
 
1996/0531    
	b = s.s->processed; 
1995/1218    
	if(b == 0){ 
1995/1217    
	                 
1996/1029    
	if(s.s->processed == 0){ 
1995/1217    
		/* read in the whole message */ 
1996/0531    
		s.s->processed = s.s->unprocessed; 
		s.s->unprocessed = 0; 
		ensure(s.s, &s.s->processed, 2); 
		consume(&s.s->processed, count, 2); 
1996/1029    
		ensure(s.s, &s.s->unprocessed, 2); 
		consume(&s.s->unprocessed, count, 2); 
1995/1217    
		if(count[0] & 0x80){ 
			len = ((count[0] & 0x7f)<<8) | count[1]; 
1996/0531    
			ensure(s.s, &s.s->processed, len); 
1996/1029    
			ensure(s.s, &s.s->unprocessed, len); 
1995/1217    
			pad = 0; 
		} else { 
			len = ((count[0] & 0x3f)<<8) | count[1]; 
1996/0531    
			ensure(s.s, &s.s->processed, len+1); 
			consume(&s.s->processed, count, 1); 
1996/1029    
			ensure(s.s, &s.s->unprocessed, len+1); 
			consume(&s.s->unprocessed, count, 1); 
1995/1217    
			pad = count[0]; 
1996/1029    
			if(pad > len){ 
				print("pad %d buf len %d\n", pad, len); 
				error("bad pad in ssl message"); 
			} 
1995/1217    
		} 
 
		/* trade memory bandwidth for less processing complexity */ 
1996/0531    
		b = s.s->processed = pullupblock(s.s->processed, len); 
1996/1029    
		/* put extra on unprocessed queue */ 
		s.s->processed = qremove(&s.s->unprocessed, len, 0); 
1995/1217    
 
		/* put remainder on unprocessed queue */ 
		i = BLEN(b); 
		if(i > len){ 
			i -= len; 
1996/0531    
			s.s->unprocessed = allocb(i); 
			memmove(s.s->unprocessed->wp, b->rp+len, i); 
			s.s->unprocessed->wp += i; 
1995/1217    
			b->wp -= i; 
1996/1029    
		if(waserror()){ 
			qunlock(&s.s->in.ctlq); 
			nexterror(); 
1995/1217    
		} 
                 
1996/0531    
		if(s.s->encryptalg) 
			b = decryptb(s.s, b); 
1995/1218    
		else { 
1996/0531    
			if(BLEN(b) < s.s->diglen) 
1995/1218    
				error("baddigest"); 
1996/0531    
			checkdigestb(s.s, b); 
			b->rp += s.s->diglen; 
1996/1029    
		qlock(&s.s->in.ctlq); 
		switch(s.s->state){ 
		case Sencrypting: 
			s.s->processed = decryptb(s.s, s.s->processed); 
			break; 
		case Sdigesting: 
			s.s->processed = pullupblock(s.s->processed, s.s->diglen); 
			if(s.s->processed == 0) 
				error("ssl message too short"); 
			checkdigestb(s.s, s.s->processed); 
			s.s->processed->rp += s.s->diglen; 
			break; 
1995/1218    
		} 
1996/1029    
		qunlock(&s.s->in.ctlq); 
		poperror(); 
1995/1217    
 
		/* remove pad */ 
1995/1218    
		if(b->wp - b->rp < pad) 
1995/1217    
			panic("sslbread"); 
		b->wp -= pad; 
1996/0531    
		s.s->processed = b; 
1996/1029    
		if(pad) 
			s.s->processed = qremove(&s.s->processed, len - pad, 1); 
1995/1217    
	} 
 
	if(BLEN(b) > n){ 
		b = allocb(n); 
1996/0531    
		memmove(b->wp, s.s->processed->rp, n); 
1995/1217    
		b->wp += n; 
1996/0531    
		s.s->processed->rp += n; 
1995/1217    
	} else  
1996/0531    
		s.s->processed = b->next; 
1996/1029    
	/* return at most what was asked for */ 
	b = qremove(&s.s->processed, n, 0); 
1995/1217    
 
1996/0531    
	qunlock(&s.s->in.q); 
1995/1217    
	poperror(); 
1996/0601/sys/src/9/port/devssl.c:280,3021996/1029/sys/src/9/port/devssl.c:564,602
1996/0223    
sslread(Chan *c, void *a, long n, ulong offset) 
1995/1213    
{ 
1996/0531    
	volatile struct { Block *b; } b; 
1996/1029    
	Block *nb; 
	uchar *va; 
	int i; 
	char buf[128]; 
1995/1213    
 
	switch(c->qid.path & ~CHDIR){ 
1996/0223    
	case Qdir: 
		return devdirread(c, a, n, digesttab, Ndigesttab, devgen); 
1996/1029    
	if(c->qid.path & CHDIR) 
		return devdirread(c, a, n, 0, 0, sslgen); 
 
	switch(TYPE(c->qid)) { 
	default: 
		error(Ebadusefd); 
	case Qctl: 
		sprint(buf, "%d", CONV(c->qid)); 
		return readstr(offset, a, n, buf); 
	case Qdata: 
		b.b = sslbread(c, n, offset); 
		break; 
1995/1213    
	} 
 
1996/0531    
	b.b = sslbread(c, n, offset); 
1995/1213    
                 
1996/0223    
	if(waserror()){ 
1996/0531    
		freeb(b.b); 
1996/1029    
		freeblist(b.b); 
1996/0223    
		nexterror(); 
1995/1213    
	} 
 
1996/0531    
	n = BLEN(b.b); 
	memmove(a, b.b->rp, n); 
	freeb(b.b); 
1996/1029    
	n = 0; 
	va = a; 
	for(nb = b.b; nb; nb = nb->next){ 
		i = BLEN(nb); 
		memmove(va+n, nb->rp, i); 
		n += i; 
	} 
1996/0223    
 
1996/1029    
	freeblist(b.b); 
1996/0223    
	poperror(); 
 
1995/1213    
	return n; 
1996/0601/sys/src/9/port/devssl.c:303,3081996/1029/sys/src/9/port/devssl.c:603,630
1995/1213    
} 
 
1995/1215    
/* 
1996/1029    
 *  this algorithm doesn't have to be great since we're just 
 *  trying to obscure the block fill 
 */ 
static void 
randfill(uchar *buf, int len) 
{ 
	int j; 
	ushort rn; 
 
	j = 0; 
	rn = 0; 
	while(len-- > 0){ 
		if(j == 0){ 
			rn = nrand(1<<16); 
			*buf++ = rn; 
		} else 
			*buf++ = rn>>8; 
		j ^= 1; 
	} 
} 
 
/* 
1995/1215    
 *  use SSL record format, add in count and digest or encrypt 
 */ 
long 
1996/0601/sys/src/9/port/devssl.c:315,3291996/1029/sys/src/9/port/devssl.c:637,655
1995/1217    
	uchar *p; 
1995/1215    
 
1996/0531    
	bb.b = b; 
	s.s = c->aux; 
	if(s.s == 0 || s.s->state != Established) 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslbwrite"); 
	if(s.s->state == Sincomplete){ 
		freeb(b); 
1995/1215    
		error(Ebadusefd); 
1996/1029    
	} 
1995/1215    
 
	if(waserror()){ 
1996/0531    
		qunlock(&s.s->out.q); 
		if(bb.b) 
			freeb(bb.b); 
		dighangup(s.s); 
1996/1029    
		sslhangup(s.s); 
1995/1215    
		nexterror(); 
	} 
1996/0531    
	qlock(&s.s->out.q); 
1996/0601/sys/src/9/port/devssl.c:366,3721996/1029/sys/src/9/port/devssl.c:692,698
1995/1215    
		/* SSL style count */ 
		if(pad){ 
1995/1218    
			nb = padblock(nb, -pad); 
1995/1215    
			memset(nb->wp, 0, pad); 
1996/1029    
			randfill(nb->wp, pad); 
1995/1227    
			nb->wp += pad; 
1995/1215    
			m += pad; 
1995/1218    
 
1996/0601/sys/src/9/port/devssl.c:382,3941996/1029/sys/src/9/port/devssl.c:708,725
1995/1217    
			offset = 2; 
		} 
1995/1213    
 
1996/0531    
		if(s.s->encryptalg) 
1996/1029    
		switch(s.s->state){ 
		case Sencrypting: 
1996/0531    
			nb = encryptb(s.s, nb, offset); 
1995/1215    
		else 
1996/1029    
			break; 
		case Sdigesting: 
1996/0531    
			nb = digestb(s.s, nb, offset); 
1996/1029    
			break; 
		} 
1995/1213    
 
1996/0531    
		(*devtab[s.s->c->type].bwrite)(s.s->c, nb, offset); 
1995/1213    
                 
1996/1029    
		m = BLEN(nb); 
		(*devtab[s.s->c->type].bwrite)(s.s->c, nb, s.s->c->offset); 
		s.s->c->offset += m; 
1995/1215    
	} 
1996/0531    
	qunlock(&s.s->out.q); 
1995/1215    
	poperror(); 
1996/0601/sys/src/9/port/devssl.c:396,4731996/1029/sys/src/9/port/devssl.c:727,804
1995/1215    
	return rv; 
1996/0223    
} 
 
1996/1029    
static void 
setsecret(OneWay *w, uchar *secret, int n) 
{ 
	if(w->secret) 
		free(w->secret); 
 
	w->secret = malloc(n); 
	memmove(w->secret, secret, n); 
	w->slen = n; 
	w->mid = 0; 
 
} 
 
#ifdef NOSPOOKS 
static void 
initDESkey(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
	w->state = malloc(sizeof(DESstate)); 
	if(w->slen >= 16) 
		setupDESstate(w->state, w->secret, w->secret+8); 
	else if(w->slen >= 8) 
		setupDESstate(w->state, w->secret, 0); 
	else 
		error("secret too short"); 
} 
#endif NOSPOOKS 
 
static void 
initRC4key(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
#ifndef NOSPOOKS 
	if(w->slen > 5) 
		w->slen = 5; 
#endif NOSPOOKS 
 
	w->state = malloc(sizeof(RC4state)); 
	setupRC4state(w->state, w->secret, w->slen); 
} 
 
1996/0223    
long 
sslwrite(Chan *c, void *a, long n, ulong offset) 
{ 
	Dstate *s; 
1996/1029    
	volatile struct { Dstate *s; } s; 
1996/0531    
	volatile struct { Block *b; } b; 
1996/0223    
	int m; 
1996/1029    
	int m, t; 
1996/0223    
	char *p, *e, buf[32]; 
 
	switch(c->qid.path & ~CHDIR){ 
	case Qclone: 
		break; 
	default: 
		error(Ebadusefd); 
	} 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslwrite"); 
1996/0223    
 
	s = c->aux; 
	if(s == 0) 
		error(Ebadusefd); 
1996/1029    
	t = TYPE(c->qid); 
	if(t == Qdata){ 
		if(s.s->state == Sincomplete) 
			error(Ebadusefd); 
1996/0223    
 
	switch(s->state){ 
	case Algwait: 
		/* get algorithm */ 
		if(n >= sizeof(buf)) 
			error(Ebadarg); 
		strncpy(buf, a, n); 
		buf[n] = 0; 
		s->blocklen = 1; 
		s->diglen = 0; 
		if(strcmp(buf, "md5") == 0){ 
			s->hf = md5; 
			s->diglen = MD5dlen; 
		} else if(strcmp(buf, "sha") == 0){ 
			s->hf = sha; 
			s->diglen = SHAdlen; 
		} else if(strcmp(buf, "descbc") == 0){ 
			s->encryptalg = DESCBC; 
			s->blocklen = 8; 
		} else if(strcmp(buf, "desecb") == 0){ 
			s->encryptalg = DESECB; 
			s->blocklen = 8; 
		} else 
			error(Ebadarg); 
		s->state = Fdwait; 
		break; 
	case Fdwait: 
		/* get communications channel */ 
		s->c = buftochan(a, n); 
		s->state = Secretinwait; 
		break; 
	case Secretinwait: 
		/* get secret for incoming messages */ 
		setsecret(s, &s->in, a, n); 
		s->state = Secretoutwait; 
		break; 
	case Secretoutwait: 
		/* get secret for outgoing messages */ 
		setsecret(s, &s->out, a, n); 
		if(s->blocklen != 1){ 
			s->max = (1<<15) - s->diglen; 
			s->max -= s->max % s->blocklen; 
			s->maxpad = (1<<14) - s->diglen; 
			s->maxpad -= s->maxpad % s->blocklen; 
		} else 
			s->maxpad = s->max = (1<<15) - s->diglen; 
		s->state = Established; 
		break; 
	case Established: 
		p = a; 
		for(e = p + n; p < e; p += m){ 
1996/1029    
		e = p + n; 
		do { 
1996/0223    
			m = e - p; 
			if(m > s->max) 
				m = s->max; 
1996/1029    
			if(m > s.s->max) 
				m = s.s->max; 
1996/0223    
	 
1996/0531    
			b.b = allocb(m); 
1996/0223    
			if(waserror()){ 
1996/0601/sys/src/9/port/devssl.c:479,5811996/1029/sys/src/9/port/devssl.c:810,946
1996/0531    
			b.b->wp += m; 
1996/0223    
	 
1996/0531    
			sslbwrite(c, b.b, offset); 
1996/0223    
		} 
		break; 
1996/1029    
 
			p += m; 
		} while(p < e); 
		return n; 
	} 
 
	/* mutex with operations using what we're about to change */ 
	if(waserror()){ 
		qunlock(&s.s->in.ctlq); 
		qunlock(&s.s->out.q); 
		nexterror(); 
	} 
	qlock(&s.s->in.ctlq); 
	qlock(&s.s->out.q); 
 
	switch(t){ 
1996/0223    
	default: 
		error(Ebadusefd); 
1996/1029    
		panic("sslwrite"); 
	case Qsecretin: 
		setsecret(&s.s->in, a, n); 
		goto out; 
		return n; 
	case Qsecretout: 
		setsecret(&s.s->out, a, n); 
		goto out; 
		return n; 
	case Qctl: 
		break; 
1996/0223    
	} 
 
	return n; 
1995/1213    
} 
1996/1029    
	if(n >= sizeof(buf)) 
		error(Ebadarg); 
	strncpy(buf, a, n); 
	buf[n] = 0; 
	p = strchr(buf, '\n'); 
	if(p) 
		*p = 0; 
	p = strchr(buf, ' '); 
	if(p) 
		*p++ = 0; 
1995/1213    
 
/* 
 *  make sure we have at least 'n' bytes in list 'l' 
 */ 
static void 
ensure(Dstate *s, Block **l, int n) 
{ 
	int i, sofar; 
	Block *b; 
1996/1029    
	if(strcmp(buf, "fd") == 0){ 
		s.s->c = buftochan(p); 
1995/1213    
 
	b = *l; 
	if(b){ 
		sofar = BLEN(b); 
		l = &b->next; 
	} else 
		sofar = 0; 
1996/1029    
		/* default is clear (msg delimiters only) */ 
		s.s->state = Sclear; 
		s.s->blocklen = 1; 
		s.s->diglen = 0; 
		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
	} else if(strcmp(buf, "alg") == 0 && p != 0){ 
		s.s->blocklen = 1; 
		s.s->diglen = 0; 
1995/1213    
 
	while(sofar < n){ 
		b = (*devtab[s->c->type].bread)(s->c, Maxdmsg, 0); 
		if(b == 0) 
			error(Ehungup); 
		i = BLEN(b); 
		if(i <= 0){ 
			freeb(b); 
			continue; 
1996/1029    
		if(s.s->c == 0) 
			error("must set fd before algorithm"); 
 
		if(strcmp(p, "clear") == 0){ 
			s.s->state = Sclear; 
			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
			goto out; 
1995/1213    
		} 
 
		*l = b; 
		l = &b->next; 
		sofar += i; 
	} 
} 
1996/1029    
		if(s.s->in.secret && s.s->out.secret == 0) 
			setsecret(&s.s->out, s.s->in.secret, s.s->in.slen); 
		if(s.s->out.secret && s.s->in.secret == 0) 
			setsecret(&s.s->in, s.s->out.secret, s.s->out.slen); 
		if(strcmp(p, "md5") == 0){ 
			s.s->hf = md5; 
			s.s->diglen = MD5dlen; 
			s.s->state = Sdigesting; 
		} else if(strcmp(p, "sha") == 0){ 
			s.s->hf = sha; 
			s.s->diglen = SHAdlen; 
			s.s->state = Sdigesting; 
#ifdef NOSPOOKS 
		} else if(strcmp(p, "descbc") == 0){ 
			if(s.s->in.secret == 0 || s.s->out.secret == 0) 
				error(Ebadarg); 
			s.s->encryptalg = DESCBC; 
			s.s->blocklen = 8; 
			initDESkey(&s.s->in); 
			initDESkey(&s.s->out); 
			s.s->state = Sencrypting; 
		} else if(strcmp(p, "desecb") == 0){ 
			if(s.s->in.secret == 0 || s.s->out.secret == 0) 
				error(Ebadarg); 
			s.s->encryptalg = DESECB; 
			s.s->blocklen = 8; 
			initDESkey(&s.s->in); 
			initDESkey(&s.s->out); 
			s.s->state = Sencrypting; 
#endif NOSPOOKS 
		} else if(strcmp(p, "rc4") == 0){ 
			if(s.s->in.secret == 0 || s.s->out.secret == 0) 
				error(Ebadarg); 
			s.s->encryptalg = RC4; 
			s.s->blocklen = 1; 
			initRC4key(&s.s->in); 
			initRC4key(&s.s->out); 
			s.s->state = Sencrypting; 
		} else 
			error(Ebadarg); 
1995/1213    
 
/* 
 *  copy 'n' bytes from 'l' into 'p' and free 
 *  the bytes in 'l' 
 */ 
static void 
consume(Block **l, uchar *p, int n) 
{ 
	Block *b; 
	int i; 
1996/1029    
		if(s.s->blocklen != 1){ 
			s.s->max = (1<<15) - s.s->diglen - 1; 
			s.s->max -= s.s->max % s.s->blocklen; 
			s.s->maxpad = (1<<14) - s.s->diglen - 1; 
			s.s->maxpad -= s.s->maxpad % s.s->blocklen; 
		} else 
			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
	} else 
		error(Ebadarg); 
1995/1213    
 
	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)) 
			break; 
		*l = b->next; 
		freeb(b); 
	} 
1996/1029    
out: 
	qunlock(&s.s->in.ctlq); 
	qunlock(&s.s->out.q); 
	poperror(); 
	return n; 
1995/1213    
} 
 
1995/1217    
static void 
1995/1218    
setsecret(Dstate *s, OneWay *w, uchar *secret, int n) 
1995/1213    
{ 
1996/0531    
	w->secret = malloc(n); 
1995/1217    
	memmove(w->secret, secret, n); 
	w->slen = n; 
	w->mid = 0; 
1995/1213    
 
1995/1217    
	switch(s->encryptalg){ 
1995/1218    
	case DESECB: 
		if(n < 8) 
			error("secret too small"); 
1996/0531    
		w->state = malloc(sizeof(DESstate)); 
1995/1217    
		setupDESstate(w->state, secret, 0); 
		break; 
	case DESCBC: 
1995/1218    
		if(n < 16) 
			error("secret too small"); 
1996/0531    
		w->state = malloc(sizeof(DESstate)); 
1995/1217    
		setupDESstate(w->state, secret, secret+8); 
		break; 
	} 
} 
1995/1213    
                 
1995/1217    
static Block* 
encryptb(Dstate *s, Block *b, int offset) 
{ 
1996/1029    
#ifdef NOSPOOKS 
1995/1218    
	uchar *p, *ep, *p2, *ip, *eip; 
1995/1217    
	DESstate *ds; 
1996/1029    
#endif NOSPOOKS 
1995/1213    
 
1995/1217    
	switch(s->encryptalg){ 
1996/1029    
#ifdef NOSPOOKS 
1995/1218    
	case DESECB: 
1995/1217    
		ds = s->out.state; 
		ep = b->rp + BLEN(b); 
1996/0601/sys/src/9/port/devssl.c:594,6331996/1029/sys/src/9/port/devssl.c:959,1026
1995/1218    
			memmove(ds->ivec, p, 8); 
		} 
1995/1217    
		break; 
1996/1029    
#endif NOSPOOKS 
	case RC4: 
		rc4(s->out.state, b->rp + offset, BLEN(b) - offset); 
		break; 
1995/1213    
	} 
1995/1217    
	return b; 
} 
1995/1213    
 
1995/1217    
static Block* 
decryptb(Dstate *s, Block *b) 
1996/1029    
decryptb(Dstate *s, Block *inb) 
1995/1217    
{ 
1996/1029    
	Block *b, **l; 
#ifdef NOSPOOKS 
1995/1218    
	uchar *p, *ep, *tp, *ip, *eip; 
1995/1217    
	DESstate *ds; 
1995/1218    
	uchar tmp[8]; 
1996/1029    
#endif NOSPOOKS 
	int i; 
1995/1213    
 
1995/1217    
	switch(s->encryptalg){ 
1995/1218    
	case DESECB: 
1995/1217    
		ds = s->out.state; 
		ep = b->rp + BLEN(b); 
		for(p = b->rp + s->diglen; p < ep; p += 8) 
			block_cipher(ds->expanded, p, 1); 
		break; 
	case DESCBC: 
		ds = s->out.state; 
		ep = b->rp + BLEN(b); 
1995/1218    
		for(p = b->rp + s->diglen; p < ep;){ 
			memmove(tmp, p, 8); 
			block_cipher(ds->expanded, p, 1); 
			tp = tmp; 
			ip = ds->ivec; 
			for(eip = ip+8; ip < eip; ){ 
				*p++ ^= *ip; 
				*ip++ = *tp++; 
1996/1029    
	l = &inb; 
	for(b = inb; b; b = b->next){ 
		/* make sure we have a multiple of s->blocklen */ 
		if(s->blocklen > 1){ 
			i = BLEN(b); 
			if(i % s->blocklen){ 
				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen)); 
				if(b == 0) 
					error("ssl encrypted message too short"); 
1995/1218    
			} 
		} 
1995/1217    
		break; 
1996/1029    
		l = &b->next; 
 
		/* decrypt */ 
		switch(s->encryptalg){ 
#ifdef NOSPOOKS 
		case DESECB: 
			ds = s->in.state; 
			ep = b->rp + BLEN(b); 
			for(p = b->rp + s->diglen; p < ep; p += 8) 
				block_cipher(ds->expanded, p, 1); 
			break; 
		case DESCBC: 
			ds = s->in.state; 
			ep = b->rp + BLEN(b); 
			for(p = b->rp + s->diglen; p < ep;){ 
				memmove(tmp, p, 8); 
				block_cipher(ds->expanded, p, 1); 
				tp = tmp; 
				ip = ds->ivec; 
				for(eip = ip+8; ip < eip; ){ 
					*p++ ^= *ip; 
					*ip++ = *tp++; 
				} 
			} 
			break; 
#endif NOSPOOKS 
		case RC4: 
			rc4(s->in.state, b->rp, BLEN(b)); 
			break; 
		} 
1995/1217    
	} 
1995/1213    
	return b; 
1996/1029    
	return inb; 
1995/1213    
} 
 
1995/1217    
static Block* 
1996/0601/sys/src/9/port/devssl.c:662,6681996/1029/sys/src/9/port/devssl.c:1055,1061
1995/1215    
} 
1995/1213    
 
1995/1217    
static void 
checkdigestb(Dstate *s, Block *b) 
1996/1029    
checkdigestb(Dstate *s, Block *inb) 
1995/1215    
{ 
1995/1217    
	uchar *p; 
	DigestState ss; 
1996/0601/sys/src/9/port/devssl.c:670,6861996/1029/sys/src/9/port/devssl.c:1063,1087
1995/1218    
	int n, h; 
1995/1217    
	OneWay *w; 
	uchar digest[128]; 
1996/1029    
	Block *b; 
1995/1213    
 
1995/1217    
	w = &s->in; 
1995/1213    
 
1995/1217    
	memset(&ss, 0, sizeof(ss)); 
	h = s->diglen; 
	n = BLEN(b) - h; 
 
	/* hash secret + message */ 
1996/1029    
	/* hash secret */ 
1995/1217    
	(*s->hf)(w->secret, w->slen, 0, &ss); 
1995/1218    
	(*s->hf)(b->rp + h, n, 0, &ss); 
1995/1217    
 
1996/1029    
	/* hash message */ 
	h = s->diglen; 
	for(b = inb; b; b = b->next){ 
		n = BLEN(b) - h; 
		if(n < 0) 
			panic("checkdigestb"); 
		(*s->hf)(b->rp + h, n, 0, &ss); 
		h = 0; 
	} 
 
1995/1217    
	/* hash message id */ 
	p = msgid; 
	n = w->mid++; 
1996/0601/sys/src/9/port/devssl.c:690,7131996/1029/sys/src/9/port/devssl.c:1091,1112
1995/1217    
	*p = n; 
1995/1218    
	(*s->hf)(msgid, 4, digest, &ss); 
1995/1217    
 
1995/1218    
	if(memcmp(digest, b->rp, s->diglen) != 0) 
1996/1029    
	if(memcmp(digest, inb->rp, s->diglen) != 0) 
1995/1217    
		error("bad digest"); 
1995/1213    
} 
 
1995/1215    
/* get channel associated with an fd */ 
1995/1213    
static Chan* 
buftochan(char *a, long n) 
1996/1029    
buftochan(char *p) 
1995/1213    
{ 
	Chan *c; 
	int fd; 
	char buf[32]; 
 
	if(n >= sizeof buf) 
		error(Egreg); 
	memmove(buf, a, n);		/* so we can NUL-terminate */ 
	buf[n] = 0; 
	fd = strtoul(buf, 0, 0); 
                 
1996/1029    
	if(p == 0) 
		error(Ebadarg); 
	fd = strtoul(p, 0, 0); 
	if(fd < 0) 
		error(Ebadarg); 
1995/1213    
	c = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */ 
	return c; 
} 
1996/0601/sys/src/9/port/devssl.c:714,7201996/1029/sys/src/9/port/devssl.c:1113,1119
1995/1213    
 
1995/1215    
/* hand up a digest connection */ 
static void 
dighangup(Dstate *s) 
1996/1029    
sslhangup(Dstate *s) 
1995/1213    
{ 
1995/1215    
	Block *b; 
1995/1213    
 
1996/0601/sys/src/9/port/devssl.c:727,7331996/1029/sys/src/9/port/devssl.c:1126,1132
1995/1215    
		freeb(s->unprocessed); 
		s->unprocessed = 0; 
1995/1213    
	} 
1995/1215    
	s->state = Closed; 
1996/1029    
	s->state = Sincomplete; 
1996/0531    
	qunlock(&s->in.q); 
1995/1213    
} 
 
1996/0601/sys/src/9/port/devssl.c:739,7491996/1029/sys/src/9/port/devssl.c:1138,1150
1995/1213    
handle_exception(int type, char *exception) 
{ 
	if(type == CRITICAL) 
1996/0531    
		panic("crypt library (devssl): %s", exception); 
1996/1029    
		panic("crypt library: %s: %r", exception); 
1995/1213    
	else 
1996/0531    
		print("crypt library (devssl): %s\n", exception); 
1996/1029    
		print("crypt library: %s: %r\n", exception); 
1995/1213    
} 
 
1996/1029    
extern void rbcheck(char*); 
 
1995/1213    
void* 
crypt_malloc(int size) 
{ 
1996/0601/sys/src/9/port/devssl.c:762,7641996/1029/sys/src/9/port/devssl.c:1163,1232
1995/1213    
		handle_exception(CRITICAL, "freeing null pointer"); 
	free(x); 
} 
1996/1029    
 
 
static Dstate* 
dsclone(Chan *ch) 
{ 
	Dstate **pp, **ep, **np; 
	int newmax; 
 
	if(waserror()) { 
		unlock(&dslock); 
		nexterror(); 
	} 
	lock(&dslock); 
	ep = &dstate[maxdstate]; 
	for(pp = dstate; pp < ep; pp++) { 
		if(*pp == 0) { 
			dsnew(ch, pp); 
			break; 
		} 
	} 
	if(pp >= ep) { 
		if(maxdstate >= Maxdstate) { 
			unlock(&dslock); 
			poperror(); 
			return 0; 
		} 
		newmax = 2 * maxdstate; 
		if(newmax > Maxdstate) 
			newmax = Maxdstate; 
		np = smalloc(sizeof(Dstate*) * newmax); 
		if(np == 0) 
			error(Enomem); 
		memmove(np, dstate, sizeof(Dstate*) * maxdstate); 
		dstate = np; 
		pp = &dstate[maxdstate]; 
		memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate)); 
		maxdstate = newmax; 
		dsnew(ch, pp); 
	} 
	unlock(&dslock); 
	poperror(); 
	return *pp; 
} 
 
static void 
dsnew(Chan *ch, Dstate **pp) 
{ 
	Dstate *s; 
	int t; 
 
	*pp = s = malloc(sizeof(*s)); 
	if(!s) 
		error(Enomem); 
	if(pp - dstate >= dshiwat) 
		dshiwat++; 
	memset(s, 0, sizeof(*s)); 
	s->state = Sincomplete; 
	s->ref = 1; 
	strncpy(s->user, up->user, sizeof(s->user)); 
	s->perm = 0660; 
	t = TYPE(ch->qid); 
	if(t == Qclonus) 
		t = Qctl; 
	ch->qid.path = QID(pp - dstate, t); 
	ch->qid.vers = 0; 
} 
 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)