137da2899SCharles.Forsyth /*
237da2899SCharles.Forsyth * devssl - secure sockets layer
337da2899SCharles.Forsyth */
437da2899SCharles.Forsyth #include "dat.h"
537da2899SCharles.Forsyth #include "fns.h"
637da2899SCharles.Forsyth #include "error.h"
737da2899SCharles.Forsyth
837da2899SCharles.Forsyth #include "mp.h"
937da2899SCharles.Forsyth #include "libsec.h"
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsyth typedef struct OneWay OneWay;
1237da2899SCharles.Forsyth struct OneWay
1337da2899SCharles.Forsyth {
1437da2899SCharles.Forsyth QLock q;
1537da2899SCharles.Forsyth QLock ctlq;
1637da2899SCharles.Forsyth
1737da2899SCharles.Forsyth void *state; /* encryption state */
1837da2899SCharles.Forsyth int slen; /* secret data length */
1937da2899SCharles.Forsyth uchar *secret; /* secret */
2037da2899SCharles.Forsyth ulong mid; /* message id */
2137da2899SCharles.Forsyth };
2237da2899SCharles.Forsyth
2337da2899SCharles.Forsyth enum
2437da2899SCharles.Forsyth {
2537da2899SCharles.Forsyth /* connection states */
2637da2899SCharles.Forsyth Sincomplete= 0,
2737da2899SCharles.Forsyth Sclear= 1,
2837da2899SCharles.Forsyth Sencrypting= 2,
2937da2899SCharles.Forsyth Sdigesting= 4,
3037da2899SCharles.Forsyth Sdigenc= Sencrypting|Sdigesting,
3137da2899SCharles.Forsyth
3237da2899SCharles.Forsyth /* encryption algorithms */
3337da2899SCharles.Forsyth Noencryption= 0,
3437da2899SCharles.Forsyth DESCBC= 1,
3537da2899SCharles.Forsyth DESECB= 2,
3637da2899SCharles.Forsyth RC4= 3,
3737da2899SCharles.Forsyth IDEACBC= 4,
3837da2899SCharles.Forsyth IDEAECB= 5
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsyth typedef struct Dstate Dstate;
4237da2899SCharles.Forsyth struct Dstate
4337da2899SCharles.Forsyth {
4437da2899SCharles.Forsyth Chan *c; /* io channel */
4537da2899SCharles.Forsyth uchar state; /* state of connection */
4637da2899SCharles.Forsyth int ref; /* serialized by dslock for atomic destroy */
4737da2899SCharles.Forsyth
4837da2899SCharles.Forsyth uchar encryptalg; /* encryption algorithm */
4937da2899SCharles.Forsyth ushort blocklen; /* blocking length */
5037da2899SCharles.Forsyth
5137da2899SCharles.Forsyth ushort diglen; /* length of digest */
5237da2899SCharles.Forsyth DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
5337da2899SCharles.Forsyth
5437da2899SCharles.Forsyth /* for SSL format */
5537da2899SCharles.Forsyth int max; /* maximum unpadded data per msg */
5637da2899SCharles.Forsyth int maxpad; /* maximum padded data per msg */
5737da2899SCharles.Forsyth
5837da2899SCharles.Forsyth /* input side */
5937da2899SCharles.Forsyth OneWay in;
6037da2899SCharles.Forsyth Block *processed;
6137da2899SCharles.Forsyth Block *unprocessed;
6237da2899SCharles.Forsyth
6337da2899SCharles.Forsyth /* output side */
6437da2899SCharles.Forsyth OneWay out;
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsyth /* protections */
6737da2899SCharles.Forsyth char* user;
6837da2899SCharles.Forsyth int perm;
6937da2899SCharles.Forsyth };
7037da2899SCharles.Forsyth
7137da2899SCharles.Forsyth enum
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth Maxdmsg= 1<<16,
7437da2899SCharles.Forsyth Maxdstate= 1<<10,
7537da2899SCharles.Forsyth };
7637da2899SCharles.Forsyth
7737da2899SCharles.Forsyth Lock dslock;
7837da2899SCharles.Forsyth int dshiwat;
7937da2899SCharles.Forsyth int maxdstate = 20;
8037da2899SCharles.Forsyth Dstate** dstate;
8137da2899SCharles.Forsyth
8237da2899SCharles.Forsyth enum{
8337da2899SCharles.Forsyth Qtopdir = 1, /* top level directory */
8437da2899SCharles.Forsyth Qclonus,
8537da2899SCharles.Forsyth Qconvdir, /* directory for a conversation */
8637da2899SCharles.Forsyth Qdata,
8737da2899SCharles.Forsyth Qctl,
8837da2899SCharles.Forsyth Qsecretin,
8937da2899SCharles.Forsyth Qsecretout,
9037da2899SCharles.Forsyth Qencalgs,
9137da2899SCharles.Forsyth Qhashalgs
9237da2899SCharles.Forsyth };
9337da2899SCharles.Forsyth
9437da2899SCharles.Forsyth #define TYPE(x) ((ulong)(x).path & 0xf)
9537da2899SCharles.Forsyth #define CONV(x) (((ulong)(x).path >> 4)&(Maxdstate-1))
9637da2899SCharles.Forsyth #define QID(c, y) (((c)<<4) | (y))
9737da2899SCharles.Forsyth
9837da2899SCharles.Forsyth static char* encalgs;
9937da2899SCharles.Forsyth static char* hashalgs;
10037da2899SCharles.Forsyth
10137da2899SCharles.Forsyth void producerand(void);
10237da2899SCharles.Forsyth
10337da2899SCharles.Forsyth static void alglistinit(void);
10437da2899SCharles.Forsyth static void ensure(Dstate*, Block**, int);
10537da2899SCharles.Forsyth static void consume(Block**, uchar*, int);
10637da2899SCharles.Forsyth static void setsecret(OneWay*, uchar*, int);
10737da2899SCharles.Forsyth static Block* encryptb(Dstate*, Block*, int);
10837da2899SCharles.Forsyth static Block* decryptb(Dstate*, Block*);
10937da2899SCharles.Forsyth static Block* digestb(Dstate*, Block*, int);
11037da2899SCharles.Forsyth static void checkdigestb(Dstate*, Block*);
11137da2899SCharles.Forsyth static Chan* buftochan(char*);
11237da2899SCharles.Forsyth static void sslhangup(Dstate*);
113*ad01d857SCharles.Forsyth static void dsclone(Chan *c);
11437da2899SCharles.Forsyth static void dsnew(Chan *c, Dstate **);
11537da2899SCharles.Forsyth
11637da2899SCharles.Forsyth static int
sslgen(Chan * c,char * dname,Dirtab * d,int nd,int s,Dir * dp)11737da2899SCharles.Forsyth sslgen(Chan *c, char *dname, Dirtab *d, int nd, int s, Dir *dp)
11837da2899SCharles.Forsyth {
11937da2899SCharles.Forsyth Qid q;
12037da2899SCharles.Forsyth Dstate *ds;
121*ad01d857SCharles.Forsyth char *p, *nm;
12237da2899SCharles.Forsyth
12337da2899SCharles.Forsyth USED(dname);
12437da2899SCharles.Forsyth USED(nd);
12537da2899SCharles.Forsyth USED(d);
12637da2899SCharles.Forsyth q.type = QTFILE;
12737da2899SCharles.Forsyth q.vers = 0;
12837da2899SCharles.Forsyth if(s == DEVDOTDOT){
12937da2899SCharles.Forsyth q.path = QID(0, Qtopdir);
13037da2899SCharles.Forsyth q.type = QTDIR;
13137da2899SCharles.Forsyth devdir(c, q, "#D", 0, eve, 0555, dp);
13237da2899SCharles.Forsyth return 1;
13337da2899SCharles.Forsyth }
13437da2899SCharles.Forsyth switch(TYPE(c->qid)) {
13537da2899SCharles.Forsyth case Qtopdir:
13637da2899SCharles.Forsyth if(s < dshiwat) {
13737da2899SCharles.Forsyth q.path = QID(s, Qconvdir);
13837da2899SCharles.Forsyth q.type = QTDIR;
13937da2899SCharles.Forsyth ds = dstate[s];
14037da2899SCharles.Forsyth if(ds != 0)
14137da2899SCharles.Forsyth nm = ds->user;
14237da2899SCharles.Forsyth else
14337da2899SCharles.Forsyth nm = eve;
144*ad01d857SCharles.Forsyth snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
145*ad01d857SCharles.Forsyth devdir(c, q, up->genbuf, 0, nm, DMDIR|0555, dp);
14637da2899SCharles.Forsyth return 1;
14737da2899SCharles.Forsyth }
14837da2899SCharles.Forsyth if(s > dshiwat)
14937da2899SCharles.Forsyth return -1;
15037da2899SCharles.Forsyth /* fall through */
15137da2899SCharles.Forsyth case Qclonus:
15237da2899SCharles.Forsyth q.path = QID(0, Qclonus);
15337da2899SCharles.Forsyth devdir(c, q, "clone", 0, eve, 0666, dp);
15437da2899SCharles.Forsyth return 1;
15537da2899SCharles.Forsyth case Qconvdir:
15637da2899SCharles.Forsyth ds = dstate[CONV(c->qid)];
15737da2899SCharles.Forsyth if(ds != 0)
15837da2899SCharles.Forsyth nm = ds->user;
15937da2899SCharles.Forsyth else
16037da2899SCharles.Forsyth nm = eve;
16137da2899SCharles.Forsyth switch(s) {
16237da2899SCharles.Forsyth default:
16337da2899SCharles.Forsyth return -1;
16437da2899SCharles.Forsyth case 0:
16537da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qctl);
16637da2899SCharles.Forsyth p = "ctl";
16737da2899SCharles.Forsyth break;
16837da2899SCharles.Forsyth case 1:
16937da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qdata);
17037da2899SCharles.Forsyth p = "data";
17137da2899SCharles.Forsyth break;
17237da2899SCharles.Forsyth case 2:
17337da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qsecretin);
17437da2899SCharles.Forsyth p = "secretin";
17537da2899SCharles.Forsyth break;
17637da2899SCharles.Forsyth case 3:
17737da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qsecretout);
17837da2899SCharles.Forsyth p = "secretout";
17937da2899SCharles.Forsyth break;
18037da2899SCharles.Forsyth case 4:
18137da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qencalgs);
18237da2899SCharles.Forsyth p = "encalgs";
18337da2899SCharles.Forsyth break;
18437da2899SCharles.Forsyth case 5:
18537da2899SCharles.Forsyth q.path = QID(CONV(c->qid), Qhashalgs);
18637da2899SCharles.Forsyth p = "hashalgs";
18737da2899SCharles.Forsyth break;
18837da2899SCharles.Forsyth }
18937da2899SCharles.Forsyth devdir(c, q, p, 0, nm, 0660, dp);
19037da2899SCharles.Forsyth return 1;
19137da2899SCharles.Forsyth }
19237da2899SCharles.Forsyth return -1;
19337da2899SCharles.Forsyth }
19437da2899SCharles.Forsyth
19537da2899SCharles.Forsyth static void
sslinit(void)19637da2899SCharles.Forsyth sslinit(void)
19737da2899SCharles.Forsyth {
19837da2899SCharles.Forsyth if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
19937da2899SCharles.Forsyth panic("sslinit");
20037da2899SCharles.Forsyth alglistinit();
20137da2899SCharles.Forsyth }
20237da2899SCharles.Forsyth
20337da2899SCharles.Forsyth static Chan *
sslattach(char * spec)20437da2899SCharles.Forsyth sslattach(char *spec)
20537da2899SCharles.Forsyth {
20637da2899SCharles.Forsyth Chan *c;
20737da2899SCharles.Forsyth
20837da2899SCharles.Forsyth c = devattach('D', spec);
20937da2899SCharles.Forsyth c->qid.path = QID(0, Qtopdir);
21037da2899SCharles.Forsyth c->qid.vers = 0;
21137da2899SCharles.Forsyth c->qid.type = QTDIR;
21237da2899SCharles.Forsyth return c;
21337da2899SCharles.Forsyth }
21437da2899SCharles.Forsyth
21537da2899SCharles.Forsyth static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)21637da2899SCharles.Forsyth sslwalk(Chan *c, Chan *nc, char **name, int nname)
21737da2899SCharles.Forsyth {
21837da2899SCharles.Forsyth return devwalk(c, nc, name, nname, 0, 0, sslgen);
21937da2899SCharles.Forsyth }
22037da2899SCharles.Forsyth
22137da2899SCharles.Forsyth static int
sslstat(Chan * c,uchar * db,int n)22237da2899SCharles.Forsyth sslstat(Chan *c, uchar *db, int n)
22337da2899SCharles.Forsyth {
22437da2899SCharles.Forsyth return devstat(c, db, n, 0, 0, sslgen);
22537da2899SCharles.Forsyth }
22637da2899SCharles.Forsyth
22737da2899SCharles.Forsyth static Chan*
sslopen(Chan * c,int omode)22837da2899SCharles.Forsyth sslopen(Chan *c, int omode)
22937da2899SCharles.Forsyth {
23037da2899SCharles.Forsyth Dstate *s, **pp;
23137da2899SCharles.Forsyth int perm;
23237da2899SCharles.Forsyth
23337da2899SCharles.Forsyth perm = 0;
23437da2899SCharles.Forsyth omode &= 3;
23537da2899SCharles.Forsyth switch(omode) {
23637da2899SCharles.Forsyth case OREAD:
23737da2899SCharles.Forsyth perm = 4;
23837da2899SCharles.Forsyth break;
23937da2899SCharles.Forsyth case OWRITE:
24037da2899SCharles.Forsyth perm = 2;
24137da2899SCharles.Forsyth break;
24237da2899SCharles.Forsyth case ORDWR:
24337da2899SCharles.Forsyth perm = 6;
24437da2899SCharles.Forsyth break;
24537da2899SCharles.Forsyth }
24637da2899SCharles.Forsyth
24737da2899SCharles.Forsyth switch(TYPE(c->qid)) {
24837da2899SCharles.Forsyth default:
24937da2899SCharles.Forsyth panic("sslopen");
25037da2899SCharles.Forsyth case Qtopdir:
25137da2899SCharles.Forsyth case Qconvdir:
25237da2899SCharles.Forsyth if(omode != OREAD)
25337da2899SCharles.Forsyth error(Eperm);
25437da2899SCharles.Forsyth break;
25537da2899SCharles.Forsyth case Qclonus:
256*ad01d857SCharles.Forsyth dsclone(c);
25737da2899SCharles.Forsyth break;
25837da2899SCharles.Forsyth case Qctl:
25937da2899SCharles.Forsyth case Qdata:
26037da2899SCharles.Forsyth case Qsecretin:
26137da2899SCharles.Forsyth case Qsecretout:
26237da2899SCharles.Forsyth if(waserror()) {
26337da2899SCharles.Forsyth unlock(&dslock);
26437da2899SCharles.Forsyth nexterror();
26537da2899SCharles.Forsyth }
26637da2899SCharles.Forsyth lock(&dslock);
26737da2899SCharles.Forsyth pp = &dstate[CONV(c->qid)];
26837da2899SCharles.Forsyth s = *pp;
26937da2899SCharles.Forsyth if(s == 0)
27037da2899SCharles.Forsyth dsnew(c, pp);
27137da2899SCharles.Forsyth else {
27237da2899SCharles.Forsyth if((perm & (s->perm>>6)) != perm
27337da2899SCharles.Forsyth && (strcmp(up->env->user, s->user) != 0
27437da2899SCharles.Forsyth || (perm & s->perm) != perm))
27537da2899SCharles.Forsyth error(Eperm);
27637da2899SCharles.Forsyth
27737da2899SCharles.Forsyth s->ref++;
27837da2899SCharles.Forsyth }
27937da2899SCharles.Forsyth unlock(&dslock);
28037da2899SCharles.Forsyth poperror();
28137da2899SCharles.Forsyth break;
28237da2899SCharles.Forsyth case Qencalgs:
28337da2899SCharles.Forsyth case Qhashalgs:
28437da2899SCharles.Forsyth if(omode != OREAD)
28537da2899SCharles.Forsyth error(Eperm);
28637da2899SCharles.Forsyth break;
28737da2899SCharles.Forsyth }
28837da2899SCharles.Forsyth c->mode = openmode(omode);
28937da2899SCharles.Forsyth c->flag |= COPEN;
29037da2899SCharles.Forsyth c->offset = 0;
29137da2899SCharles.Forsyth return c;
29237da2899SCharles.Forsyth }
29337da2899SCharles.Forsyth
29437da2899SCharles.Forsyth static int
sslwstat(Chan * c,uchar * db,int n)295*ad01d857SCharles.Forsyth sslwstat(Chan *c, uchar *db, int n)
29637da2899SCharles.Forsyth {
297*ad01d857SCharles.Forsyth Dir *dir;
29837da2899SCharles.Forsyth Dstate *s;
299*ad01d857SCharles.Forsyth int m;
30037da2899SCharles.Forsyth
30137da2899SCharles.Forsyth s = dstate[CONV(c->qid)];
30237da2899SCharles.Forsyth if(s == 0)
30337da2899SCharles.Forsyth error(Ebadusefd);
30437da2899SCharles.Forsyth if(strcmp(s->user, up->env->user) != 0)
30537da2899SCharles.Forsyth error(Eperm);
306*ad01d857SCharles.Forsyth
307*ad01d857SCharles.Forsyth dir = smalloc(sizeof(Dir)+n);
308*ad01d857SCharles.Forsyth m = convM2D(db, n, &dir[0], (char*)&dir[1]);
309*ad01d857SCharles.Forsyth if(m == 0){
310*ad01d857SCharles.Forsyth free(dir);
311*ad01d857SCharles.Forsyth error(Eshortstat);
312*ad01d857SCharles.Forsyth }
313*ad01d857SCharles.Forsyth
314*ad01d857SCharles.Forsyth if(!emptystr(dir->uid))
315*ad01d857SCharles.Forsyth kstrdup(&s->user, dir->uid);
316*ad01d857SCharles.Forsyth if(dir->mode != ~0UL)
317*ad01d857SCharles.Forsyth s->perm = dir->mode;
318*ad01d857SCharles.Forsyth
319*ad01d857SCharles.Forsyth free(dir);
320*ad01d857SCharles.Forsyth return m;
32137da2899SCharles.Forsyth }
32237da2899SCharles.Forsyth
32337da2899SCharles.Forsyth static void
sslclose(Chan * c)32437da2899SCharles.Forsyth sslclose(Chan *c)
32537da2899SCharles.Forsyth {
32637da2899SCharles.Forsyth Dstate *s;
32737da2899SCharles.Forsyth
32837da2899SCharles.Forsyth switch(TYPE(c->qid)) {
32937da2899SCharles.Forsyth case Qctl:
33037da2899SCharles.Forsyth case Qdata:
33137da2899SCharles.Forsyth case Qsecretin:
33237da2899SCharles.Forsyth case Qsecretout:
33337da2899SCharles.Forsyth if((c->flag & COPEN) == 0)
33437da2899SCharles.Forsyth break;
33537da2899SCharles.Forsyth
33637da2899SCharles.Forsyth s = dstate[CONV(c->qid)];
33737da2899SCharles.Forsyth if(s == 0)
33837da2899SCharles.Forsyth break;
33937da2899SCharles.Forsyth
34037da2899SCharles.Forsyth lock(&dslock);
34137da2899SCharles.Forsyth if(--s->ref > 0) {
34237da2899SCharles.Forsyth unlock(&dslock);
34337da2899SCharles.Forsyth break;
34437da2899SCharles.Forsyth }
34537da2899SCharles.Forsyth dstate[CONV(c->qid)] = 0;
34637da2899SCharles.Forsyth unlock(&dslock);
34737da2899SCharles.Forsyth
34837da2899SCharles.Forsyth sslhangup(s);
34937da2899SCharles.Forsyth if(s->c)
35037da2899SCharles.Forsyth cclose(s->c);
35137da2899SCharles.Forsyth free(s->user);
35237da2899SCharles.Forsyth free(s->in.secret);
35337da2899SCharles.Forsyth free(s->out.secret);
35437da2899SCharles.Forsyth free(s->in.state);
35537da2899SCharles.Forsyth free(s->out.state);
35637da2899SCharles.Forsyth free(s);
35737da2899SCharles.Forsyth }
35837da2899SCharles.Forsyth }
35937da2899SCharles.Forsyth
36037da2899SCharles.Forsyth /*
36137da2899SCharles.Forsyth * make sure we have at least 'n' bytes in list 'l'
36237da2899SCharles.Forsyth */
36337da2899SCharles.Forsyth static void
ensure(Dstate * s,Block ** l,int n)36437da2899SCharles.Forsyth ensure(Dstate *s, Block **l, int n)
36537da2899SCharles.Forsyth {
36637da2899SCharles.Forsyth int sofar, i;
36737da2899SCharles.Forsyth Block *b, *bl;
36837da2899SCharles.Forsyth
36937da2899SCharles.Forsyth sofar = 0;
37037da2899SCharles.Forsyth for(b = *l; b; b = b->next){
37137da2899SCharles.Forsyth sofar += BLEN(b);
37237da2899SCharles.Forsyth if(sofar >= n)
37337da2899SCharles.Forsyth return;
37437da2899SCharles.Forsyth l = &b->next;
37537da2899SCharles.Forsyth }
37637da2899SCharles.Forsyth
37737da2899SCharles.Forsyth while(sofar < n){
37837da2899SCharles.Forsyth bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
37937da2899SCharles.Forsyth if(bl == 0)
38037da2899SCharles.Forsyth error(Ehungup);
38137da2899SCharles.Forsyth *l = bl;
38237da2899SCharles.Forsyth i = 0;
38337da2899SCharles.Forsyth for(b = bl; b; b = b->next){
38437da2899SCharles.Forsyth i += BLEN(b);
38537da2899SCharles.Forsyth l = &b->next;
38637da2899SCharles.Forsyth }
38737da2899SCharles.Forsyth if(i == 0)
38837da2899SCharles.Forsyth error(Ehungup);
38937da2899SCharles.Forsyth
39037da2899SCharles.Forsyth sofar += i;
39137da2899SCharles.Forsyth }
39237da2899SCharles.Forsyth }
39337da2899SCharles.Forsyth
39437da2899SCharles.Forsyth /*
39537da2899SCharles.Forsyth * copy 'n' bytes from 'l' into 'p' and free
39637da2899SCharles.Forsyth * the bytes in 'l'
39737da2899SCharles.Forsyth */
39837da2899SCharles.Forsyth static void
consume(Block ** l,uchar * p,int n)39937da2899SCharles.Forsyth consume(Block **l, uchar *p, int n)
40037da2899SCharles.Forsyth {
40137da2899SCharles.Forsyth Block *b;
40237da2899SCharles.Forsyth int i;
40337da2899SCharles.Forsyth
40437da2899SCharles.Forsyth for(; *l && n > 0; n -= i){
40537da2899SCharles.Forsyth b = *l;
40637da2899SCharles.Forsyth i = BLEN(b);
40737da2899SCharles.Forsyth if(i > n)
40837da2899SCharles.Forsyth i = n;
40937da2899SCharles.Forsyth memmove(p, b->rp, i);
41037da2899SCharles.Forsyth b->rp += i;
41137da2899SCharles.Forsyth p += i;
41237da2899SCharles.Forsyth if(BLEN(b) < 0)
41337da2899SCharles.Forsyth panic("consume");
41437da2899SCharles.Forsyth if(BLEN(b))
41537da2899SCharles.Forsyth break;
41637da2899SCharles.Forsyth *l = b->next;
41737da2899SCharles.Forsyth freeb(b);
41837da2899SCharles.Forsyth }
41937da2899SCharles.Forsyth }
42037da2899SCharles.Forsyth
42137da2899SCharles.Forsyth /*
42237da2899SCharles.Forsyth * remove at most n bytes from the queue, if discard is set
42337da2899SCharles.Forsyth * dump the remainder
42437da2899SCharles.Forsyth */
42537da2899SCharles.Forsyth static Block*
qtake(Block ** l,int n,int discard)42637da2899SCharles.Forsyth qtake(Block **l, int n, int discard)
42737da2899SCharles.Forsyth {
42837da2899SCharles.Forsyth Block *nb, *b, *first;
42937da2899SCharles.Forsyth int i;
43037da2899SCharles.Forsyth
43137da2899SCharles.Forsyth first = *l;
43237da2899SCharles.Forsyth for(b = first; b; b = b->next){
43337da2899SCharles.Forsyth i = BLEN(b);
43437da2899SCharles.Forsyth if(i == n){
43537da2899SCharles.Forsyth if(discard){
43637da2899SCharles.Forsyth freeblist(b->next);
43737da2899SCharles.Forsyth *l = 0;
43837da2899SCharles.Forsyth } else
43937da2899SCharles.Forsyth *l = b->next;
44037da2899SCharles.Forsyth b->next = 0;
44137da2899SCharles.Forsyth return first;
44237da2899SCharles.Forsyth } else if(i > n){
44337da2899SCharles.Forsyth i -= n;
44437da2899SCharles.Forsyth if(discard){
44537da2899SCharles.Forsyth freeblist(b->next);
44637da2899SCharles.Forsyth *l = 0;
44737da2899SCharles.Forsyth } else {
44837da2899SCharles.Forsyth nb = allocb(i);
44937da2899SCharles.Forsyth memmove(nb->wp, b->rp+n, i);
45037da2899SCharles.Forsyth nb->wp += i;
45137da2899SCharles.Forsyth nb->next = b->next;
45237da2899SCharles.Forsyth *l = nb;
45337da2899SCharles.Forsyth }
45437da2899SCharles.Forsyth b->wp -= i;
45537da2899SCharles.Forsyth b->next = 0;
45637da2899SCharles.Forsyth if(BLEN(b) < 0)
45737da2899SCharles.Forsyth panic("qtake");
45837da2899SCharles.Forsyth return first;
45937da2899SCharles.Forsyth } else
46037da2899SCharles.Forsyth n -= i;
46137da2899SCharles.Forsyth if(BLEN(b) < 0)
46237da2899SCharles.Forsyth panic("qtake");
46337da2899SCharles.Forsyth }
46437da2899SCharles.Forsyth *l = 0;
46537da2899SCharles.Forsyth return first;
46637da2899SCharles.Forsyth }
46737da2899SCharles.Forsyth
46837da2899SCharles.Forsyth static Block*
sslbread(Chan * c,long n,ulong offset)46937da2899SCharles.Forsyth sslbread(Chan *c, long n, ulong offset)
47037da2899SCharles.Forsyth {
47137da2899SCharles.Forsyth volatile struct { Dstate *s; } s;
47237da2899SCharles.Forsyth volatile struct { int nc; } nc;
47337da2899SCharles.Forsyth Block *b;
47437da2899SCharles.Forsyth uchar count[3];
47537da2899SCharles.Forsyth int len, pad;
47637da2899SCharles.Forsyth
47737da2899SCharles.Forsyth USED(offset);
47837da2899SCharles.Forsyth s.s = dstate[CONV(c->qid)];
47937da2899SCharles.Forsyth if(s.s == 0)
48037da2899SCharles.Forsyth panic("sslbread");
48137da2899SCharles.Forsyth if(s.s->state == Sincomplete)
48237da2899SCharles.Forsyth error(Ebadusefd);
48337da2899SCharles.Forsyth
48437da2899SCharles.Forsyth nc.nc = 0;
48537da2899SCharles.Forsyth if(waserror()){
48637da2899SCharles.Forsyth qunlock(&s.s->in.q);
48737da2899SCharles.Forsyth if(strcmp(up->env->errstr, "interrupted") == 0){
48837da2899SCharles.Forsyth if(nc.nc > 0){
48937da2899SCharles.Forsyth b = allocb(nc.nc);
49037da2899SCharles.Forsyth memmove(b->wp, count, nc.nc);
49137da2899SCharles.Forsyth b->wp += nc.nc;
49237da2899SCharles.Forsyth b->next = s.s->unprocessed;
49337da2899SCharles.Forsyth s.s->unprocessed = b;
49437da2899SCharles.Forsyth }
49537da2899SCharles.Forsyth } else
49637da2899SCharles.Forsyth sslhangup(s.s);
49737da2899SCharles.Forsyth nexterror();
49837da2899SCharles.Forsyth }
49937da2899SCharles.Forsyth qlock(&s.s->in.q);
50037da2899SCharles.Forsyth
50137da2899SCharles.Forsyth if(s.s->processed == 0){
50237da2899SCharles.Forsyth /* read in the whole message */
50337da2899SCharles.Forsyth ensure(s.s, &s.s->unprocessed, 2);
50437da2899SCharles.Forsyth
50537da2899SCharles.Forsyth consume(&s.s->unprocessed, count, 2);
50637da2899SCharles.Forsyth nc.nc += 2;
50737da2899SCharles.Forsyth if(count[0] & 0x80){
50837da2899SCharles.Forsyth len = ((count[0] & 0x7f)<<8) | count[1];
50937da2899SCharles.Forsyth ensure(s.s, &s.s->unprocessed, len);
51037da2899SCharles.Forsyth pad = 0;
51137da2899SCharles.Forsyth } else {
51237da2899SCharles.Forsyth len = ((count[0] & 0x3f)<<8) | count[1];
51337da2899SCharles.Forsyth ensure(s.s, &s.s->unprocessed, len+1);
51437da2899SCharles.Forsyth consume(&s.s->unprocessed, count + nc.nc, 1);
51537da2899SCharles.Forsyth pad = count[nc.nc];
51637da2899SCharles.Forsyth nc.nc++;
51737da2899SCharles.Forsyth if(pad > len){
51837da2899SCharles.Forsyth print("pad %d buf len %d\n", pad, len);
51937da2899SCharles.Forsyth error("bad pad in ssl message");
52037da2899SCharles.Forsyth }
52137da2899SCharles.Forsyth }
52237da2899SCharles.Forsyth nc.nc = 0;
52337da2899SCharles.Forsyth
52437da2899SCharles.Forsyth /* put extra on unprocessed queue */
52537da2899SCharles.Forsyth s.s->processed = qtake(&s.s->unprocessed, len, 0);
52637da2899SCharles.Forsyth
52737da2899SCharles.Forsyth if(waserror()){
52837da2899SCharles.Forsyth qunlock(&s.s->in.ctlq);
52937da2899SCharles.Forsyth nexterror();
53037da2899SCharles.Forsyth }
53137da2899SCharles.Forsyth qlock(&s.s->in.ctlq);
53237da2899SCharles.Forsyth switch(s.s->state){
53337da2899SCharles.Forsyth case Sencrypting:
53437da2899SCharles.Forsyth s.s->processed = decryptb(s.s, s.s->processed);
53537da2899SCharles.Forsyth break;
53637da2899SCharles.Forsyth case Sdigesting:
53737da2899SCharles.Forsyth s.s->processed = pullupblock(s.s->processed, s.s->diglen);
53837da2899SCharles.Forsyth if(s.s->processed == 0)
53937da2899SCharles.Forsyth error("ssl message too short");
54037da2899SCharles.Forsyth checkdigestb(s.s, s.s->processed);
54137da2899SCharles.Forsyth s.s->processed->rp += s.s->diglen;
54237da2899SCharles.Forsyth break;
54337da2899SCharles.Forsyth case Sdigenc:
54437da2899SCharles.Forsyth s.s->processed = decryptb(s.s, s.s->processed);
54537da2899SCharles.Forsyth s.s->processed = pullupblock(s.s->processed, s.s->diglen);
54637da2899SCharles.Forsyth if(s.s->processed == 0)
54737da2899SCharles.Forsyth error("ssl message too short");
54837da2899SCharles.Forsyth checkdigestb(s.s, s.s->processed);
54937da2899SCharles.Forsyth s.s->processed->rp += s.s->diglen;
55037da2899SCharles.Forsyth len -= s.s->diglen;
55137da2899SCharles.Forsyth break;
55237da2899SCharles.Forsyth }
55337da2899SCharles.Forsyth s.s->in.mid++;
55437da2899SCharles.Forsyth qunlock(&s.s->in.ctlq);
55537da2899SCharles.Forsyth poperror();
55637da2899SCharles.Forsyth
55737da2899SCharles.Forsyth /* remove pad */
55837da2899SCharles.Forsyth if(pad)
55937da2899SCharles.Forsyth s.s->processed = qtake(&s.s->processed, len - pad, 1);
56037da2899SCharles.Forsyth }
56137da2899SCharles.Forsyth
56237da2899SCharles.Forsyth /* return at most what was asked for */
56337da2899SCharles.Forsyth b = qtake(&s.s->processed, n, 0);
56437da2899SCharles.Forsyth
56537da2899SCharles.Forsyth qunlock(&s.s->in.q);
56637da2899SCharles.Forsyth poperror();
56737da2899SCharles.Forsyth
56837da2899SCharles.Forsyth return b;
56937da2899SCharles.Forsyth }
57037da2899SCharles.Forsyth
57137da2899SCharles.Forsyth static long
sslread(Chan * c,void * a,long n,vlong offset)57237da2899SCharles.Forsyth sslread(Chan *c, void *a, long n, vlong offset)
57337da2899SCharles.Forsyth {
57437da2899SCharles.Forsyth volatile struct { Block *b; } b;
57537da2899SCharles.Forsyth Block *nb;
57637da2899SCharles.Forsyth uchar *va;
57737da2899SCharles.Forsyth int i;
57837da2899SCharles.Forsyth char buf[128];
57937da2899SCharles.Forsyth
58037da2899SCharles.Forsyth if(c->qid.type & QTDIR)
58137da2899SCharles.Forsyth return devdirread(c, a, n, 0, 0, sslgen);
58237da2899SCharles.Forsyth
58337da2899SCharles.Forsyth switch(TYPE(c->qid)) {
58437da2899SCharles.Forsyth default:
58537da2899SCharles.Forsyth error(Ebadusefd);
58637da2899SCharles.Forsyth case Qctl:
58737da2899SCharles.Forsyth sprint(buf, "%ld", CONV(c->qid));
58837da2899SCharles.Forsyth return readstr(offset, a, n, buf);
58937da2899SCharles.Forsyth case Qdata:
59037da2899SCharles.Forsyth b.b = sslbread(c, n, offset);
59137da2899SCharles.Forsyth break;
59237da2899SCharles.Forsyth case Qencalgs:
59337da2899SCharles.Forsyth return readstr(offset, a, n, encalgs);
59437da2899SCharles.Forsyth case Qhashalgs:
59537da2899SCharles.Forsyth return readstr(offset, a, n, hashalgs);
59637da2899SCharles.Forsyth }
59737da2899SCharles.Forsyth
59837da2899SCharles.Forsyth n = 0;
59937da2899SCharles.Forsyth va = a;
60037da2899SCharles.Forsyth for(nb = b.b; nb; nb = nb->next){
60137da2899SCharles.Forsyth i = BLEN(nb);
60237da2899SCharles.Forsyth memmove(va+n, nb->rp, i);
60337da2899SCharles.Forsyth n += i;
60437da2899SCharles.Forsyth }
60537da2899SCharles.Forsyth
60637da2899SCharles.Forsyth freeblist(b.b);
60737da2899SCharles.Forsyth
60837da2899SCharles.Forsyth return n;
60937da2899SCharles.Forsyth }
61037da2899SCharles.Forsyth
61137da2899SCharles.Forsyth /*
61237da2899SCharles.Forsyth * this algorithm doesn't have to be great since we're just
61337da2899SCharles.Forsyth * trying to obscure the block fill
61437da2899SCharles.Forsyth */
61537da2899SCharles.Forsyth static void
randfill(uchar * buf,int len)61637da2899SCharles.Forsyth randfill(uchar *buf, int len)
61737da2899SCharles.Forsyth {
61837da2899SCharles.Forsyth while(len-- > 0)
61937da2899SCharles.Forsyth *buf++ = nrand(256);
62037da2899SCharles.Forsyth }
62137da2899SCharles.Forsyth
62237da2899SCharles.Forsyth /*
62337da2899SCharles.Forsyth * use SSL record format, add in count and digest or encrypt
62437da2899SCharles.Forsyth */
62537da2899SCharles.Forsyth static long
sslbwrite(Chan * c,Block * b,ulong offset)62637da2899SCharles.Forsyth sslbwrite(Chan *c, Block *b, ulong offset)
62737da2899SCharles.Forsyth {
62837da2899SCharles.Forsyth volatile struct { Dstate *s; } s;
62937da2899SCharles.Forsyth volatile struct { Block *b; } bb;
63037da2899SCharles.Forsyth Block *nb;
63137da2899SCharles.Forsyth int h, n, m, pad, rv;
63237da2899SCharles.Forsyth uchar *p;
63337da2899SCharles.Forsyth
63437da2899SCharles.Forsyth bb.b = b;
63537da2899SCharles.Forsyth s.s = dstate[CONV(c->qid)];
63637da2899SCharles.Forsyth if(s.s == 0)
63737da2899SCharles.Forsyth panic("sslbwrite");
63837da2899SCharles.Forsyth if(s.s->state == Sincomplete){
63937da2899SCharles.Forsyth freeb(b);
64037da2899SCharles.Forsyth error(Ebadusefd);
64137da2899SCharles.Forsyth }
64237da2899SCharles.Forsyth
64337da2899SCharles.Forsyth if(waserror()){
64437da2899SCharles.Forsyth qunlock(&s.s->out.q);
64537da2899SCharles.Forsyth if(bb.b)
64637da2899SCharles.Forsyth freeb(bb.b);
64737da2899SCharles.Forsyth sslhangup(s.s);
64837da2899SCharles.Forsyth nexterror();
64937da2899SCharles.Forsyth }
65037da2899SCharles.Forsyth qlock(&s.s->out.q);
65137da2899SCharles.Forsyth
65237da2899SCharles.Forsyth rv = 0;
65337da2899SCharles.Forsyth while(bb.b){
65437da2899SCharles.Forsyth m = n = BLEN(bb.b);
65537da2899SCharles.Forsyth h = s.s->diglen + 2;
65637da2899SCharles.Forsyth
65737da2899SCharles.Forsyth /* trim to maximum block size */
65837da2899SCharles.Forsyth pad = 0;
65937da2899SCharles.Forsyth if(m > s.s->max){
66037da2899SCharles.Forsyth m = s.s->max;
66137da2899SCharles.Forsyth } else if(s.s->blocklen != 1){
66237da2899SCharles.Forsyth pad = (m + s.s->diglen)%s.s->blocklen;
66337da2899SCharles.Forsyth if(pad){
66437da2899SCharles.Forsyth if(m > s.s->maxpad){
66537da2899SCharles.Forsyth pad = 0;
66637da2899SCharles.Forsyth m = s.s->maxpad;
66737da2899SCharles.Forsyth } else {
66837da2899SCharles.Forsyth pad = s.s->blocklen - pad;
66937da2899SCharles.Forsyth h++;
67037da2899SCharles.Forsyth }
67137da2899SCharles.Forsyth }
67237da2899SCharles.Forsyth }
67337da2899SCharles.Forsyth
67437da2899SCharles.Forsyth rv += m;
67537da2899SCharles.Forsyth if(m != n){
67637da2899SCharles.Forsyth nb = allocb(m + h + pad);
67737da2899SCharles.Forsyth memmove(nb->wp + h, bb.b->rp, m);
67837da2899SCharles.Forsyth nb->wp += m + h;
67937da2899SCharles.Forsyth bb.b->rp += m;
68037da2899SCharles.Forsyth } else {
68137da2899SCharles.Forsyth /* add header space */
68237da2899SCharles.Forsyth nb = padblock(bb.b, h);
68337da2899SCharles.Forsyth bb.b = 0;
68437da2899SCharles.Forsyth }
68537da2899SCharles.Forsyth m += s.s->diglen;
68637da2899SCharles.Forsyth
68737da2899SCharles.Forsyth /* SSLv2 style count */
68837da2899SCharles.Forsyth if(pad){
68937da2899SCharles.Forsyth nb = padblock(nb, -pad);
69037da2899SCharles.Forsyth randfill(nb->wp, pad);
69137da2899SCharles.Forsyth nb->wp += pad;
69237da2899SCharles.Forsyth m += pad;
69337da2899SCharles.Forsyth
69437da2899SCharles.Forsyth p = nb->rp;
69537da2899SCharles.Forsyth p[0] = (m>>8);
69637da2899SCharles.Forsyth p[1] = m;
69737da2899SCharles.Forsyth p[2] = pad;
69837da2899SCharles.Forsyth offset = 3;
69937da2899SCharles.Forsyth } else {
70037da2899SCharles.Forsyth p = nb->rp;
70137da2899SCharles.Forsyth p[0] = (m>>8) | 0x80;
70237da2899SCharles.Forsyth p[1] = m;
70337da2899SCharles.Forsyth offset = 2;
70437da2899SCharles.Forsyth }
70537da2899SCharles.Forsyth
70637da2899SCharles.Forsyth switch(s.s->state){
70737da2899SCharles.Forsyth case Sencrypting:
70837da2899SCharles.Forsyth nb = encryptb(s.s, nb, offset);
70937da2899SCharles.Forsyth break;
71037da2899SCharles.Forsyth case Sdigesting:
71137da2899SCharles.Forsyth nb = digestb(s.s, nb, offset);
71237da2899SCharles.Forsyth break;
71337da2899SCharles.Forsyth case Sdigenc:
71437da2899SCharles.Forsyth nb = digestb(s.s, nb, offset);
71537da2899SCharles.Forsyth nb = encryptb(s.s, nb, offset);
71637da2899SCharles.Forsyth break;
71737da2899SCharles.Forsyth }
71837da2899SCharles.Forsyth
71937da2899SCharles.Forsyth s.s->out.mid++;
72037da2899SCharles.Forsyth
72137da2899SCharles.Forsyth m = BLEN(nb);
72237da2899SCharles.Forsyth devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset);
72337da2899SCharles.Forsyth s.s->c->offset += m;
72437da2899SCharles.Forsyth }
72537da2899SCharles.Forsyth qunlock(&s.s->out.q);
72637da2899SCharles.Forsyth poperror();
72737da2899SCharles.Forsyth
72837da2899SCharles.Forsyth return rv;
72937da2899SCharles.Forsyth }
73037da2899SCharles.Forsyth
73137da2899SCharles.Forsyth static void
setsecret(OneWay * w,uchar * secret,int n)73237da2899SCharles.Forsyth setsecret(OneWay *w, uchar *secret, int n)
73337da2899SCharles.Forsyth {
73437da2899SCharles.Forsyth free(w->secret);
73537da2899SCharles.Forsyth w->secret = mallocz(n, 0);
73637da2899SCharles.Forsyth if(w->secret == nil)
73737da2899SCharles.Forsyth error(Enomem);
73837da2899SCharles.Forsyth memmove(w->secret, secret, n);
73937da2899SCharles.Forsyth w->slen = n;
74037da2899SCharles.Forsyth }
74137da2899SCharles.Forsyth
74237da2899SCharles.Forsyth static void
initIDEAkey(OneWay * w)74337da2899SCharles.Forsyth initIDEAkey(OneWay *w)
74437da2899SCharles.Forsyth {
74537da2899SCharles.Forsyth
74637da2899SCharles.Forsyth free(w->state);
74737da2899SCharles.Forsyth w->state = malloc(sizeof(IDEAstate));
74837da2899SCharles.Forsyth if(w->state == nil)
74937da2899SCharles.Forsyth error(Enomem);
75037da2899SCharles.Forsyth if(w->slen >= 24)
75137da2899SCharles.Forsyth setupIDEAstate(w->state, w->secret, w->secret+16);
75237da2899SCharles.Forsyth else if(w->slen >= 16)
75337da2899SCharles.Forsyth setupIDEAstate(w->state, w->secret, 0);
75437da2899SCharles.Forsyth else
75537da2899SCharles.Forsyth error("secret too short");
75637da2899SCharles.Forsyth }
75737da2899SCharles.Forsyth
75837da2899SCharles.Forsyth static void
initDESkey(OneWay * w)75937da2899SCharles.Forsyth initDESkey(OneWay *w)
76037da2899SCharles.Forsyth {
76137da2899SCharles.Forsyth
76237da2899SCharles.Forsyth free(w->state);
76337da2899SCharles.Forsyth w->state = malloc(sizeof(DESstate));
76437da2899SCharles.Forsyth if (!w->state)
76537da2899SCharles.Forsyth error(Enomem);
76637da2899SCharles.Forsyth if(w->slen >= 16)
76737da2899SCharles.Forsyth setupDESstate(w->state, w->secret, w->secret+8);
76837da2899SCharles.Forsyth else if(w->slen >= 8)
76937da2899SCharles.Forsyth setupDESstate(w->state, w->secret, 0);
77037da2899SCharles.Forsyth else
77137da2899SCharles.Forsyth error("secret too short");
77237da2899SCharles.Forsyth }
77337da2899SCharles.Forsyth
77437da2899SCharles.Forsyth /*
77537da2899SCharles.Forsyth * 40 bit DES is the same as 56 bit DES. However,
77637da2899SCharles.Forsyth * 16 bits of the key are masked to zero.
77737da2899SCharles.Forsyth */
77837da2899SCharles.Forsyth static void
initDESkey_40(OneWay * w)77937da2899SCharles.Forsyth initDESkey_40(OneWay *w)
78037da2899SCharles.Forsyth {
78137da2899SCharles.Forsyth uchar key[8];
78237da2899SCharles.Forsyth
78337da2899SCharles.Forsyth
78437da2899SCharles.Forsyth if(w->slen >= 8) {
78537da2899SCharles.Forsyth memmove(key, w->secret, 8);
78637da2899SCharles.Forsyth key[0] &= 0x0f;
78737da2899SCharles.Forsyth key[2] &= 0x0f;
78837da2899SCharles.Forsyth key[4] &= 0x0f;
78937da2899SCharles.Forsyth key[6] &= 0x0f;
79037da2899SCharles.Forsyth }
79137da2899SCharles.Forsyth
79237da2899SCharles.Forsyth free(w->state);
79337da2899SCharles.Forsyth w->state = malloc(sizeof(DESstate));
79437da2899SCharles.Forsyth if (!w->state)
79537da2899SCharles.Forsyth error(Enomem);
79637da2899SCharles.Forsyth if(w->slen >= 16)
79737da2899SCharles.Forsyth setupDESstate(w->state, key, w->secret+8);
79837da2899SCharles.Forsyth else if(w->slen >= 8)
79937da2899SCharles.Forsyth setupDESstate(w->state, key, 0);
80037da2899SCharles.Forsyth else
80137da2899SCharles.Forsyth error("secret too short");
80237da2899SCharles.Forsyth }
80337da2899SCharles.Forsyth
80437da2899SCharles.Forsyth static void
initRC4key(OneWay * w)80537da2899SCharles.Forsyth initRC4key(OneWay *w)
80637da2899SCharles.Forsyth {
80737da2899SCharles.Forsyth free(w->state);
80837da2899SCharles.Forsyth w->state = malloc(sizeof(RC4state));
80937da2899SCharles.Forsyth if (!w->state)
81037da2899SCharles.Forsyth error(Enomem);
81137da2899SCharles.Forsyth setupRC4state(w->state, w->secret, w->slen);
81237da2899SCharles.Forsyth }
81337da2899SCharles.Forsyth
81437da2899SCharles.Forsyth /*
81537da2899SCharles.Forsyth * 40 bit RC4 is the same as n-bit RC4. However,
81637da2899SCharles.Forsyth * we ignore all but the first 40 bits of the key.
81737da2899SCharles.Forsyth */
81837da2899SCharles.Forsyth static void
initRC4key_40(OneWay * w)81937da2899SCharles.Forsyth initRC4key_40(OneWay *w)
82037da2899SCharles.Forsyth {
82137da2899SCharles.Forsyth int slen = w->slen;
82237da2899SCharles.Forsyth
82337da2899SCharles.Forsyth if(slen > 5)
82437da2899SCharles.Forsyth slen = 5;
82537da2899SCharles.Forsyth
82637da2899SCharles.Forsyth free(w->state);
82737da2899SCharles.Forsyth w->state = malloc(sizeof(RC4state));
82837da2899SCharles.Forsyth if (!w->state)
82937da2899SCharles.Forsyth error(Enomem);
83037da2899SCharles.Forsyth setupRC4state(w->state, w->secret, slen);
83137da2899SCharles.Forsyth }
83237da2899SCharles.Forsyth
83337da2899SCharles.Forsyth /*
83437da2899SCharles.Forsyth * 128 bit RC4 is the same as n-bit RC4. However,
83537da2899SCharles.Forsyth * we ignore all but the first 128 bits of the key.
83637da2899SCharles.Forsyth */
83737da2899SCharles.Forsyth static void
initRC4key_128(OneWay * w)83837da2899SCharles.Forsyth initRC4key_128(OneWay *w)
83937da2899SCharles.Forsyth {
84037da2899SCharles.Forsyth int slen = w->slen;
84137da2899SCharles.Forsyth
84237da2899SCharles.Forsyth if(slen > 16)
84337da2899SCharles.Forsyth slen = 16;
84437da2899SCharles.Forsyth
84537da2899SCharles.Forsyth free(w->state);
84637da2899SCharles.Forsyth w->state = malloc(sizeof(RC4state));
84737da2899SCharles.Forsyth if (!w->state)
84837da2899SCharles.Forsyth error(Enomem);
84937da2899SCharles.Forsyth setupRC4state(w->state, w->secret, slen);
85037da2899SCharles.Forsyth }
85137da2899SCharles.Forsyth
85237da2899SCharles.Forsyth typedef struct Hashalg Hashalg;
85337da2899SCharles.Forsyth struct Hashalg
85437da2899SCharles.Forsyth {
85537da2899SCharles.Forsyth char *name;
85637da2899SCharles.Forsyth int diglen;
85737da2899SCharles.Forsyth DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
85837da2899SCharles.Forsyth };
85937da2899SCharles.Forsyth
86037da2899SCharles.Forsyth Hashalg hashtab[] =
86137da2899SCharles.Forsyth {
86237da2899SCharles.Forsyth { "md4", MD4dlen, md4, },
86337da2899SCharles.Forsyth { "md5", MD5dlen, md5, },
86437da2899SCharles.Forsyth { "sha1", SHA1dlen, sha1, },
86537da2899SCharles.Forsyth { "sha", SHA1dlen, sha1, },
86637da2899SCharles.Forsyth { 0 }
86737da2899SCharles.Forsyth };
86837da2899SCharles.Forsyth
86937da2899SCharles.Forsyth static int
parsehashalg(char * p,Dstate * s)87037da2899SCharles.Forsyth parsehashalg(char *p, Dstate *s)
87137da2899SCharles.Forsyth {
87237da2899SCharles.Forsyth Hashalg *ha;
87337da2899SCharles.Forsyth
87437da2899SCharles.Forsyth for(ha = hashtab; ha->name; ha++){
87537da2899SCharles.Forsyth if(strcmp(p, ha->name) == 0){
87637da2899SCharles.Forsyth s->hf = ha->hf;
87737da2899SCharles.Forsyth s->diglen = ha->diglen;
87837da2899SCharles.Forsyth s->state &= ~Sclear;
87937da2899SCharles.Forsyth s->state |= Sdigesting;
88037da2899SCharles.Forsyth return 0;
88137da2899SCharles.Forsyth }
88237da2899SCharles.Forsyth }
88337da2899SCharles.Forsyth return -1;
88437da2899SCharles.Forsyth }
88537da2899SCharles.Forsyth
88637da2899SCharles.Forsyth typedef struct Encalg Encalg;
88737da2899SCharles.Forsyth struct Encalg
88837da2899SCharles.Forsyth {
88937da2899SCharles.Forsyth char *name;
89037da2899SCharles.Forsyth int blocklen;
89137da2899SCharles.Forsyth int alg;
89237da2899SCharles.Forsyth void (*keyinit)(OneWay*);
89337da2899SCharles.Forsyth };
89437da2899SCharles.Forsyth
89537da2899SCharles.Forsyth Encalg encrypttab[] =
89637da2899SCharles.Forsyth {
89737da2899SCharles.Forsyth { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */
89837da2899SCharles.Forsyth { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */
89937da2899SCharles.Forsyth { "des_56_cbc", 8, DESCBC, initDESkey, },
90037da2899SCharles.Forsyth { "des_56_ecb", 8, DESECB, initDESkey, },
90137da2899SCharles.Forsyth { "des_40_cbc", 8, DESCBC, initDESkey_40, },
90237da2899SCharles.Forsyth { "des_40_ecb", 8, DESECB, initDESkey_40, },
90337da2899SCharles.Forsyth { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
90437da2899SCharles.Forsyth { "rc4_256", 1, RC4, initRC4key, },
90537da2899SCharles.Forsyth { "rc4_128", 1, RC4, initRC4key_128, },
90637da2899SCharles.Forsyth { "rc4_40", 1, RC4, initRC4key_40, },
90737da2899SCharles.Forsyth { "ideacbc", 8, IDEACBC, initIDEAkey, },
90837da2899SCharles.Forsyth { "ideaecb", 8, IDEAECB, initIDEAkey, },
90937da2899SCharles.Forsyth { 0 }
91037da2899SCharles.Forsyth };
91137da2899SCharles.Forsyth
91237da2899SCharles.Forsyth static int
parseencryptalg(char * p,Dstate * s)91337da2899SCharles.Forsyth parseencryptalg(char *p, Dstate *s)
91437da2899SCharles.Forsyth {
91537da2899SCharles.Forsyth Encalg *ea;
91637da2899SCharles.Forsyth
91737da2899SCharles.Forsyth for(ea = encrypttab; ea->name; ea++){
91837da2899SCharles.Forsyth if(strcmp(p, ea->name) == 0){
91937da2899SCharles.Forsyth s->encryptalg = ea->alg;
92037da2899SCharles.Forsyth s->blocklen = ea->blocklen;
92137da2899SCharles.Forsyth (*ea->keyinit)(&s->in);
92237da2899SCharles.Forsyth (*ea->keyinit)(&s->out);
92337da2899SCharles.Forsyth s->state &= ~Sclear;
92437da2899SCharles.Forsyth s->state |= Sencrypting;
92537da2899SCharles.Forsyth return 0;
92637da2899SCharles.Forsyth }
92737da2899SCharles.Forsyth }
92837da2899SCharles.Forsyth return -1;
92937da2899SCharles.Forsyth }
93037da2899SCharles.Forsyth
93137da2899SCharles.Forsyth static void
alglistinit(void)93237da2899SCharles.Forsyth alglistinit(void)
93337da2899SCharles.Forsyth {
93437da2899SCharles.Forsyth Hashalg *h;
93537da2899SCharles.Forsyth Encalg *e;
93637da2899SCharles.Forsyth int n;
93737da2899SCharles.Forsyth
93837da2899SCharles.Forsyth n = 1;
93937da2899SCharles.Forsyth for(e = encrypttab; e->name != nil; e++)
94037da2899SCharles.Forsyth n += strlen(e->name) + 1;
94137da2899SCharles.Forsyth encalgs = malloc(n);
94237da2899SCharles.Forsyth if(encalgs == nil)
94337da2899SCharles.Forsyth panic("sslinit");
94437da2899SCharles.Forsyth n = 0;
94537da2899SCharles.Forsyth for(e = encrypttab; e->name != nil; e++){
94637da2899SCharles.Forsyth strcpy(encalgs+n, e->name);
94737da2899SCharles.Forsyth n += strlen(e->name);
94837da2899SCharles.Forsyth if(e[1].name == nil)
94937da2899SCharles.Forsyth break;
95037da2899SCharles.Forsyth encalgs[n++] = ' ';
95137da2899SCharles.Forsyth }
95237da2899SCharles.Forsyth encalgs[n] = 0;
95337da2899SCharles.Forsyth
95437da2899SCharles.Forsyth n = 1;
95537da2899SCharles.Forsyth for(h = hashtab; h->name != nil; h++)
95637da2899SCharles.Forsyth n += strlen(h->name) + 1;
95737da2899SCharles.Forsyth hashalgs = malloc(n);
95837da2899SCharles.Forsyth if(hashalgs == nil)
95937da2899SCharles.Forsyth panic("sslinit");
96037da2899SCharles.Forsyth n = 0;
96137da2899SCharles.Forsyth for(h = hashtab; h->name != nil; h++){
96237da2899SCharles.Forsyth strcpy(hashalgs+n, h->name);
96337da2899SCharles.Forsyth n += strlen(h->name);
96437da2899SCharles.Forsyth if(h[1].name == nil)
96537da2899SCharles.Forsyth break;
96637da2899SCharles.Forsyth hashalgs[n++] = ' ';
96737da2899SCharles.Forsyth }
96837da2899SCharles.Forsyth hashalgs[n] = 0;
96937da2899SCharles.Forsyth }
97037da2899SCharles.Forsyth
97137da2899SCharles.Forsyth static long
sslwrite(Chan * c,void * a,long n,vlong offset)97237da2899SCharles.Forsyth sslwrite(Chan *c, void *a, long n, vlong offset)
97337da2899SCharles.Forsyth {
97437da2899SCharles.Forsyth volatile struct { Dstate *s; } s;
97537da2899SCharles.Forsyth volatile struct { Block *b; } b;
97637da2899SCharles.Forsyth int m, t;
97737da2899SCharles.Forsyth char *p, *np, *e, buf[32];
97837da2899SCharles.Forsyth uchar *x;
97937da2899SCharles.Forsyth
98037da2899SCharles.Forsyth s.s = dstate[CONV(c->qid)];
98137da2899SCharles.Forsyth if(s.s == 0)
98237da2899SCharles.Forsyth panic("sslwrite");
98337da2899SCharles.Forsyth
98437da2899SCharles.Forsyth t = TYPE(c->qid);
98537da2899SCharles.Forsyth if(t == Qdata){
98637da2899SCharles.Forsyth if(s.s->state == Sincomplete)
98737da2899SCharles.Forsyth error(Ebadusefd);
98837da2899SCharles.Forsyth
98937da2899SCharles.Forsyth p = a;
99037da2899SCharles.Forsyth e = p + n;
99137da2899SCharles.Forsyth do {
99237da2899SCharles.Forsyth m = e - p;
99337da2899SCharles.Forsyth if(m > s.s->max)
99437da2899SCharles.Forsyth m = s.s->max;
99537da2899SCharles.Forsyth
99637da2899SCharles.Forsyth b.b = allocb(m);
99737da2899SCharles.Forsyth memmove(b.b->wp, p, m);
99837da2899SCharles.Forsyth b.b->wp += m;
99937da2899SCharles.Forsyth
100037da2899SCharles.Forsyth sslbwrite(c, b.b, offset);
100137da2899SCharles.Forsyth
100237da2899SCharles.Forsyth p += m;
100337da2899SCharles.Forsyth } while(p < e);
100437da2899SCharles.Forsyth return n;
100537da2899SCharles.Forsyth }
100637da2899SCharles.Forsyth
100737da2899SCharles.Forsyth /* mutex with operations using what we're about to change */
100837da2899SCharles.Forsyth if(waserror()){
100937da2899SCharles.Forsyth qunlock(&s.s->in.ctlq);
101037da2899SCharles.Forsyth qunlock(&s.s->out.q);
101137da2899SCharles.Forsyth nexterror();
101237da2899SCharles.Forsyth }
101337da2899SCharles.Forsyth qlock(&s.s->in.ctlq);
101437da2899SCharles.Forsyth qlock(&s.s->out.q);
101537da2899SCharles.Forsyth
101637da2899SCharles.Forsyth switch(t){
101737da2899SCharles.Forsyth default:
101837da2899SCharles.Forsyth panic("sslwrite");
101937da2899SCharles.Forsyth case Qsecretin:
102037da2899SCharles.Forsyth setsecret(&s.s->in, a, n);
102137da2899SCharles.Forsyth goto out;
102237da2899SCharles.Forsyth case Qsecretout:
102337da2899SCharles.Forsyth setsecret(&s.s->out, a, n);
102437da2899SCharles.Forsyth goto out;
102537da2899SCharles.Forsyth case Qctl:
102637da2899SCharles.Forsyth break;
102737da2899SCharles.Forsyth }
102837da2899SCharles.Forsyth
102937da2899SCharles.Forsyth if(n >= sizeof(buf))
103037da2899SCharles.Forsyth error(Ebadarg);
103137da2899SCharles.Forsyth strncpy(buf, a, n);
103237da2899SCharles.Forsyth buf[n] = 0;
103337da2899SCharles.Forsyth p = strchr(buf, '\n');
103437da2899SCharles.Forsyth if(p)
103537da2899SCharles.Forsyth *p = 0;
103637da2899SCharles.Forsyth p = strchr(buf, ' ');
103737da2899SCharles.Forsyth if(p)
103837da2899SCharles.Forsyth *p++ = 0;
103937da2899SCharles.Forsyth
104037da2899SCharles.Forsyth if(strcmp(buf, "fd") == 0){
104137da2899SCharles.Forsyth s.s->c = buftochan(p);
104237da2899SCharles.Forsyth
104337da2899SCharles.Forsyth /* default is clear (msg delimiters only) */
104437da2899SCharles.Forsyth s.s->state = Sclear;
104537da2899SCharles.Forsyth s.s->blocklen = 1;
104637da2899SCharles.Forsyth s.s->diglen = 0;
104737da2899SCharles.Forsyth s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
104837da2899SCharles.Forsyth s.s->in.mid = 0;
104937da2899SCharles.Forsyth s.s->out.mid = 0;
105037da2899SCharles.Forsyth } else if(strcmp(buf, "alg") == 0 && p != 0){
105137da2899SCharles.Forsyth s.s->blocklen = 1;
105237da2899SCharles.Forsyth s.s->diglen = 0;
105337da2899SCharles.Forsyth
105437da2899SCharles.Forsyth if(s.s->c == 0)
105537da2899SCharles.Forsyth error("must set fd before algorithm");
105637da2899SCharles.Forsyth
105737da2899SCharles.Forsyth if(strcmp(p, "clear") == 0){
105837da2899SCharles.Forsyth s.s->state = Sclear;
105937da2899SCharles.Forsyth s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
106037da2899SCharles.Forsyth goto out;
106137da2899SCharles.Forsyth }
106237da2899SCharles.Forsyth
106337da2899SCharles.Forsyth if(s.s->in.secret && s.s->out.secret == 0)
106437da2899SCharles.Forsyth setsecret(&s.s->out, s.s->in.secret, s.s->in.slen);
106537da2899SCharles.Forsyth if(s.s->out.secret && s.s->in.secret == 0)
106637da2899SCharles.Forsyth setsecret(&s.s->in, s.s->out.secret, s.s->out.slen);
106737da2899SCharles.Forsyth if(s.s->in.secret == 0 || s.s->out.secret == 0)
106837da2899SCharles.Forsyth error("algorithm but no secret");
106937da2899SCharles.Forsyth
107037da2899SCharles.Forsyth s.s->hf = 0;
107137da2899SCharles.Forsyth s.s->encryptalg = Noencryption;
107237da2899SCharles.Forsyth s.s->blocklen = 1;
107337da2899SCharles.Forsyth
107437da2899SCharles.Forsyth for(;;){
107537da2899SCharles.Forsyth np = strchr(p, ' ');
107637da2899SCharles.Forsyth if(np)
107737da2899SCharles.Forsyth *np++ = 0;
107837da2899SCharles.Forsyth else{
107937da2899SCharles.Forsyth np = strchr(p, '/');
108037da2899SCharles.Forsyth if(np)
108137da2899SCharles.Forsyth *np++ = 0;
108237da2899SCharles.Forsyth }
108337da2899SCharles.Forsyth if(parsehashalg(p, s.s) < 0)
108437da2899SCharles.Forsyth if(parseencryptalg(p, s.s) < 0)
108537da2899SCharles.Forsyth error(Ebadarg);
108637da2899SCharles.Forsyth
108737da2899SCharles.Forsyth if(np == 0)
108837da2899SCharles.Forsyth break;
108937da2899SCharles.Forsyth p = np;
109037da2899SCharles.Forsyth }
109137da2899SCharles.Forsyth
109237da2899SCharles.Forsyth if(s.s->hf == 0 && s.s->encryptalg == Noencryption)
109337da2899SCharles.Forsyth error(Ebadarg);
109437da2899SCharles.Forsyth
109537da2899SCharles.Forsyth if(s.s->blocklen != 1){
109637da2899SCharles.Forsyth /* make multiple of blocklen */
109737da2899SCharles.Forsyth s.s->max = (1<<15) - s.s->diglen - 1;
109837da2899SCharles.Forsyth s.s->max -= s.s->max % s.s->blocklen;
109937da2899SCharles.Forsyth s.s->maxpad = (1<<14) - s.s->diglen - 1;
110037da2899SCharles.Forsyth s.s->maxpad -= s.s->maxpad % s.s->blocklen;
110137da2899SCharles.Forsyth } else
110237da2899SCharles.Forsyth s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1;
110337da2899SCharles.Forsyth } else if(strcmp(buf, "secretin") == 0 && p != 0) {
110437da2899SCharles.Forsyth m = (strlen(p)*3)/2;
110537da2899SCharles.Forsyth x = smalloc(m);
110637da2899SCharles.Forsyth if(waserror()){
110737da2899SCharles.Forsyth free(x);
110837da2899SCharles.Forsyth nexterror();
110937da2899SCharles.Forsyth }
111037da2899SCharles.Forsyth t = dec64(x, m, p, strlen(p));
111137da2899SCharles.Forsyth setsecret(&s.s->in, x, t);
111237da2899SCharles.Forsyth poperror();
111337da2899SCharles.Forsyth free(x);
111437da2899SCharles.Forsyth } else if(strcmp(buf, "secretout") == 0 && p != 0) {
111537da2899SCharles.Forsyth m = (strlen(p)*3)/2;
111637da2899SCharles.Forsyth x = smalloc(m);
111737da2899SCharles.Forsyth if(waserror()){
111837da2899SCharles.Forsyth free(x);
111937da2899SCharles.Forsyth nexterror();
112037da2899SCharles.Forsyth }
112137da2899SCharles.Forsyth t = dec64(x, m, p, strlen(p));
112237da2899SCharles.Forsyth setsecret(&s.s->out, x, t);
112337da2899SCharles.Forsyth poperror();
112437da2899SCharles.Forsyth free(x);
112537da2899SCharles.Forsyth } else
112637da2899SCharles.Forsyth error(Ebadarg);
112737da2899SCharles.Forsyth
112837da2899SCharles.Forsyth out:
112937da2899SCharles.Forsyth qunlock(&s.s->in.ctlq);
113037da2899SCharles.Forsyth qunlock(&s.s->out.q);
113137da2899SCharles.Forsyth poperror();
113237da2899SCharles.Forsyth return n;
113337da2899SCharles.Forsyth }
113437da2899SCharles.Forsyth
113537da2899SCharles.Forsyth
113637da2899SCharles.Forsyth static Block*
encryptb(Dstate * s,Block * b,int offset)113737da2899SCharles.Forsyth encryptb(Dstate *s, Block *b, int offset)
113837da2899SCharles.Forsyth {
113937da2899SCharles.Forsyth uchar *p, *ep, *p2, *ip, *eip;
114037da2899SCharles.Forsyth DESstate *ds;
114137da2899SCharles.Forsyth IDEAstate *is;
114237da2899SCharles.Forsyth
114337da2899SCharles.Forsyth switch(s->encryptalg){
114437da2899SCharles.Forsyth case DESECB:
114537da2899SCharles.Forsyth ds = s->out.state;
114637da2899SCharles.Forsyth ep = b->rp + BLEN(b);
114737da2899SCharles.Forsyth for(p = b->rp + offset; p < ep; p += 8)
114837da2899SCharles.Forsyth block_cipher(ds->expanded, p, 0);
114937da2899SCharles.Forsyth break;
115037da2899SCharles.Forsyth case DESCBC:
115137da2899SCharles.Forsyth ds = s->out.state;
115237da2899SCharles.Forsyth ep = b->rp + BLEN(b);
115337da2899SCharles.Forsyth for(p = b->rp + offset; p < ep; p += 8){
115437da2899SCharles.Forsyth p2 = p;
115537da2899SCharles.Forsyth ip = ds->ivec;
115637da2899SCharles.Forsyth for(eip = ip+8; ip < eip; )
115737da2899SCharles.Forsyth *p2++ ^= *ip++;
115837da2899SCharles.Forsyth block_cipher(ds->expanded, p, 0);
115937da2899SCharles.Forsyth memmove(ds->ivec, p, 8);
116037da2899SCharles.Forsyth }
116137da2899SCharles.Forsyth break;
116237da2899SCharles.Forsyth case IDEAECB:
116337da2899SCharles.Forsyth is = s->out.state;
116437da2899SCharles.Forsyth ep = b->rp + BLEN(b);
116537da2899SCharles.Forsyth for(p = b->rp + offset; p < ep; p += 8)
116637da2899SCharles.Forsyth idea_cipher(is->edkey, p, 0);
116737da2899SCharles.Forsyth break;
116837da2899SCharles.Forsyth case IDEACBC:
116937da2899SCharles.Forsyth is = s->out.state;
117037da2899SCharles.Forsyth ep = b->rp + BLEN(b);
117137da2899SCharles.Forsyth for(p = b->rp + offset; p < ep; p += 8){
117237da2899SCharles.Forsyth p2 = p;
117337da2899SCharles.Forsyth ip = is->ivec;
117437da2899SCharles.Forsyth for(eip = ip+8; ip < eip; )
117537da2899SCharles.Forsyth *p2++ ^= *ip++;
117637da2899SCharles.Forsyth idea_cipher(is->edkey, p, 0);
117737da2899SCharles.Forsyth memmove(is->ivec, p, 8);
117837da2899SCharles.Forsyth }
117937da2899SCharles.Forsyth break;
118037da2899SCharles.Forsyth case RC4:
118137da2899SCharles.Forsyth rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
118237da2899SCharles.Forsyth break;
118337da2899SCharles.Forsyth }
118437da2899SCharles.Forsyth return b;
118537da2899SCharles.Forsyth }
118637da2899SCharles.Forsyth
118737da2899SCharles.Forsyth static Block*
decryptb(Dstate * s,Block * inb)118837da2899SCharles.Forsyth decryptb(Dstate *s, Block *inb)
118937da2899SCharles.Forsyth {
119037da2899SCharles.Forsyth Block *b, **l;
119137da2899SCharles.Forsyth uchar *p, *ep, *tp, *ip, *eip;
119237da2899SCharles.Forsyth DESstate *ds;
119337da2899SCharles.Forsyth IDEAstate *is;
119437da2899SCharles.Forsyth uchar tmp[8];
119537da2899SCharles.Forsyth int i;
119637da2899SCharles.Forsyth
119737da2899SCharles.Forsyth l = &inb;
119837da2899SCharles.Forsyth for(b = inb; b; b = b->next){
119937da2899SCharles.Forsyth /* make sure we have a multiple of s->blocklen */
120037da2899SCharles.Forsyth if(s->blocklen > 1){
120137da2899SCharles.Forsyth i = BLEN(b);
120237da2899SCharles.Forsyth if(i % s->blocklen){
120337da2899SCharles.Forsyth *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
120437da2899SCharles.Forsyth if(b == 0)
120537da2899SCharles.Forsyth error("ssl encrypted message too short");
120637da2899SCharles.Forsyth }
120737da2899SCharles.Forsyth }
120837da2899SCharles.Forsyth l = &b->next;
120937da2899SCharles.Forsyth
121037da2899SCharles.Forsyth /* decrypt */
121137da2899SCharles.Forsyth switch(s->encryptalg){
121237da2899SCharles.Forsyth case DESECB:
121337da2899SCharles.Forsyth ds = s->in.state;
121437da2899SCharles.Forsyth ep = b->rp + BLEN(b);
121537da2899SCharles.Forsyth for(p = b->rp; p < ep; p += 8)
121637da2899SCharles.Forsyth block_cipher(ds->expanded, p, 1);
121737da2899SCharles.Forsyth break;
121837da2899SCharles.Forsyth case DESCBC:
121937da2899SCharles.Forsyth ds = s->in.state;
122037da2899SCharles.Forsyth ep = b->rp + BLEN(b);
122137da2899SCharles.Forsyth for(p = b->rp; p < ep;){
122237da2899SCharles.Forsyth memmove(tmp, p, 8);
122337da2899SCharles.Forsyth block_cipher(ds->expanded, p, 1);
122437da2899SCharles.Forsyth tp = tmp;
122537da2899SCharles.Forsyth ip = ds->ivec;
122637da2899SCharles.Forsyth for(eip = ip+8; ip < eip; ){
122737da2899SCharles.Forsyth *p++ ^= *ip;
122837da2899SCharles.Forsyth *ip++ = *tp++;
122937da2899SCharles.Forsyth }
123037da2899SCharles.Forsyth }
123137da2899SCharles.Forsyth break;
123237da2899SCharles.Forsyth case IDEAECB:
123337da2899SCharles.Forsyth is = s->in.state;
123437da2899SCharles.Forsyth ep = b->rp + BLEN(b);
123537da2899SCharles.Forsyth for(p = b->rp; p < ep; p += 8)
123637da2899SCharles.Forsyth idea_cipher(is->edkey, p, 1);
123737da2899SCharles.Forsyth break;
123837da2899SCharles.Forsyth case IDEACBC:
123937da2899SCharles.Forsyth is = s->in.state;
124037da2899SCharles.Forsyth ep = b->rp + BLEN(b);
124137da2899SCharles.Forsyth for(p = b->rp; p < ep;){
124237da2899SCharles.Forsyth memmove(tmp, p, 8);
124337da2899SCharles.Forsyth idea_cipher(is->edkey, p, 1);
124437da2899SCharles.Forsyth tp = tmp;
124537da2899SCharles.Forsyth ip = is->ivec;
124637da2899SCharles.Forsyth for(eip = ip+8; ip < eip; ){
124737da2899SCharles.Forsyth *p++ ^= *ip;
124837da2899SCharles.Forsyth *ip++ = *tp++;
124937da2899SCharles.Forsyth }
125037da2899SCharles.Forsyth }
125137da2899SCharles.Forsyth break;
125237da2899SCharles.Forsyth case RC4:
125337da2899SCharles.Forsyth rc4(s->in.state, b->rp, BLEN(b));
125437da2899SCharles.Forsyth break;
125537da2899SCharles.Forsyth }
125637da2899SCharles.Forsyth }
125737da2899SCharles.Forsyth return inb;
125837da2899SCharles.Forsyth }
125937da2899SCharles.Forsyth
126037da2899SCharles.Forsyth static Block*
digestb(Dstate * s,Block * b,int offset)126137da2899SCharles.Forsyth digestb(Dstate *s, Block *b, int offset)
126237da2899SCharles.Forsyth {
126337da2899SCharles.Forsyth uchar *p;
126437da2899SCharles.Forsyth DigestState ss;
126537da2899SCharles.Forsyth uchar msgid[4];
126637da2899SCharles.Forsyth ulong n, h;
126737da2899SCharles.Forsyth OneWay *w;
126837da2899SCharles.Forsyth
126937da2899SCharles.Forsyth w = &s->out;
127037da2899SCharles.Forsyth
127137da2899SCharles.Forsyth memset(&ss, 0, sizeof(ss));
127237da2899SCharles.Forsyth h = s->diglen + offset;
127337da2899SCharles.Forsyth n = BLEN(b) - h;
127437da2899SCharles.Forsyth
127537da2899SCharles.Forsyth /* hash secret + message */
127637da2899SCharles.Forsyth (*s->hf)(w->secret, w->slen, 0, &ss);
127737da2899SCharles.Forsyth (*s->hf)(b->rp + h, n, 0, &ss);
127837da2899SCharles.Forsyth
127937da2899SCharles.Forsyth /* hash message id */
128037da2899SCharles.Forsyth p = msgid;
128137da2899SCharles.Forsyth n = w->mid;
128237da2899SCharles.Forsyth *p++ = n>>24;
128337da2899SCharles.Forsyth *p++ = n>>16;
128437da2899SCharles.Forsyth *p++ = n>>8;
128537da2899SCharles.Forsyth *p = n;
128637da2899SCharles.Forsyth (*s->hf)(msgid, 4, b->rp + offset, &ss);
128737da2899SCharles.Forsyth
128837da2899SCharles.Forsyth return b;
128937da2899SCharles.Forsyth }
129037da2899SCharles.Forsyth
129137da2899SCharles.Forsyth static void
checkdigestb(Dstate * s,Block * inb)129237da2899SCharles.Forsyth checkdigestb(Dstate *s, Block *inb)
129337da2899SCharles.Forsyth {
129437da2899SCharles.Forsyth uchar *p;
129537da2899SCharles.Forsyth DigestState ss;
129637da2899SCharles.Forsyth uchar msgid[4];
129737da2899SCharles.Forsyth int n, h;
129837da2899SCharles.Forsyth OneWay *w;
129937da2899SCharles.Forsyth uchar digest[128];
130037da2899SCharles.Forsyth Block *b;
130137da2899SCharles.Forsyth
130237da2899SCharles.Forsyth w = &s->in;
130337da2899SCharles.Forsyth
130437da2899SCharles.Forsyth memset(&ss, 0, sizeof(ss));
130537da2899SCharles.Forsyth
130637da2899SCharles.Forsyth /* hash secret */
130737da2899SCharles.Forsyth (*s->hf)(w->secret, w->slen, 0, &ss);
130837da2899SCharles.Forsyth
130937da2899SCharles.Forsyth /* hash message */
131037da2899SCharles.Forsyth h = s->diglen;
131137da2899SCharles.Forsyth for(b = inb; b; b = b->next){
131237da2899SCharles.Forsyth n = BLEN(b) - h;
131337da2899SCharles.Forsyth if(n < 0)
131437da2899SCharles.Forsyth panic("checkdigestb");
131537da2899SCharles.Forsyth (*s->hf)(b->rp + h, n, 0, &ss);
131637da2899SCharles.Forsyth h = 0;
131737da2899SCharles.Forsyth }
131837da2899SCharles.Forsyth
131937da2899SCharles.Forsyth /* hash message id */
132037da2899SCharles.Forsyth p = msgid;
132137da2899SCharles.Forsyth n = w->mid;
132237da2899SCharles.Forsyth *p++ = n>>24;
132337da2899SCharles.Forsyth *p++ = n>>16;
132437da2899SCharles.Forsyth *p++ = n>>8;
132537da2899SCharles.Forsyth *p = n;
132637da2899SCharles.Forsyth (*s->hf)(msgid, 4, digest, &ss);
132737da2899SCharles.Forsyth
132837da2899SCharles.Forsyth /* requires pullupblock */
132937da2899SCharles.Forsyth if(memcmp(digest, inb->rp, s->diglen) != 0)
133037da2899SCharles.Forsyth error("bad digest");
133137da2899SCharles.Forsyth }
133237da2899SCharles.Forsyth
133337da2899SCharles.Forsyth /* get channel associated with an fd */
133437da2899SCharles.Forsyth static Chan*
buftochan(char * p)133537da2899SCharles.Forsyth buftochan(char *p)
133637da2899SCharles.Forsyth {
133737da2899SCharles.Forsyth Chan *c;
133837da2899SCharles.Forsyth int fd;
133937da2899SCharles.Forsyth
134037da2899SCharles.Forsyth if(p == 0)
134137da2899SCharles.Forsyth error(Ebadarg);
134237da2899SCharles.Forsyth fd = strtoul(p, 0, 0);
134337da2899SCharles.Forsyth if(fd < 0)
134437da2899SCharles.Forsyth error(Ebadarg);
134537da2899SCharles.Forsyth c = fdtochan(up->env->fgrp, fd, -1, 0, 1); /* error check and inc ref */
134637da2899SCharles.Forsyth return c;
134737da2899SCharles.Forsyth }
134837da2899SCharles.Forsyth
134937da2899SCharles.Forsyth /* hang up a digest connection */
135037da2899SCharles.Forsyth static void
sslhangup(Dstate * s)135137da2899SCharles.Forsyth sslhangup(Dstate *s)
135237da2899SCharles.Forsyth {
135337da2899SCharles.Forsyth qlock(&s->in.q);
135437da2899SCharles.Forsyth freeblist(s->processed);
135537da2899SCharles.Forsyth s->processed = 0;
135637da2899SCharles.Forsyth freeblist(s->unprocessed);
135737da2899SCharles.Forsyth s->unprocessed = 0;
135837da2899SCharles.Forsyth s->state = Sincomplete;
135937da2899SCharles.Forsyth qunlock(&s->in.q);
136037da2899SCharles.Forsyth }
136137da2899SCharles.Forsyth
1362*ad01d857SCharles.Forsyth static void
dsclone(Chan * ch)136337da2899SCharles.Forsyth dsclone(Chan *ch)
136437da2899SCharles.Forsyth {
136537da2899SCharles.Forsyth Dstate **pp, **ep, **np;
136637da2899SCharles.Forsyth int newmax;
136737da2899SCharles.Forsyth
1368*ad01d857SCharles.Forsyth lock(&dslock);
136937da2899SCharles.Forsyth if(waserror()) {
137037da2899SCharles.Forsyth unlock(&dslock);
137137da2899SCharles.Forsyth nexterror();
137237da2899SCharles.Forsyth }
137337da2899SCharles.Forsyth ep = &dstate[maxdstate];
137437da2899SCharles.Forsyth for(pp = dstate; pp < ep; pp++) {
137537da2899SCharles.Forsyth if(*pp == 0) {
137637da2899SCharles.Forsyth dsnew(ch, pp);
137737da2899SCharles.Forsyth break;
137837da2899SCharles.Forsyth }
137937da2899SCharles.Forsyth }
138037da2899SCharles.Forsyth if(pp >= ep) {
1381*ad01d857SCharles.Forsyth if(maxdstate >= Maxdstate)
1382*ad01d857SCharles.Forsyth error(Enodev);
138337da2899SCharles.Forsyth newmax = 2 * maxdstate;
138437da2899SCharles.Forsyth if(newmax > Maxdstate)
138537da2899SCharles.Forsyth newmax = Maxdstate;
1386*ad01d857SCharles.Forsyth
138737da2899SCharles.Forsyth np = realloc(dstate, sizeof(Dstate*) * newmax);
138837da2899SCharles.Forsyth if(np == 0)
138937da2899SCharles.Forsyth error(Enomem);
139037da2899SCharles.Forsyth dstate = np;
139137da2899SCharles.Forsyth pp = &dstate[maxdstate];
139237da2899SCharles.Forsyth memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate));
1393*ad01d857SCharles.Forsyth
139437da2899SCharles.Forsyth maxdstate = newmax;
139537da2899SCharles.Forsyth dsnew(ch, pp);
139637da2899SCharles.Forsyth }
139737da2899SCharles.Forsyth poperror();
1398*ad01d857SCharles.Forsyth unlock(&dslock);
139937da2899SCharles.Forsyth }
140037da2899SCharles.Forsyth
140137da2899SCharles.Forsyth static void
dsnew(Chan * ch,Dstate ** pp)140237da2899SCharles.Forsyth dsnew(Chan *ch, Dstate **pp)
140337da2899SCharles.Forsyth {
140437da2899SCharles.Forsyth Dstate *s;
140537da2899SCharles.Forsyth int t;
140637da2899SCharles.Forsyth
1407*ad01d857SCharles.Forsyth *pp = s = mallocz(sizeof(*s), 1);
1408*ad01d857SCharles.Forsyth if(s == nil)
140937da2899SCharles.Forsyth error(Enomem);
141037da2899SCharles.Forsyth if(pp - dstate >= dshiwat)
141137da2899SCharles.Forsyth dshiwat++;
141237da2899SCharles.Forsyth s->state = Sincomplete;
141337da2899SCharles.Forsyth s->ref = 1;
141437da2899SCharles.Forsyth kstrdup(&s->user, up->env->user);
141537da2899SCharles.Forsyth s->perm = 0660;
141637da2899SCharles.Forsyth t = TYPE(ch->qid);
141737da2899SCharles.Forsyth if(t == Qclonus)
141837da2899SCharles.Forsyth t = Qctl;
141937da2899SCharles.Forsyth ch->qid.path = QID(pp - dstate, t);
142037da2899SCharles.Forsyth ch->qid.vers = 0;
142137da2899SCharles.Forsyth ch->qid.type = QTFILE;
142237da2899SCharles.Forsyth }
142337da2899SCharles.Forsyth
142437da2899SCharles.Forsyth Dev ssldevtab = {
142537da2899SCharles.Forsyth 'D',
142637da2899SCharles.Forsyth "ssl",
142737da2899SCharles.Forsyth
142837da2899SCharles.Forsyth sslinit,
142937da2899SCharles.Forsyth sslattach,
143037da2899SCharles.Forsyth sslwalk,
143137da2899SCharles.Forsyth sslstat,
143237da2899SCharles.Forsyth sslopen,
143337da2899SCharles.Forsyth devcreate,
143437da2899SCharles.Forsyth sslclose,
143537da2899SCharles.Forsyth sslread,
143637da2899SCharles.Forsyth sslbread,
143737da2899SCharles.Forsyth sslwrite,
143837da2899SCharles.Forsyth sslbwrite,
143937da2899SCharles.Forsyth devremove,
144037da2899SCharles.Forsyth sslwstat
144137da2899SCharles.Forsyth };
1442