Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devssl.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devssl.c 1995/1213
## diff -e /dev/null /n/fornaxdump/1995/1213/sys/src/brazil/port/devssl.c
0a
/*
 *  template for making a new device
 */

#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	<libcrypt.h>

#include	"devtab.h"

typedef struct OneWay OneWay;
struct OneWay
{
	QLock;

	void		*state;		/* encryption state */
	int		slen;		/* hash data length */
	uchar		*secret;	/* secret */
	ulong		mid;		/* message id */
};

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,

	/* encryption algorithms */
	DESCBC=		1,
};

typedef struct Dstate Dstate;
struct Dstate
{
	Chan	*c;		/* io channel */
	uchar	state;		/* state of connection */
	uchar	encryptalg;	/* encryption algorithm */
	ushort	blocking;	/* blocking length */

	ushort	diglen;		/* length of digest */
	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */

	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;
};

enum
{
	Maxdmsg=	1<<16,
};

enum{
	Qdir,
	Qclone,
};
Dirtab digesttab[]={
	"digestclone",		{Qclone, 0},	0,	0600,
};
#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;

void producerand(void);

void
sslreset(void)
{
	randq.ep = randq.buf + sizeof(randq.buf);
	randq.rp = randq.wp = randq.buf;
}

void
sslinit(void)
{
}

Chan *
sslattach(char *spec)
{
	return devattach('D', spec);
}

Chan *
sslclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
sslwalk(Chan *c, char *name)
{
	return devwalk(c, name, digesttab, Ndigesttab, devgen);
}

void
sslstat(Chan *c, char *db)
{
	devstat(c, db, digesttab, Ndigesttab, devgen);
}

Chan *
sslopen(Chan *c, int omode)
{
	Dstate *s;

	switch(c->qid.path & ~CHDIR){
	case Qclone:
		s = smalloc(sizeof(Dstate));
		memset(s, 0, sizeof(*s));
		s->state = Algwait;
		c->aux = s;
		break;
	}
	return devopen(c, omode, digesttab, Ndigesttab, devgen);
}

void
sslcreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
	error(Eperm);
}

void
sslremove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void
sslwstat(Chan *c, char *dp)
{
	USED(c, dp);
	error(Eperm);
}

static void
dighangup(Dstate *s)
{
	Block *b;

	qlock(&s->in);
	for(b = s->processed; b; b = s->processed){
		s->processed = b->next;
		freeb(b);
	}
	if(s->unprocessed){
		freeb(s->unprocessed);
		s->unprocessed = 0;
	}
	s->state = Closed;
	qunlock(&s->in);
}

void
sslclose(Chan *c)
{
	Dstate *s;

	if(c->aux){
		s = c->aux;
		dighangup(s);
		if(s->c)
			close(s->c);
		if(s->in.secret)
			free(s->in.secret);
		if(s->out.secret)
			free(s->out.secret);
		free(s);
	}
}

long
sslread(Chan *c, void *a, long n, ulong offset)
{
	Block *b;

	switch(c->qid.path & ~CHDIR){
	case Qdir:
		return devdirread(c, a, n, digesttab, Ndigesttab, devgen);
	}

	b = sslbread(c, n, offset);

	if(waserror()){
		freeb(b);
		nexterror();
	}

	n = BLEN(b);
	memmove(a, b->rp, n);
	freeb(b);

	poperror();

	return n;
}

static void
setsecret(OneWay *w, uchar *secret, int n)
{
	w->secret = smalloc(n);
	memmove(w->secret, secret, n);
	w->slen = n;
	w->mid = 0;

	switch(s->encryptalg){
	case DESCBC:
		w->state = smalloc(sizeof(DESstate));
		setupDESstate(w->state, secret, 0);
		break;
	case DESCBC:
		w->state = smalloc(sizeof(DESstate));
		setupDESstate(w->state, secret, secret+8);
		break;
	}
}

long
sslwrite(Chan *c, char *a, long n, ulong offset)
{
	Dstate *s;
	Block *b;
	int m, sofar;
	char buf[32];

	switch(c->qid.path & ~CHDIR){
	case Qclone:
		break;
	default:
		error(Ebadusefd);
	}

	s = c->aux;
	if(s == 0)
		error(Ebadusefd);

	switch(s->state){
	case Algwait:
		/* get algorithm */
		if(n >= sizeof(buf))
			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, "desebc") == 0){
			s->encryptalg = DESEBC;
			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->in, a, n);
		s->state = Secretoutwait;
		break;
	case Secretoutwait:
		/* get secret for outgoing messages */
		setsecret(&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:
		sofar = 0;
		do {
			m = n - sofar;
			if(m > s->max)
				m = s->max;
	
			b = allocb(m);
			if(waserror()){
				freeb(b);
				nexterror();
			}
			memmove(b->wp, a+sofar, m);
			poperror();
			b->wp += m;
	
			sslbwrite(c, b, offset);
	
			sofar += m;
		} while(sofar < n);
		break;
	default:
		error(Ebadusefd);
	}

	return n;
}

void
digestb(Dstate *s, Block *b, OneWay *w)
{
	Block *nb;
	uchar *p;
	DigestState ss;
	uchar msgid[4];
	ulong n, h;

	memset(&ss, 0, sizeof(ss));
	h = s->diglen + 2;
	n = BLEN(b) - h;

	/* hash secret + message */
	(*s->hf)(w->secret, w->slen, 0, &ss);
	(*s->hf)(nb->rp + h, n, 0, &ss);

	/* hash message id */
	p = msgid;
	n = w->mid++;
	*p++ = n>>24;
	*p++ = n>>16;
	*p++ = n>>8;
	*p = n;
	(*s->func)(msgid, 4, nb->rp + 2, &ss);
}

long
encryptb(Dstate *s, Block *b)
{
	ulong n, h;
	int j;
	uchar *p, *ep, *ip;
	DESstate *ds;

	h = s->diglen + 2;

	switch(s->encryptalg){
	case DESEBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + h; p < ep; p += 8)
			block_cipher(ds->expanded, p, 0);
		break;
	case DESCBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + h; p < ep; p += 8)
			bCBCEncrypt(p, ds->ivec, ds->expanded, 8);
		break;
	}
	
}

long
decryptb(Dstate *s, Block *b)
{
	ulong n, h;
	uchar *p, *ep;
	DESstate *ds;

	h = s->diglen + 2;

	switch(s->encryptalg){
	case DESEBC:
		ds = s->in.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + h; 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 + h; p < ep; p += 8)
			bCBCDecrypt(p, ds->ivec, ds->expanded, 8);
		break;
	}
}

/*
 *  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;

	b = *l;
	if(b){
		sofar = BLEN(b);
		l = &b->next;
	} else
		sofar = 0;

	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;
		}

		*l = b;
		l = &b->next;
		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))
			break;
		*l = b->next;
		freeb(b);
	}
}

static Block*
digestbread(Dstate *s, long n)
{
	Block *b;
	int i, m, len;
	uchar *p;
	uchar *dp;
	uchar digestin[32];
	uchar digest[32];
	DigestState ss;

	memset(&ss, 0, sizeof(ss));

	ensure(s, &s->unprocessed, s->diglen);
		len = 0;
		for(i = 0; i < 4; i++){
			consume(&s->unprocessed, digestin+i, 1);
			m = digestin[i];
			if((m & 0x80) == 0)
				break;
			len = (len<<7) | (m & 0x7f);
		}
	
		/* digest count */
		p = &digestin[s->diglen];
		(*s->func)(p, i, 0, &ss);
		ensure(s, &s->unprocessed, s->diglen);

		/* get message */
		s->processed = s->unprocessed;
		s->unprocessed = 0;
		ensure(s, &s->processed, len);

		/* digest message */
		i = 0;
		for(b = s->processed; b; b = b->next){
			i = BLEN(b);
			if(i >= len)
				break;
			(*s->func)(b->rp, i, 0, &ss);
			len -= i;
		}
		if(b == 0)
			panic("digestbread");
		if(i > len){
			i -= len;
			s->unprocessed = allocb(i);
			memmove(s->unprocessed->wp, b->rp+len, i);
			s->unprocessed->wp += i;
			b->wp -= i;
		}
		(*s->func)(b->rp, len, 0, &ss);

		/* digest secret & message id */
		p = s->in.secret;
		m = s->in.mid++;
		*p++ = m>>24;
		*p++ = m>>16;
		*p++ = m>>8;
		*p = m;
		(*s->func)(s->in.secret, s->in.slen, digest, &ss);

		if(memcmp(digest, digestin, s->diglen) != 0)
			error("bad digest");
	}

	b = s->processed;
	if(BLEN(b) > n){
		b = allocb(n);
		memmove(b->wp, s->processed->rp, n);
		b->wp += n;
		s->processed->rp += n;
	} else 
		s->processed = b->next;

	return b;
}

static Block*
sslbread(Chan *c, long n, ulong offset)
{
	Block *bp;
	uchar count[2];
	int len;
	int pad;

	USED(offset);

	s = c->aux;
	if(s == 0 || s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->in);
		dighangup(s);
		nexterror();
	}

	qlock(&s->in);

	/* get the whole message */
	ensure(s, &s->unprocessed, 2);
	consume(&s->unprocessed, count, 2);
	if(count[0] & 0x80){
		len = ((count[0] & 0x7f)<<8) | count[1];
		pad = 0;
	} else {
		len = ((count[0] & 0x3f)<<8) | count[1];
		ensure(s, &s->unprocessed, 1);
		consume(&s->unprocessed, count, 1);
		pad = count[0];
	}
	ensure(s, &s->unprocessed, len);
		
	if(s->encrypalg)
		b = decryptb(s, len);
	else
		b = digestb(s, len);

	if(pad)

	qunlock(&s->in);
	poperror();

	return b;
}

static Chan*
buftochan(char *a, long n)
{
	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);

	c = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
	return c;
}

/*
 *  use SSL record format, add in count and digest or encrypt
 */
long
sslbwrite(Chan *c, Block *b, ulong offset)
{
	Dstate *s;
	Block *nb;
	int h, n, m, pad, rv;

	s = c->aux;
	if(s == 0 || s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->out);
		if(b)
			freeb(b);
		dighangup(s);
		nexterror();
	}
	qlock(&s->out);

	rv = 0;
	while(b){
		m = n = BLEN(b);
		h = s->diglen + 2;

		/* padded blocks are shorter than unpadded ones (strange) */
		pad = 0;
		if(m > s->max){
			m = s->max;
		} else if(s->blocklen != 1){
			pad = m%s->blocklen;
			if(pad){
				pad = s->blocklen - pad;
				if(m > s->maxpad){
					pad = 0;
					m = s->maxpad;
				}
			}
		}

		rv += m;
		if(m != n){
			nb = allocb(m + h + pad);
			memmove(nb->wp + h, m, nb->rptr);
			nb->wp += m + h;
			b->rp += m;
		} else {
			/* add header */
			nb = padblock(b, h);
			nb->rp -= h;

			/* add pad */
			if(pad)
				nb = padblock(nb, -pad);
			b = 0;
		}

		/* SSL style count */
		if(pad){
			memset(nb->wp, 0, pad);
			m += pad;
			nb->wp += pad;
		} else
			m |= 0x8000;
		np->rp[0] = (m>>8);
		np->rp[1] = m;

		if(encryptalg)
			encryptb(s, nb);
		else
			digestb(s, nb);

		(*devtab[s->c->type].bwrite)(s->c, nb, offset);

	}
	qunlock(&s->out);
	poperror();

	return rv;
}

/*
 *  crypt's interface to system, included here to override the
 *  library version
 */
void
handle_exception(int type, char *exception)
{
	if(type == CRITICAL)
		panic("kernel ssl: %s", exception);
	else
		print("kernel ssl: %s\n", exception);
}

void*
crypt_malloc(int size)
{
	void *x;

	x = smalloc(size);
	if(x == 0)
		handle_exception(CRITICAL, "out of memory");
	return x;
}

void
crypt_free(void *x)
{
	if(x == 0)
		handle_exception(CRITICAL, "freeing null pointer");
	free(x);
}

.
## diffname port/devssl.c 1995/1215
## diff -e /n/fornaxdump/1995/1213/sys/src/brazil/port/devssl.c /n/fornaxdump/1995/1215/sys/src/brazil/port/devssl.c
696,699c
	s->state = Closed;
	qunlock(&s->in);
.
639,694c
	if(s->unprocessed){
		freeb(s->unprocessed);
		s->unprocessed = 0;
.
628,637c
	qlock(&s->in);
	for(b = s->processed; b; b = s->processed){
		s->processed = b->next;
		freeb(b);
.
624,626c
	Block *b;
.
618,622c
/* hand up a digest connection */
static void
dighangup(Dstate *s)
.
600a
/* get channel associated with an fd */
.
595,598c
	switch(s->encryptalg){
	case DESEBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + h; p < ep; p += 8)
			block_cipher(ds->expanded, p, 0);
		break;
	case DESCBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + h; p < ep; p += 8)
			bCBCEncrypt(p, ds->ivec, ds->expanded, 8);
		break;
	}
	
.
593c
	h = s->diglen + 2;
.
574,591c
long
encryptb(Dstate *s, Block *b)
{
	ulong n, h;
	int j;
	uchar *p, *ep, *ip;
	DESstate *ds;
.
572c
	/* hash message id */
	p = msgid;
	n = w->mid++;
	*p++ = n>>24;
	*p++ = n>>16;
	*p++ = n>>8;
	*p = n;
	(*s->func)(msgid, 4, nb->rp + 2, &ss);
}
.
566,570c
	/* hash secret + message */
	(*s->hf)(w->secret, w->slen, 0, &ss);
	(*s->hf)(nb->rp + h, n, 0, &ss);
.
562,564c
	memset(&ss, 0, sizeof(ss));
	h = s->diglen + 2;
	n = BLEN(b) - h;
.
560c
	w = &s->out;
.
555,558c
	Block *nb;
	uchar *p;
	DigestState ss;
	uchar msgid[4];
	ulong n, h;
	OneWay *w;
.
552,553c
void
digestb(Dstate *s, Block *b)
.
392,393c
Block*
decryptb(Dstate *s, Block *b, int len)
.
389a
		/* read in the whole message */
		s->processed = s->unprocessed;
		s->unprocessed =- 0;
		ensure(s, &s->processed, 2);
		consume(&s->processed, count, 2);
		if(count[0] & 0x80){
			len = ((count[0] & 0x7f)<<8) | count[1];
			pad = 0;
		} else {
			len = ((count[0] & 0x3f)<<8) | count[1];
			ensure(s, &s->processed, 1);
			consume(&s->processed, count, 1);
			pad = count[0];
		}
		ensure(s, &s->processed, len);

		/* put remainder on unprocessed */
		i = 0;
		for(b = s->processed; b; b = b->next){
			i = BLEN(b);
			if(i >= len)
				break;
			(*s->func)(b->rp, i, 0, &ss);
			len -= i;
		}
		if(b == 0)
			panic("digestbread");
		if(i > len){
			i -= len;
			s->unprocessed = allocb(i);
			memmove(s->unprocessed->wp, b->rp+len, i);
			s->unprocessed->wp += i;
			b->wp -= i;
		}
			
		if(s->encrypalg)
			decryptb(s, len);
		else
			checkdigestb(s, len);

		if(pad){
			for(b = s->processed; b; b = b->next){
	}

	b = s->processed;
	if(BLEN(b) > n){
		b = allocb(n);
		memmove(b->wp, s->processed->rp, n);
		b->wp += n;
		s->processed->rp += n;
	} else 
		s->processed = b->next;

	qunlock(&s->in);
	poperror();

	return b;
.
388a
	qlock(&s->in);

	if(s->processed == 0){
.
375,387c
	s = c->aux;
	if(s == 0 || s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->in);
		dighangup(s);
		nexterror();
.
373c
	USED(offset);
.
368,371c
	Block *bp, **l;
	uchar count[2];
	int len;
	int pad;
.
365,366c
Block*
sslbread(Chan *c, long n, ulong offset)
.
355,362c
	}
	qunlock(&s->out);
	poperror();

	return rv;
.
351,353c
		(*devtab[s->c->type].bwrite)(s->c, nb, offset);
.
347,349c
		if(encryptalg)
			encryptb(s, nb);
		else
			digestb(s, nb);
.
342,345c
	int h, n, m, pad, rv;

	s = c->aux;
	if(s == 0 || s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->out);
		if(b)
			freeb(b);
		dighangup(s);
		nexterror();
	}
	qlock(&s->out);

	rv = 0;
	while(b){
		m = n = BLEN(b);
		h = s->diglen + 2;

		/* padded blocks are shorter than unpadded ones (strange) */
		pad = 0;
		if(m > s->max){
			m = s->max;
		} else if(s->blocklen != 1){
			pad = m%s->blocklen;
			if(pad){
				pad = s->blocklen - pad;
				if(m > s->maxpad){
					pad = 0;
					m = s->maxpad;
				}
			}
		}

		rv += m;
		if(m != n){
			nb = allocb(m + h + pad);
			memmove(nb->wp + h, m, b->rp);
			nb->wp += m + h;
			b->rp += m;
		} else {
			/* add header */
			nb = padblock(b, h);
			nb->rp -= h;

			/* add pad */
			if(pad)
				nb = padblock(nb, -pad);
			b = 0;
		}
		m += s->diglen;

		/* SSL style count */
		if(pad){
			memset(nb->wp, 0, pad);
			m += pad;
			nb->wp += pad;
		} else
			m |= 0x8000;
		np->rp[0] = (m>>8);
		np->rp[1] = m;
.
340a
	Dstate *s;
.
338,339c
/*
 *  use SSL record format, add in count and digest or encrypt
 */
long
sslbwrite(Chan *c, Block *b, ulong offset)
.
162,179d
## diffname port/devssl.c 1995/1217
## diff -e /n/fornaxdump/1995/1215/sys/src/brazil/port/devssl.c /n/fornaxdump/1995/1217/sys/src/brazil/port/devssl.c
687,701c
	memset(&ss, 0, sizeof(ss));
	h = s->diglen;
	n = BLEN(b) - h;

	/* hash secret + message */
	(*s->hf)(w->secret, w->slen, 0, &ss);
	(*s->hf)(nb->rp + h, n, 0, &ss);

	/* hash message id */
	p = msgid;
	n = w->mid++;
	*p++ = n>>24;
	*p++ = n>>16;
	*p++ = n>>8;
	*p = n;
	(*s->func)(msgid, 4, digest, &ss);

	if(memcmp(digest, nb->rp, s->diglen) != 0)
		error("bad digest");
.
685c
	w = &s->in;
.
681,683c
	OneWay *w;
	uchar digest[128];
.
679a
	Block *nb;
	uchar *p;
	DigestState ss;
	uchar msgid[4];
.
677,678c
static void
checkdigestb(Dstate *s, Block *b)
.
674c
	(*s->func)(msgid, 4, nb->rp+offset, &ss);

	retrn b;
.
660c
	h = s->diglen + offset;
.
647,648c
static Block*
digestb(Dstate *s, Block *b, int offset)
.
643a
	switch(s->encryptalg){
	case DESEBC:
		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);
		for(p = b->rp + s->diglen; p < ep; p += 8)
			bCBCDecrypt(p, ds->ivec, ds->expanded, 8);
		break;
	}
.
635,642c
static Block*
decryptb(Dstate *s, Block *b)
{
	ulong n, h;
	int j;
	uchar *p, *ep;
	DESstate *ds;
.
633a
	return b;
}
.
597,632c
	switch(s->encryptalg){
	case DESEBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + offset; p < ep; p += 8)
			block_cipher(ds->expanded, p, 0);
		break;
	case DESCBC:
		ds = s->out.state;
		ep = b->rp + BLEN(b);
		for(p = b->rp + offset; p < ep; p += 8)
			bCBCEncrypt(p, ds->ivec, ds->expanded, 8);
		break;
.
582,595c
static Block*
encryptb(Dstate *s, Block *b, int offset)
{
	ulong n;
	int j;
	uchar *p, *ep;
	DESstate *ds;
.
580c
	switch(s->encryptalg){
	case DESCBC:
		w->state = smalloc(sizeof(DESstate));
		setupDESstate(w->state, secret, 0);
		break;
	case DESCBC:
		w->state = smalloc(sizeof(DESstate));
		setupDESstate(w->state, secret, secret+8);
		break;
	}
}
.
572,578c
	w->secret = smalloc(n);
	memmove(w->secret, secret, n);
	w->slen = n;
	w->mid = 0;
.
569,570c
static void
setsecret(OneWay *w, uchar *secret, int n)
.
405,511d
394c
			nb = digestb(s, nb, ofsetf);
.
392c
			nb = encryptb(s, nb, offset);
.
388,389c
			p[0] = (m>>8);
			p[1] = m;
			offset = 2;
		}
.
386c
			p[0] = (m>>8);
			p[1] = m;
			p[2] = pad;
			offset = 3;
		} else {
.
381a
		p = np->rp;
.
328a
	uchar *p;
.
223a
	qlock(&s->in);

	if(s->processed == 0){
	
		/* read in the whole message */
		s->processed = s->unprocessed;
		s->unprocessed =- 0;
		ensure(s, &s->processed, 2);
		consume(&s->processed, count, 2);
		if(count[0] & 0x80){
			len = ((count[0] & 0x7f)<<8) | count[1];
			pad = 0;
		} else {
			len = ((count[0] & 0x3f)<<8) | count[1];
			ensure(s, &s->processed, 1);
			consume(&s->processed, count, 1);
			pad = count[0];
		}
		ensure(s, &s->processed, len);

		/* trade memory bandwidth for less processing complexity */
		b = s->processed = pullupblock(s->processed, len);

		/* put remainder on unprocessed queue */
		i = BLEN(b);
		if(i > len){
			i -= len;
			s->unprocessed = allocb(i);
			memmove(s->unprocessed->wp, b->rp+len, i);
			s->unprocessed->wp += i;
			b->wp -= i;
		}

		if(s->encrypalg)
			b = decryptb(s, b);
		else
			checkdigestb(s, b);

		/* remove pad */
		if(b->wp - b->rp > pad)
			panic("sslbread");
		b->wp -= pad;
		s->processed = b;
	}

	b = s->processed;
	if(BLEN(b) > n){
		b = allocb(n);
		memmove(b->wp, s->processed->rp, n);
		b->wp += n;
		s->processed->rp += n;
	} else 
		s->processed = b->next;

	qunlock(&s->in);
	poperror();

	return b;
.
214,222c
	USED(offset);

	s = c->aux;
	if(s == 0 || s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->in);
		dighangup(s);
		nexterror();
.
209,212c
	Block *bp, **l;
	uchar count[2];
	int len;
	int pad;
.
206,207c
Block*
sslbread(Chan *c, long n, ulong offset)
.
88a
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*, long);
static void	dighangup(Dstate*);


.
52c
	int	maxpad;		/* maximum padded data per msg */
.
## diffname port/devssl.c 1995/1218
## diff -e /n/fornaxdump/1995/1217/sys/src/brazil/port/devssl.c /n/fornaxdump/1995/1218/sys/src/brazil/port/devssl.c
672c
	if(memcmp(digest, b->rp, s->diglen) != 0)
.
670c
	(*s->hf)(msgid, 4, digest, &ss);
.
661c
	(*s->hf)(b->rp + h, n, 0, &ss);
.
649c
	int n, h;
.
645d
639c
	return b;
.
637c
	(*s->hf)(msgid, 4, b->rp + offset, &ss);
.
628c
	(*s->hf)(b->rp + h, n, 0, &ss);
.
613d
603,604c
		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++;
			}
		}
.
594c
	case DESECB:
.
591a
	uchar tmp[8];
.
588,590c
	uchar *p, *ep, *tp, *ip, *eip;
.
578,579c
		for(p = b->rp + offset; p < ep; p += 8){
			p2 = p;
			ip = ds->ivec;
			for(eip = ip+8; ip < eip; )
				*p2++ ^= *ip++;
			block_cipher(ds->expanded, p, 0);
			memmove(ds->ivec, p, 8);
		}
.
569c
	case DESECB:
.
563,565c
	uchar *p, *ep, *p2, *ip, *eip;
.
553a
		if(n < 16)
			error("secret too small");
.
549c
	case DESECB:
		if(n < 8)
			error("secret too small");
.
541c
setsecret(Dstate *s, OneWay *w, uchar *secret, int n)
.
472c
			nb = digestb(s, nb, offset);
.
469c
		if(s->encryptalg)
.
463,464c
			p = nb->rp;
			p[0] = (m>>8) | 0x80;
.
457c

			p = nb->rp;
.
455a
			b->wp += pad;
.
454a
			nb = padblock(nb, -pad);
.
453d
444,447d
441c
			/* add header space */
.
437c
			memmove(nb->wp + h, b->rp, m);
.
429a
				} else {
					pad = s->blocklen - pad;
					h++;
.
426d
419c
		/* trim to maximum block size */
.
379,381c
		}
.
374c
			memmove(b->wp, p, m);
.
363,365c
		p = a;
		for(e = p + n; p < e; p += m){
			m = e - p;
.
352c
		setsecret(s, &s->out, a, n);
.
347c
		setsecret(s, &s->in, a, n);
.
333,334c
		} else if(strcmp(buf, "desecb") == 0){
			s->encryptalg = DESECB;
.
301,302c
	int m;
	char *p, *e, buf[32];
.
297c
sslwrite(Chan *c, void *a, long n, ulong offset)
.
281d
275c
		if(b->wp - b->rp < pad)
.
272a
			b->rp += s->diglen;
		}
.
271c
		else {
			if(BLEN(b) < s->diglen)
				error("baddigest");
.
269c
		if(s->encryptalg)
.
254d
250c
			ensure(s, &s->processed, len+1);
.
246a
			ensure(s, &s->processed, len);
.
242c
		s->unprocessed = 0;
.
238c
	b = s->processed;
	if(b == 0){
.
222,223c
	int i, len, pad;
.
220c
	Dstate *s;
	Block *b;
.
91c
static void	setsecret(Dstate*, OneWay*, uchar*, int);
.
50a
	/* for SSL format */
.
46c
	ushort	blocklen;	/* blocking length */
.
37a
	DESECB=		2,
.
36a
	Noencryption=	0,
.
## diffname port/devssl.c 1995/1221
## diff -e /n/fornaxdump/1995/1218/sys/src/brazil/port/devssl.c /n/fornaxdump/1995/1221/sys/src/brazil/port/devssl.c
76c
	"ssl",		{Qclone, 0},	0,	0600,
.
## diffname port/devssl.c 1995/1227
## diff -e /n/fornaxdump/1995/1221/sys/src/brazil/port/devssl.c /n/fornaxdump/1995/1227/sys/src/brazil/port/devssl.c
459c
			nb->wp += pad;
.
## diffname port/devssl.c 1996/0103
## diff -e /n/fornaxdump/1995/1227/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/0103/sys/src/brazil/port/devssl.c
76c
	"ssl",		{Qclone, 0},	0,	0666,
.
## diffname port/devssl.c 1996/0202
## diff -e /n/fornaxdump/1996/0103/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/0202/sys/src/brazil/port/devssl.c
326c
			error(Ebadarg);
.
## diffname port/devssl.c 1996/0223
## diff -e /n/fornaxdump/1996/0202/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/0223/sys/src/brazil/port/devssl.c
485a
}

long
sslwrite(Chan *c, void *a, long n, ulong offset)
{
	Dstate *s;
	Block *b;
	int m;
	char *p, *e, buf[32];

	switch(c->qid.path & ~CHDIR){
	case Qclone:
		break;
	default:
		error(Ebadusefd);
	}

	s = c->aux;
	if(s == 0)
		error(Ebadusefd);

	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){
			m = e - p;
			if(m > s->max)
				m = s->max;
	
			b = allocb(m);
			if(waserror()){
				freeb(b);
				nexterror();
			}
			memmove(b->wp, p, m);
			poperror();
			b->wp += m;
	
			sslbwrite(c, b, offset);
		}
		break;
	default:
		error(Ebadusefd);
	}

	return n;
.
391a
	n = BLEN(b);
	memmove(a, b->rp, n);
	freeb(b);

	poperror();

.
322,389c
	if(waserror()){
		freeb(b);
		nexterror();
.
318,320c
	b = sslbread(c, n, offset);
.
312,315c
	case Qdir:
		return devdirread(c, a, n, digesttab, Ndigesttab, devgen);
.
308,309d
306d
304c
sslread(Chan *c, void *a, long n, ulong offset)
.
194,219d
13d
## diffname port/devssl.c 1996/0531
## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/0531/sys/src/brazil/port/devssl.c
761d
748c
	x = malloc(size);
.
740c
		print("crypt library (devssl): %s\n", exception);
.
738c
		panic("crypt library (devssl): %s", exception);
.
727c
	qunlock(&s->in.q);
.
717c
	qlock(&s->in.q);
.
562c
		w->state = malloc(sizeof(DESstate));
.
556c
		w->state = malloc(sizeof(DESstate));
.
547c
	w->secret = malloc(n);
.
477c
			sslbwrite(c, b.b, offset);
.
475c
			b.b->wp += m;
.
473c
			memmove(b.b->wp, p, m);
.
470c
				freeb(b.b);
.
468c
			b.b = allocb(m);
.
399c
	volatile struct { Block *b; } b;
.
389c
	qunlock(&s.s->out.q);
.
386c
		(*devtab[s.s->c->type].bwrite)(s.s->c, nb, offset);
.
384c
			nb = digestb(s.s, nb, offset);
.
381,382c
		if(s.s->encryptalg)
			nb = encryptb(s.s, nb, offset);
.
360c
		m += s.s->diglen;
.
356,358c
			nb = padblock(bb.b, h);
			bb.b = 0;
.
353c
			bb.b->rp += m;
.
351c
			memmove(nb->wp + h, bb.b->rp, m);
.
342c
					pad = s.s->blocklen - pad;
.
340c
					m = s.s->maxpad;
.
338c
				if(m > s.s->maxpad){
.
333,336c
		if(m > s.s->max){
			m = s.s->max;
		} else if(s.s->blocklen != 1){
			pad = m%s.s->blocklen;
.
327,329c
	while(bb.b){
		m = n = BLEN(bb.b);
		h = s.s->diglen + 2;
.
324c
	qlock(&s.s->out.q);
.
318,321c
		qunlock(&s.s->out.q);
		if(bb.b)
			freeb(bb.b);
		dighangup(s.s);
.
313,314c
	bb.b = b;
	s.s = c->aux;
	if(s.s == 0 || s.s->state != Established)
.
308c
	volatile struct { Dstate *s; } s;
	volatile struct { Block *b; } bb;
.
293,295c
	n = BLEN(b.b);
	memmove(a, b.b->rp, n);
	freeb(b.b);
.
289c
		freeb(b.b);
.
286c
	b.b = sslbread(c, n, offset);
.
279c
	volatile struct { Block *b; } b;
.
270c
	qunlock(&s.s->in.q);
.
268c
		s.s->processed = b->next;
.
266c
		s.s->processed->rp += n;
.
264c
		memmove(b->wp, s.s->processed->rp, n);
.
259c
		s.s->processed = b;
.
251,252c
			checkdigestb(s.s, b);
			b->rp += s.s->diglen;
.
249c
			if(BLEN(b) < s.s->diglen)
.
246,247c
		if(s.s->encryptalg)
			b = decryptb(s.s, b);
.
240,242c
			s.s->unprocessed = allocb(i);
			memmove(s.s->unprocessed->wp, b->rp+len, i);
			s.s->unprocessed->wp += i;
.
234c
		b = s.s->processed = pullupblock(s.s->processed, len);
.
228,229c
			ensure(s.s, &s.s->processed, len+1);
			consume(&s.s->processed, count, 1);
.
224c
			ensure(s.s, &s.s->processed, len);
.
218,221c
		s.s->processed = s.s->unprocessed;
		s.s->unprocessed = 0;
		ensure(s.s, &s.s->processed, 2);
		consume(&s.s->processed, count, 2);
.
214c
	b = s.s->processed;
.
212c
	qlock(&s.s->in.q);
.
208,209c
		qunlock(&s.s->in.q);
		dighangup(s.s);
.
203,204c
	s.s = c->aux;
	if(s.s == 0 || s.s->state != Established)
.
196c
	volatile struct { Dstate *s; } s;
.
184c
			cclose(s->c);
.
171c
	USED(c);
	USED(dp);
.
157c
	USED(c);
	USED(name);
	USED(omode);
	USED(perm);
.
145c
		s = malloc(sizeof(Dstate));
.
115c
sslattach(void *spec)
.
111a
	randq.ep = randq.buf + sizeof(randq.buf);
	randq.rp = randq.wp = randq.buf;
.
105,106d
101d
72c
	Qclone
.
67c
	Maxdmsg=	1<<16
.
38c
	DESECB=		2
.
19,22c
	void	*state;		/* encryption state */
	int	slen;		/* hash data length */
	uchar	*secret;	/* secret */
	ulong	mid;		/* message id */
.
17c
	QLock	q;
.
5,11c
#include <libcrypt.h>
.
3a
#include "u.h"
#include "../port/lib.h"
#include "../port/error.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
.
2c
 *  devssl - secure sockets layer emulation
.
## diffname port/devssl.c 1996/0601
## diff -e /n/fornaxdump/1996/0531/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/0601/sys/src/brazil/port/devssl.c
187c
			close(s->c);
.
## diffname port/devssl.c 1996/1029
## diff -e /n/fornaxdump/1996/0601/sys/src/brazil/port/devssl.c /n/fornaxdump/1996/1029/sys/src/brazil/port/devssl.c
764a


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;
}

.
746a
extern void rbcheck(char*);

.
744c
		print("crypt library: %s: %r\n", exception);
.
742c
		panic("crypt library: %s: %r", exception);
.
730c
	s->state = Sincomplete;
.
717c
sslhangup(Dstate *s)
.
705,710c
	if(p == 0)
		error(Ebadarg);
	fd = strtoul(p, 0, 0);
	if(fd < 0)
		error(Ebadarg);
.
703d
699c
buftochan(char *p)
.
693c
	if(memcmp(digest, inb->rp, s->diglen) != 0)
.
683a
	/* 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;
	}

.
682d
680c
	/* hash secret */
.
677,678d
672a
	Block *b;
.
665c
checkdigestb(Dstate *s, Block *inb)
.
630c
	return inb;
.
628c
		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;
		}
.
608,625c
	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");
.
606a
#endif NOSPOOKS
	int i;
.
603a
	Block *b, **l;
#ifdef NOSPOOKS
.
602c
decryptb(Dstate *s, Block *inb)
.
596a
#endif NOSPOOKS
	case RC4:
		rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
		break;
.
578a
#ifdef NOSPOOKS
.
576a
#endif NOSPOOKS
.
574a
#ifdef NOSPOOKS
.
556,571d
548,554d
533,545c
out:
	qunlock(&s.s->in.ctlq);
	qunlock(&s.s->out.q);
	poperror();
	return n;
.
523,531c
		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);
.
517,521c
		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);
.
507,514c
		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;
.
500,505c
		/* 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;
.
491,498c
	if(strcmp(buf, "fd") == 0){
		s.s->c = buftochan(p);
.
488,489c
	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;
.
485c
		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;
.
482,483c

			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){
.
469,470c
			if(m > s.s->max)
				m = s.s->max;
.
467c
		e = p + n;
		do {
.
418,465d
414,416c
	t = TYPE(c->qid);
	if(t == Qdata){
		if(s.s->state == Sincomplete)
			error(Ebadusefd);
.
407,412c
	s.s = dstate[CONV(c->qid)];
	if(s.s == 0)
		panic("sslwrite");
.
404c
	int m, t;
.
402c
	volatile struct { Dstate *s; } s;
.
398a
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);
}

.
390,391c
		m = BLEN(nb);
		(*devtab[s.s->c->type].bwrite)(s.s->c, nb, s.s->c->offset);
		s.s->c->offset += m;
.
388a
			break;
		}
.
387c
			break;
		case Sdigesting:
.
385c
		switch(s.s->state){
		case Sencrypting:
.
369c
			randfill(nb->wp, pad);
.
326c
		sslhangup(s.s);
.
320a
	}
.
318,319c
	s.s = dstate[CONV(c->qid)];
	if(s.s == 0)
		panic("sslbwrite");
	if(s.s->state == Sincomplete){
		freeb(b);
.
305a
 *  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;
	}
}

/*
.
299a
	freeblist(b.b);
.
296,298c
	n = 0;
	va = a;
	for(nb = b.b; nb; nb = nb->next){
		i = BLEN(nb);
		memmove(va+n, nb->rp, i);
		n += i;
	}
.
292c
		freeblist(b.b);
.
289,290d
284,286c
	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;
.
282a
	Block *nb;
	uchar *va;
	int i;
	char buf[128];
.
265,271c
	/* return at most what was asked for */
	b = qremove(&s.s->processed, n, 0);
.
259,262c
		if(pad)
			s.s->processed = qremove(&s.s->processed, len - pad, 1);
.
256a
		qunlock(&s.s->in.ctlq);
		poperror();
.
248,255c
		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;
.
239,246c
		if(waserror()){
			qunlock(&s.s->in.ctlq);
			nexterror();
.
236,237c
		/* put extra on unprocessed queue */
		s.s->processed = qremove(&s.s->unprocessed, len, 0);
.
233a
			if(pad > len){
				print("pad %d buf len %d\n", pad, len);
				error("bad pad in ssl message");
			}
.
231,232c
			ensure(s.s, &s.s->unprocessed, len+1);
			consume(&s.s->unprocessed, count, 1);
.
227c
			ensure(s.s, &s.s->unprocessed, len);
.
221,224c
		ensure(s.s, &s.s->unprocessed, 2);
		consume(&s.s->unprocessed, count, 2);
.
217,219c
	if(s.s->processed == 0){
.
212c
		sslhangup(s.s);
.
206,207c
	s.s = dstate[CONV(c->qid)];
	if(s.s == 0)
		panic("sslbread");
	if(s.s->state == Sincomplete)
.
202c
	int len, pad;
.
195a
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;
}

.
192a

.
191a
		if(s->in.state)
			free(s->in.state);
		if(s->out.state)
			free(s->out.state);
.
183,185c
	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);
.
173,175c
	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;
.
150c

	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;
.
148a
	case OWRITE:
		perm = 2;
		break;
	case ORDWR:
		perm = 6;
		break;
.
142,147c
	perm = 0;
	omode &= 3;
	switch(omode) {
	case OREAD:
		perm = 4;
.
140c
	Dstate *s, **pp;
	int perm;
.
134c
	devstat(c, db, 0, 0, sslgen);
.
128c
	return devwalk(c, name, 0, 0, sslgen);
.
116c
	Chan *c;

	c = devattach('D', spec);
	c->qid.path = QID(0, Qtopdir)|CHDIR;
	c->qid.vers = 0;
	return c;
.
109,110c
	if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
		panic("sslinit");
.
105a
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;
}

.
98,99c
static Chan*	buftochan(char*);
static void	sslhangup(Dstate*);
static Dstate*	dsclone(Chan *c);
static void	dsnew(Chan *c, Dstate **);
.
93c
static void	setsecret(OneWay*, uchar*, int);
.
89,90d
79,87c
#define TYPE(x) 	((x).path & 0xf)
#define CONV(x) 	(((x).path >> 4)&(Maxdstate-1))
#define QID(c, y) 	(((c)<<4) | (y))
.
74,77d
71,72c
	Qtopdir		= 1,	/* top level directory */
	Qclonus,
	Qconvdir,		/* directory for a conversation */
	Qdata,
	Qctl,
	Qsecretin,
	Qsecretout
.
67c
	Maxdmsg=	1<<16,
	Maxdstate=	64
.
64a
Lock	dslock;
int	dshiwat;
int	maxdstate = 20;
Dstate** dstate;

.
62a

	/* protections */
	char	user[NAMELEN];
	int	perm;
.
45a
	int	ref;		/* serialized by dslock for atomic destroy */

.
38c
	DESECB=		2,
#endif NOSPOOKS
	RC4=		3
.
36a
#ifdef NOSPOOKS
.
28,33c
	Sincomplete=	0,
	Sclear,
	Sencrypting,
	Sdigesting,
.
17a
	QLock	ctlq;
.
12a
#define NOSPOOKS 1
.
## diffname port/devssl.c 1997/0327
## diff -e /n/fornaxdump/1996/1029/sys/src/brazil/port/devssl.c /n/emeliedump/1997/0327/sys/src/brazil/port/devssl.c
1092c
	s->hf(msgid, 4, digest, &ss);
.
1081c
		s->hf(b->rp + h, n, 0, &ss);
.
1073c
	s->hf(w->secret, w->slen, 0, &ss);
.
1052c
	s->hf(msgid, 4, b->rp + offset, &ss);
.
1042,1043c
	s->hf(w->secret, w->slen, 0, &ss);
	s->hf(b->rp + h, n, 0, &ss);
.
932a
Dev ssldevtab = {
	devreset,
	sslinit,
	sslattach,
	devclone,
	sslwalk,
	sslstat,
	sslopen,
	devcreate,
	sslclose,
	sslread,
	sslbread,
	sslwrite,
	sslbwrite,
	devremove,
	sslwstat,
};
.
779c
static long
.
721c
		devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset);
.
630c
static long
.
563c
static long
.
484c
static Block*
.
422,435d
380c
		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
.
352,361d
338c
			cclose(s->c);
.
311c
static void
.
276,293c
static void
.
212c
static Chan*
.
206c
static void
.
194,200c
static int
.
183c
static Chan*
.
176c
static void
.
111,116c
static int
.
## diffname port/devssl.c 1997/0408
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/port/devssl.c /n/emeliedump/1997/0408/sys/src/brazil/port/devssl.c
881a
	'D',
	"ssl",

.
## diffname port/devssl.c 1997/0618
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/port/devssl.c /n/emeliedump/1997/0618/sys/src/brazil/port/devssl.c
1200d
1131c
		return;
.
1119,1124c
	return smalloc(size);
.
1060c
	(*s->hf)(msgid, 4, digest, &ss);
.
1055c
	n = w->mid;
.
1049c
		(*s->hf)(b->rp + h, n, 0, &ss);
.
1041c
	(*s->hf)(w->secret, w->slen, 0, &ss);
.
1020c
	(*s->hf)(msgid, 4, b->rp + offset, &ss);
.
1015c
	n = w->mid;
.
1010,1011c
	(*s->hf)(w->secret, w->slen, 0, &ss);
	(*s->hf)(b->rp + h, n, 0, &ss);
.
985d
964d
946d
942d
930d
911d
908d
905d
839,861c

			if(np == 0)
				break;
			p = np;
		}

		if(s.s->hf == 0 && s.s->encryptalg == Noencryption)
.
827,837c
		if(s.s->in.secret == 0 || s.s->out.secret == 0)
			error("algorithm but no secret");

		s.s->hf = 0;
		s.s->encryptalg = Noencryption;
		s.s->blocklen = 1;

		for(;;){
			np = strchr(p, ' ');
			if(np)
				*np++ = 0;

			if(parsehashalg(p, s.s) < 0)
			if(parseencryptalg(p, s.s) < 0)
.
809a
		s.s->in.mid = 0;
		s.s->out.mid = 0;
.
733c
	char *p, *np, *e, buf[32];
.
726a
struct Hashalg
{
	char	*name;
	int	diglen;
	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
} hashtab[] =
{
	{ "md4", MD4dlen, md4, },
	{ "md5", MD5dlen, md5, },
	{ "sha", SHAdlen, sha, },
	{ 0 }
};

static int
parsehashalg(char *p, Dstate *s)
{
	struct Hashalg *ha;

	for(ha = hashtab; ha->name; ha++){
		if(strcmp(p, ha->name) == 0){
			s->hf = ha->hf;
			s->diglen = ha->diglen;
			s->state &= ~Sclear;
			s->state |= Sdigesting;
			return 0;
		}
	}
	return -1;
}

struct Encalg
{
	char	*name;
	int	blocklen;
	int	alg;
	void	(*keyinit)(OneWay*);
} encrypttab[] =
{
	{ "descbc", 8, DESCBC, initDESkey, },
	{ "desebc", 8, DESECB, initDESkey, },
	{ "rc4", 1, RC4, initRC4key, },
	{ 0 }
};

static int
parseencryptalg(char *p, Dstate *s)
{
	struct Encalg *ea;

	for(ea = encrypttab; ea->name; ea++){
		if(strcmp(p, ea->name) == 0){
			s->encryptalg = ea->alg;
			s->blocklen = ea->blocklen;
			(*ea->keyinit)(&s->in);
			(*ea->keyinit)(&s->out);
			s->state &= ~Sclear;
			s->state |= Sencrypting;
			return 0;
		}
	}
	return -1;
}

.
723c
	w->state = smalloc(sizeof(RC4state));
.
721d
718d
708d
700c
	w->state = smalloc(sizeof(DESstate));
.
691d
687,688d
684c
	w->secret = smalloc(n);
.
667a
		s.s->out.mid++;

.
665a
		case Sdigenc:
			nb = digestb(s.s, nb, offset);
			nb = encryptb(s.s, nb, offset);
			break;
.
560,572c
	while(len-- > 0)
		*buf++ = nrand(256);
.
493a
		s.s->in.mid++;
.
492a
		case Sdigenc:
			s.s->processed = decryptb(s.s, s.s->processed);
			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;
.
174c
	if((dstate = smalloc(sizeof(Dstate*) * maxdstate)) == 0)
.
40d
37d
31,33c
	Sclear=		1,
	Sencrypting=	2,
	Sdigesting=	4,
	Sdigenc=	Sencrypting|Sdigesting,
.
13,14d
11c
#include	<libcrypt.h>
.
4,9c
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
.
## diffname port/devssl.c 1997/0619
## diff -e /n/emeliedump/1997/0618/sys/src/brazil/port/devssl.c /n/emeliedump/1997/0619/sys/src/brazil/port/devssl.c
715,717d
## diffname port/devssl.c 1998/0319
## diff -e /n/emeliedump/1997/0619/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0319/sys/src/brazil/port/devssl.c
788a
	ulong offset = off;
.
783c
sslwrite(Chan *c, void *a, long n, vlong off)
.
524a
	ulong offset = off;
.
518c
sslread(Chan *c, void *a, long n, vlong off)
.
## diffname port/devssl.c 1998/0327
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0327/sys/src/brazil/port/devssl.c
436,437d
430c
sslbread(Chan *c, long n, ulong)
.
## diffname port/devssl.c 1998/0417
## diff -e /n/emeliedump/1998/0327/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0417/sys/src/brazil/port/devssl.c
922a
}

static void
sslinit(void)
{
	struct Encalg *e;
	struct Hashalg *h;
	int n;
	char *cp;

	if((dstate = smalloc(sizeof(Dstate*) * maxdstate)) == 0)
		panic("sslinit");

	n = 1;
	for(e = encrypttab; e->name != nil; e++)
		n += strlen(e->name) + 1;
	cp = encalgs = smalloc(n);
	for(e = encrypttab;;){
		strcpy(cp, e->name);
		cp += strlen(e->name);
		e++;
		if(e->name == nil)
			break;
		*cp++ = ' ';
	}
	*cp = 0;

	n = 1;
	for(h = hashtab; h->name != nil; h++)
		n += strlen(h->name) + 1;
	cp = hashalgs = smalloc(n);
	for(h = hashtab;;){
		strcpy(cp, h->name);
		cp += strlen(h->name);
		h++;
		if(h->name == nil)
			break;
		*cp++ = ' ';
	}
	*cp = 0;
.
536a
	case Qencalgs:
		return readstr(offset, a, n, encalgs);
		break;
	case Qhashalgs:
		return readstr(offset, a, n, hashalgs);
		break;
.
254a
	case Qencalgs:
	case Qhashalgs:
		if(omode != OREAD)
			error(Eperm);
		break;
.
221a
	case Qprotodir:
.
168,174d
160a
		case 4:
			q.path = QID(CONV(c->qid), Qencalgs);
			p = "encalgs";
			break;
		case 5:
			q.path = QID(CONV(c->qid), Qhashalgs);
			p = "hashalgs";
			break;
.
119a
		if(s > 0)
			return -1;
		q.path = QID(0, Qprotodir)|CHDIR;
		devdir(c, q, "ssl", 0, eve, 0555, dp);
		return 1;
	case Qprotodir:
.
89c
	Qsecretout,
	Qencalgs,
	Qhashalgs,
.
83a
	Qprotodir,
.
74a
char	*encalgs;
char	*hashalgs;
.
## diffname port/devssl.c 1998/0501
## diff -e /n/emeliedump/1998/0417/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0501/sys/src/brazil/port/devssl.c
1075c
			for(p = b->rp; p < ep;){
.
1069c
			for(p = b->rp; p < ep; p += 8)
.
633c
			pad = (m + s.s->diglen)%s.s->blocklen;
.
512a
			len -= s.s->diglen;
.
## diffname port/devssl.c 1998/0512
## diff -e /n/emeliedump/1998/0501/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0512/sys/src/brazil/port/devssl.c
839c

.
830c

.
## diffname port/devssl.c 1998/0806
## diff -e /n/emeliedump/1998/0512/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0806/sys/src/brazil/port/devssl.c
790c
	Encalg *ea;
.
785a
#else
Encalg encrypttab[] =
{
	{ "descbc", 8, DESCBC, initDESkey_40, },
	{ "desebc", 8, DESECB, initDESkey_40, },
	{ "descbc_40", 8, DESCBC, initDESkey_40, },
	{ "desebc_40", 8, DESECB, initDESkey_40, },
	{ "rc4", 1, RC4, initRC4key_40, },
	{ "rc4_40", 1, RC4, initRC4key_40, },
	{ 0 }
};
#endif NOSPOOKS
.
783a
	{ "rc4_40", 1, RC4, initRC4key_40, },
.
782a
	{ "descbc_40", 8, DESCBC, initDESkey_40, },
	{ "desebc_40", 8, DESECB, initDESkey_40, },
.
779c
};

#ifdef NOSPOOKS
Encalg encrypttab[] =
.
772a
typedef struct Encalg Encalg;
.
759c
	Hashalg *ha;
.
748c
};

Hashalg hashtab[] =
.
742a
/*
 *  40 bit RC4 is the same as n-bit RC4.  However,
 *  we ignore all but the first 40 bits of the key.
 */
static void
initRC4key_40(OneWay *w)
{
	if(w->state){
		free(w->state);
		w->state = 0;
	}

	if(w->slen > 5)
		w->slen = 5;

	w->state = malloc(sizeof(RC4state));
	setupRC4state(w->state, w->secret, w->slen);
}

typedef struct Hashalg Hashalg;
.
731a
initDESkey_40(OneWay *w)
{
	if(w->state){
		free(w->state);
		w->state = 0;
	}

	if(w->slen >= 16) {
		w->secret[8] &= 0x0f; 
		w->secret[10] &= 0x0f; 
		w->secret[12] &= 0x0f; 
		w->secret[14] &= 0x0f;
	}
	if(w->slen >= 8) {
		w->secret[0] &= 0x0f; 
		w->secret[2] &= 0x0f; 
		w->secret[4] &= 0x0f; 
		w->secret[6] &= 0x0f;
	}

	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");
}

static void
.
730a
/*
 *  40 bit DES is the same as 56 bit DES.  However,
 *  16 bits of the key are masked to zero.
 */
.
12a
#define NOSPOOKS 1

.
## diffname port/devssl.c 1998/0807
## diff -e /n/emeliedump/1998/0806/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0807/sys/src/brazil/port/devssl.c
857c
	{ "desecb_40", 8, DESECB, initDESkey_40, },
.
855c
	{ "desecb", 8, DESECB, initDESkey_40, },
.
846c
	{ "desecb_40", 8, DESECB, initDESkey_40, },
.
844c
	{ "desecb", 8, DESECB, initDESkey, },
.
752,755c
		w->secret[0] &= 0x0f;
		w->secret[2] &= 0x0f;
		w->secret[4] &= 0x0f;
		w->secret[6] &= 0x0f;
.
745,750d
## diffname port/devssl.c 1998/0825
## diff -e /n/emeliedump/1998/0807/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0825/sys/src/brazil/port/devssl.c
553c
		sprint(buf, "%lud", CONV(c->qid));
.
## diffname port/devssl.c 1998/0910
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/port/devssl.c /n/emeliedump/1998/0910/sys/src/brazil/port/devssl.c
848,852c
	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
.
837,841c
	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
	{ "des_56_cbc", 8, DESCBC, initDESkey, },
	{ "des_56_ecb", 8, DESECB, initDESkey, },
	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
	{ "rc4_256", 1, RC4, initRC4key, },
	{ "rc4_128", 1, RC4, initRC4key_128, },
.
791a
/*
 *  128 bit RC4 is the same as n-bit RC4.  However,
 *  we ignore all but the first 128 bits of the key.
 */
static void
initRC4key_128(OneWay *w)
{
	if(w->state){
		free(w->state);
		w->state = 0;
	}

	if(w->slen > 16)
		w->slen = 16;

	w->state = malloc(sizeof(RC4state));
	setupRC4state(w->state, w->secret, w->slen);
}


.
## diffname port/devssl.c 1999/0302
## diff -e /n/emeliedump/1998/0910/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0302/sys/src/brazil/port/devssl.c
421c
			return first;
.
## diffname port/devssl.c 1999/0320
## diff -e /n/emeliedump/1999/0302/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0320/sys/src/brazil/port/devssl.c
190c
sslattach(char *spec)
.
## diffname port/devssl.c 1999/0414
## diff -e /n/emeliedump/1999/0320/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0414/sys/src/brazil/port/devssl.c
1256c
	if(memcmp(digest, bin->rp, s->diglen) != 0)
.
1239c
	for(b = bin; b; b = b->next){
.
1220c
checkdigestb(Dstate *s, Block *bin)
.
1185c
	return bin;
.
1145,1146c
	l = &bin;
	for(b = bin; b; b = b->next){
.
1137c
decryptb(Dstate *s, Block *bin)
.
## diffname port/devssl.c 1999/0415
## diff -e /n/emeliedump/1999/0414/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0415/sys/src/brazil/port/devssl.c
756c
		setupDESstate(w->state, key, 0);
.
754c
		setupDESstate(w->state, key, w->secret+8);
.
745,749c
	if(w->slen >= 8){
		memmove(key, w->secret, 8);
		key[0] &= 0x0f;
		key[2] &= 0x0f;
		key[4] &= 0x0f;
		key[6] &= 0x0f;
.
739a
	uchar key[8];

.
## diffname port/devssl.c 1999/0527
## diff -e /n/emeliedump/1999/0415/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0527/sys/src/brazil/port/devssl.c
996,997d
994a
		s.s->state = Sclear;
		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
.
## diffname port/devssl.c 1999/0804
## diff -e /n/emeliedump/1999/0527/sys/src/brazil/port/devssl.c /n/emeliedump/1999/0804/sys/src/brazil/port/devssl.c
1035a
	} else if(strcmp(buf, "secretin") == 0 && p != 0) {
		m = (strlen(p)*3)/2;
		x = smalloc(m);
		n = dec64(x, m, p, strlen(p));
		setsecret(&s.s->in, x, n);
		free(x);
	} else if(strcmp(buf, "secretout") == 0 && p != 0) {
		m = (strlen(p)*3)/2 + 1;
		x = smalloc(m);
		n = dec64(x, m, p, strlen(p));
		setsecret(&s.s->out, x, n);
		free(x);
.
1027c
			error("bad algorithm");
.
1019c
				error("bad algorithm");
.
968c
		error("arg too long");
.
962d
958d
908c
	char *p, *np, *e, buf[128];
	uchar *x;
.
## diffname port/devssl.c 1999/1230
## diff -e /n/emeliedump/1999/0804/sys/src/brazil/port/devssl.c /n/emeliedump/1999/1230/sys/src/9/port/devssl.c
149a
		if(s == DEVDOTDOT){
			q.path = QID(0, Qprotodir)|CHDIR;
			devdir(c, q, "ssl", 0, eve, 0555, dp);
			return 1;
		}
.
141c
			devdir(c, q, name, 0, nm, 0555, dp);
.
132a
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, ".", 0, eve, 0555, dp);
			return 1;
		}
.
126a
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, "#D", 0, eve, 0555, dp);
			return 1;
		}
.
## diffname port/devssl.c 2000/0112
## diff -e /n/emeliedump/1999/1230/sys/src/9/port/devssl.c /n/emeliedump/2000/0112/sys/src/9/port/devssl.c
1323,1352d
842c
	{ "sha1", SHA1dlen, sha1, },
.
11c
#include	<mp.h>
#include	<libsec.h>
.
## diffname port/devssl.c 2000/0113
## diff -e /n/emeliedump/2000/0112/sys/src/9/port/devssl.c /n/emeliedump/2000/0113/sys/src/9/port/devssl.c
11d
## diffname port/devssl.c 2000/0204
## diff -e /n/emeliedump/2000/0113/sys/src/9/port/devssl.c /n/emeliedump/2000/0204/sys/src/9/port/devssl.c
842a
	{ "sha", SHA1dlen, sha1, },
.
## diffname port/devssl.c 2000/0325
## diff -e /n/emeliedump/2000/0204/sys/src/9/port/devssl.c /n/emeliedump/2000/0325/sys/src/9/port/devssl.c
198a
		return 1;
	case Qclonus:
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
		return 1;
	default:
		ds = dstate[CONV(c->qid)];
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, ds->user, 0660, dp);
.
162c
			devdir(c, q, "ssl", 0, eve, CHDIR|0555, dp);
.
151c
			devdir(c, q, name, 0, nm, CHDIR|0555, dp);
.
140c
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp);
.
135c
		devdir(c, q, "ssl", 0, eve, CHDIR|0555, dp);
.
129c
			devdir(c, q, "#D", 0, eve, CHDIR|0555, dp);
.
114a
char *sslnames[] = {
[Qclonus]	"clone",
[Qdata]		"data",
[Qctl]		"ctl",
[Qsecretin]	"secretin",
[Qsecretout]	"secretout",
[Qencalgs]	"encalgs",
[Qhashalgs]	"hashalgs",
};

.
100,101c
#define CONV(x) 	(((x).path >> 5)&(Maxdstate-1))
#define QID(c, y) 	(((c)<<5) | (y))
.
## diffname port/devssl.c 2000/0913
## diff -e /n/emeliedump/2000/0325/sys/src/9/port/devssl.c /n/emeliedump/2000/0913/sys/src/9/port/devssl.c
653c
		if(nb != nil)
			freeb(nb);
.
651c
		if(bb.b != nil)
.
648a
	nb = nil;
.
629c
 *  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.
.
556c
			s.s->processed = qremove(&b, len - pad, 1);
		else
			s.s->processed = b;
		b = nil;
		s.s->in.mid++;
		qunlock(&s.s->in.ctlq);
		poperror();
		USED(nconsumed);
.
550,552d
545,546c
			checkdigestb(s.s, b);
			b->rp += s.s->diglen;
.
541,543c
			b = decryptb(s.s, b);
			b = pullupblock(b, s.s->diglen);
			if(b == nil)
.
537,538c
			checkdigestb(s.s, b);
			b->rp += s.s->diglen;
.
534,535c
			b = pullupblock(b, s.s->diglen);
			if(b == nil)
.
531c
			b = decryptb(s.s, b);
.
525a
			if(b != nil)
				freeb(b);
.
523a
		/* grab the next message and decode/decrypt it */
		b = qremove(&s.s->unprocessed, len, 0);

.
521,522c
		/*  if an Eintr happens after this, we screwed.  Make
		 *  sure nothing we call can sleep.  Luckily, allocb
		 *  won't sleep, it'll just error out.
		 */
.
519a
		USED(nconsumed);
		nconsumed = 0;
.
513,514c
			consume(&s.s->unprocessed, &consumed[2], 1);
			pad = consumed[2];
.
511c
			len = ((consumed[0] & 0x3f)<<8) | consumed[1];
.
505,507c
		consume(&s.s->unprocessed, consumed, 2);
		nconsumed = 2;
		if(consumed[0] & 0x80){
			len = ((consumed[0] & 0x7f)<<8) | consumed[1];
.
497d
495a
		if(strcmp(up->error, Eintr) != 0 && nconsumed)
			regurgitate(s.s, consumed, nconsumed);
.
494a
	nconsumed = 0;
.
486c
	uchar consumed[3];
	int nconsumed;
.
480a
/*
 *  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.
 */
.
433a
 *  give back n bytes
 */
static void
regurgitate(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(p, b->wp, n);
		b->wp += n;
		b->next = s->unprocessed;
		s->unprocessed = b;
	} else {
		b->rp -= n;
		memmove(p, b->rp, n);
	}
}

/*
.
75c
int	maxdstate = 128;
.
## diffname port/devssl.c 2000/0914
## diff -e /n/emeliedump/2000/0913/sys/src/9/port/devssl.c /n/emeliedump/2000/0914/sys/src/9/port/devssl.c
704,705d
452c
		memmove(b->rp, p, n);
.
446c
		memmove(b->wp, p, n);
.
## diffname port/devssl.c 2000/0915
## diff -e /n/emeliedump/2000/0914/sys/src/9/port/devssl.c /n/emeliedump/2000/0915/sys/src/9/port/devssl.c
699d
## diffname port/devssl.c 2000/0919
## diff -e /n/emeliedump/2000/0915/sys/src/9/port/devssl.c /n/emeliedump/2000/0919/sys/src/9/port/devssl.c
557c
		/*  if an Eintr happens after this, we're screwed.  Make
.
528c
		if(strcmp(up->error, Eintr) != 0)
.
## diffname port/devssl.c 2001/0331
## diff -e /n/emeliedump/2000/0919/sys/src/9/port/devssl.c /n/emeliedump/2001/0331/sys/src/9/port/devssl.c
778d
776d
528c
		if(strcmp(up->error, Eintr) == 0)
.
## diffname port/devssl.c 2001/0504
## diff -e /n/emeliedump/2001/0331/sys/src/9/port/devssl.c /n/emeliedump/2001/0504/sys/src/9/port/devssl.c
529a
			poperror();
		}
.
528c
		if(strcmp(up->error, Eintr) == 0 && !waserror()){
.
505,509c
 *  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.
.
## diffname port/devssl.c 2001/0515
## diff -e /n/emeliedump/2001/0504/sys/src/9/port/devssl.c /n/emeliedump/2001/0515/sys/src/9/port/devssl.c
644d
641d
215c
		if(ds != nil)
			nm = ds->user;
		else
			nm = eve;
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
.
## diffname port/devssl.c 2001/0527
## diff -e /n/emeliedump/2001/0515/sys/src/9/port/devssl.c /n/emeliedump/2001/0527/sys/src/9/port/devssl.c
1449c
	kstrdup(&s->user, up->user);
.
1426c

		names = smalloc(sizeof(char*) * newmax);
		if(names == 0)
			error(Enomem);
		memmove(names, dsname, sizeof(char*) * maxdstate);
		dsname = names;

.
1419a

.
1396a
	char **names;
.
1188d
1151a
	if((dsname = smalloc(sizeof(char*) * maxdstate)) == 0)
		panic("sslinit");

.
780a
		s.s->c->offset += m;
.
779a
		m = BLEN(nb);
.
646a
		break;
.
644a
		break;
.
638c
		ft = CONV(c->qid);
		sprint(buf, "%d", ft);
.
634c
	ft = TYPE(c->qid);
	switch(ft) {
.
631c
	if(c->qid.type & QTDIR)
.
629a
	int ft;
.
534,535d
532c
		if(strcmp(up->error, Eintr) != 0)
.
509,513c
 *  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.
.
360a
		if(s->user != nil)
			free(s->user);
.
341c
	ft = TYPE(c->qid);
	switch(ft) {
.
339a
	int ft;
.
332,333c
	dir = smalloc(sizeof(Dir)+n);
	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
	if(m > 0){
		kstrdup(&s->user, dir->uid);
		s->perm = dir->mode;
	}
	free(dir);
	return m;
.
324,325d
322a
	int m;
.
321c
	Dir *dir;
.
318,319c
static int
sslwstat(Chan *c, uchar *db, int n)
.
268c
	ft = TYPE(c->qid);
	switch(ft) {
.
252a
	int ft;
.
245c
	return devstat(c, db, n, nil, 0, sslgen);
.
242,243c
static int
sslstat(Chan *c, uchar *db, int n)
.
239c
	return devwalk(c, nc, name, nname, nil, 0, sslgen);
.
236,237c
static Walkqid*
sslwalk(Chan *c, Chan *nc, char **name, int nname)
.
232a
	c->qid.type = QTDIR;
.
231c
	c->qid.path = QID(0, Qtopdir);
.
215,219c
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, ds->user, 0660, dp);
.
171,172c
			q.path = QID(0, Qprotodir);
			q.type = QTDIR;
			devdir(c, q, "ssl", 0, eve, 0555, dp);
.
161c
			if(dsname[s] == nil){
				sprint(name, "%d", s);
				kstrdup(&dsname[s], name);
			}
			devdir(c, q, dsname[s], 0, nm, 0555, dp);
.
154,155c
			q.path = QID(s, Qconvdir);
			q.type = QTDIR;
.
149,150c
			q.path = QID(0, Qtopdir);
			q.type = QTDIR;
			devdir(c, q, ".", 0, eve, 0555, dp);
.
144,145c
		q.path = QID(0, Qprotodir);
		q.type = QTDIR;
		devdir(c, q, "ssl", 0, eve, 0555, dp);
.
138,139c
			q.path = QID(0, Qtopdir);
			q.type = QTDIR;
			devdir(c, q, "#D", 0, eve, 0555, dp);
.
135c

	ft = TYPE(c->qid);
	switch(ft) {
.
133a

	q.type = QTFILE;
.
130a
	int ft;
.
126c
sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
.
76c
char	**dsname;
Dstate	**dstate;
.
69c
	char	*user;
.
## diffname port/devssl.c 2001/0602
## diff -e /n/emeliedump/2001/0527/sys/src/9/port/devssl.c /n/emeliedump/2001/0602/sys/src/9/port/devssl.c
633c
	b = qtake(&s.s->processed, n, 0);
.
622c
			s.s->processed = qtake(&b, len - pad, 1);
.
589c
		b = qtake(&s.s->unprocessed, len, 0);
.
524c
			panic("qtake");
.
519c
				panic("qtake");
.
487c
qtake(Block **l, int n, int discard)
.
## diffname port/devssl.c 2001/0823
## diff -e /n/emeliedump/2001/0602/sys/src/9/port/devssl.c /n/emeliedump/2001/0823/sys/src/9/port/devssl.c
1469c
	return ret;
.
1441,1466d
1434,1437c
	ret = nil;
	for(i=0; i<Maxdstate; i++){
		if(dstate[i] == nil){
			dsnew(ch, &dstate[i]);
			ret = dstate[i];
.
1425,1427c
	int i;
	Dstate *ret;
.
1399a
	if(devtab[c->type] == &ssldevtab){
		cclose(c);
		error("cannot ssl encrypt devssl files");
	}
.
1176,1181d
86a
Lock	dslock;
int	dshiwat;
char	*dsname[Maxdstate];
Dstate	*dstate[Maxdstate];
char	*encalgs;
char	*hashalgs;

.
84c
	Maxdstate=	128,	/* must be a power of 2 */
.
73,80d
## diffname port/devssl.c 2001/0825
## diff -e /n/emeliedump/2001/0823/sys/src/9/port/devssl.c /n/emeliedump/2001/0825/sys/src/9/port/devssl.c
628c
		poperror();
.
612c
				error("ssl message too short (dig+enc)");
.
604c
				error("ssl message too short (digesting)");
.
598a
			if(b == nil)
				error("ssl message too short (encrypting)");
.
589a
		if(blocklen(b) != len+pad)
			print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);

.
588c
		b = qtake(&s.s->unprocessed, len+pad, 0);
.
586a
		if(waserror()){
			print("devssl: unhandled allocation failure\n");
			nexterror();
		}

		/* skip header */
		consume(&s.s->unprocessed, consumed, toconsume);

.
582,584c
		/*
		 * Now we have a full SSL packet in the unprocessed list.
		 * Start processing.  We can't get Eintr's here.
		 * The only cause for errors from here until the end of the
		 * loop is allocation failures in the block manipulation.
		 * We'll worry about that when we come across it.
.
579,580c
		ensure(s.s, &s.s->unprocessed, toconsume+len+pad);
.
577a
			toconsume = 3;
.
570,573c
			len = ((p[0] & 0x3f)<<8) | p[1];
			pad = p[2];
.
568a
			toconsume = 2;
.
561,566c
		/*
		 * Read in the whole message.  Until we've got it all,
		 * it stays on s.s->unprocessed, so that if we get Eintr,
		 * we'll pick up where we left off.
		 */
		ensure(s.s, &s.s->unprocessed, 3);
		s.s->unprocessed = pullupblock(s.s->unprocessed, 2);
		p = s.s->unprocessed->rp;
		if(p[0] & 0x80){
			len = ((p[0] & 0x7f)<<8) | p[1];
.
558d
553,554d
551c
	qlock(&s.s->in.q);
.
541,542c
	uchar consumed[3], *p;
	int toconsume;
.
479a
 */
.
460d
418c
			nexterror();
.
## diffname port/devssl.c 2001/1106
## diff -e /n/emeliedump/2001/0825/sys/src/9/port/devssl.c /n/emeliedump/2001/1106/sys/src/9/port/devssl.c
348c

.
346a
	if(dir->mode != ~0UL)
.
345c
	if(m == 0){
		free(dir);
		error(Eshortstat);
	}

	if(!emptystr(dir->uid))
.
## diffname port/devssl.c 2002/0109
## diff -e /n/emeliedump/2001/1106/sys/src/9/port/devssl.c /n/emeliedump/2002/0109/sys/src/9/port/devssl.c
1231a
	devshutdown,
.
## diffname port/devssl.c 2002/0306
## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devssl.c /n/emeliedump/2002/0306/sys/src/9/port/devssl.c
1176,1177c
		t = dec64(x, m, p, strlen(p));
		setsecret(&s.s->out, x, t);
.
1170,1171c
		t = dec64(x, m, p, strlen(p));
		setsecret(&s.s->in, x, t);
.
607c
		if(blocklen(b) != len)
.
605c
		b = qtake(&s.s->unprocessed, len, 0);
.
586c
		ensure(s.s, &s.s->unprocessed, toconsume+len);
.
577a
			s.s->unprocessed = pullupblock(s.s->unprocessed, 3);
.
2c
 *  devssl - secure sockets layer
.
## diffname port/devssl.c 2002/0307
## diff -e /n/emeliedump/2002/0306/sys/src/9/port/devssl.c /n/emeliedump/2002/0307/sys/src/9/port/devssl.c
1184,1185c
	qunlock(&s->in.ctlq);
	qunlock(&s->out.q);
.
1178c
		setsecret(&s->out, x, t);
.
1172c
		setsecret(&s->in, x, t);
.
1167c
			s->maxpad = s->max = (1<<15) - s->diglen - 1;
.
1161,1165c
		if(s->blocklen != 1){
			s->max = (1<<15) - s->diglen - 1;
			s->max -= s->max % s->blocklen;
			s->maxpad = (1<<14) - s->diglen - 1;
			s->maxpad -= s->maxpad % s->blocklen;
.
1158c
		if(s->hf == 0 && s->encryptalg == Noencryption)
.
1149,1150c
			if(parsehashalg(p, s) < 0)
			if(parseencryptalg(p, s) < 0)
.
1140,1142c
		s->hf = 0;
		s->encryptalg = Noencryption;
		s->blocklen = 1;
.
1133,1137c
		if(s->in.secret && s->out.secret == 0)
			setsecret(&s->out, s->in.secret, s->in.slen);
		if(s->out.secret && s->in.secret == 0)
			setsecret(&s->in, s->out.secret, s->out.slen);
		if(s->in.secret == 0 || s->out.secret == 0)
.
1127,1128c
		s->state = Sclear;
		s->maxpad = s->max = (1<<15) - s->diglen - 1;
.
1124c
		if(s->c == 0)
.
1121,1122c
		s->blocklen = 1;
		s->diglen = 0;
.
1114,1119c
		s->state = Sclear;
		s->blocklen = 1;
		s->diglen = 0;
		s->maxpad = s->max = (1<<15) - s->diglen - 1;
		s->in.mid = 0;
		s->out.mid = 0;
.
1111c
		s->c = buftochan(p);
.
1093c
		setsecret(&s->out, a, n);
.
1090c
		setsecret(&s->in, a, n);
.
1083,1084c
	qlock(&s->in.ctlq);
	qlock(&s->out.q);
.
1079,1080c
		qunlock(&s->in.ctlq);
		qunlock(&s->out.q);
.
1073a

		poperror();
		qunlock(&s->out.q);
.
1070c
			sslput(s, b);
.
1068c
			b->wp += m;
.
1066c
			memmove(b->wp, p, m);
.
1063c
				freeb(b);
.
1061c
			b = allocb(m);
.
1058,1059c
			if(m > s->max)
				m = s->max;
.
1053a
		/* lock should a write gets split over multiple records */
		if(waserror()){
			qunlock(&s->out.q);
			nexterror();
		}
		qlock(&s->out.q);

.
1051c
		if(s->state == Sincomplete)
.
1045,1046c
	s = dstate[CONV(c->qid)];
	if(s == 0)
.
1043d
1038,1039c
	Dstate * volatile s;
	Block * volatile b;
.
1036c
sslwrite(Chan *c, void *a, long n, vlong)
.
833a
	poperror();
.
831,832d
828,829c
		devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
		s->c->offset += m;
.
825c
		s->out.mid++;
.
820,821c
			nb = digestb(s, nb, offset);
			nb = encryptb(s, nb, offset);
.
817c
			nb = digestb(s, nb, offset);
.
814c
			nb = encryptb(s, nb, offset);
.
812c
		switch(s->state){
.
791c
		m += s->diglen;
.
788,789c
			nb = padblock(b, h);
			b = 0;
.
785c
			b->rp += m;
.
783c
			memmove(nb->wp + h, b->rp, m);
.
774c
					pad = s->blocklen - pad;
.
772c
					m = s->maxpad;
.
770c
				if(m > s->maxpad){
.
765,768c
		if(m > s->max){
			m = s->max;
		} else if(s->blocklen != 1){
			pad = (m + s->diglen)%s->blocklen;
.
759,761c
	while(b != nil){
		m = n = BLEN(b);
		h = s->diglen + 2;
.
756d
751,753c
		if(b != nil)
			free(b);
.
741,749d
739a
	int offset;
.
735,736d
733c
sslput(Dstate *s, Block * volatile b)
.
725a
static long
sslbwrite(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;
}

.
709c
	freeblist(b);
.
703c
	for(nb = b; nb; nb = nb->next){
.
697c
		freeblist(b);
.
686c
		b = sslbread(c, n, offset);
.
666c
	Block * volatile b;
.
657c
	qunlock(&s->in.q);
.
655c
	b = qtake(&s->processed, n, 0);
.
648,649c
		s->in.mid++;
		qunlock(&s->in.ctlq);
.
646c
			s->processed = b;
.
644c
			s->processed = qtake(&b, len - pad, 1);
.
636,638c
			checkdigestb(s, b);
			b->rp += s->diglen;
			len -= s->diglen;
.
632,633c
			b = decryptb(s, b);
			b = pullupblock(b, s->diglen);
.
628,629c
			checkdigestb(s, b);
			b->rp += s->diglen;
.
625c
			b = pullupblock(b, s->diglen);
.
622c
			b = decryptb(s, b);
.
617,618c
		qlock(&s->in.ctlq);
		switch(s->state){
.
612c
			qunlock(&s->in.ctlq);
.
606c
		b = qtake(&s->unprocessed, len, 0);
.
603c
		consume(&s->unprocessed, consumed, toconsume);
.
587c
		ensure(s, &s->unprocessed, toconsume+len);
.
578c
			s->unprocessed = pullupblock(s->unprocessed, 3);
.
574c
			ensure(s, &s->unprocessed, len);
.
569,571c
		ensure(s, &s->unprocessed, 3);
		s->unprocessed = pullupblock(s->unprocessed, 2);
		p = s->unprocessed->rp;
.
566c
		 * it stays on s->unprocessed, so that if we get Eintr,
.
563c
	if(s->processed == 0){
.
559c
		qunlock(&s->in.q);
.
557c
	qlock(&s->in.q);
.
554c
	if(s->state == Sincomplete)
.
551,552c
	s = dstate[CONV(c->qid)];
	if(s == 0)
.
545c
	Dstate * volatile s;
.
113a
static long	sslput(Dstate *s, Block * volatile b);
.
## diffname port/devssl.c 2002/0522
## diff -e /n/emeliedump/2002/0307/sys/src/9/port/devssl.c /n/emeliedump/2002/0522/sys/src/9/port/devssl.c
229c
		if(ds != 0)
			nm = ds->user;
		else
			nm = eve;
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
.
## diffname port/devssl.c 2003/0211
## diff -e /n/emeliedump/2002/0522/sys/src/9/port/devssl.c /n/emeliedump/2003/0211/sys/src/9/port/devssl.c
655d
594,606d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.