1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441 |
- /*
- * devssl - secure sockets layer
- */
- #include "dat.h"
- #include "fns.h"
- #include "error.h"
- #include "mp.h"
- #include "libsec.h"
- typedef struct OneWay OneWay;
- struct OneWay
- {
- QLock q;
- QLock ctlq;
- void *state; /* encryption state */
- int slen; /* secret data length */
- uchar *secret; /* secret */
- ulong mid; /* message id */
- };
- enum
- {
- /* connection states */
- Sincomplete= 0,
- Sclear= 1,
- Sencrypting= 2,
- Sdigesting= 4,
- Sdigenc= Sencrypting|Sdigesting,
- /* encryption algorithms */
- Noencryption= 0,
- DESCBC= 1,
- DESECB= 2,
- RC4= 3,
- IDEACBC= 4,
- IDEAECB= 5
- };
- typedef struct Dstate Dstate;
- struct Dstate
- {
- Chan *c; /* io channel */
- uchar state; /* state of connection */
- int ref; /* serialized by dslock for atomic destroy */
- uchar encryptalg; /* encryption algorithm */
- ushort blocklen; /* blocking length */
- ushort diglen; /* length of digest */
- DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
- /* for SSL format */
- int max; /* maximum unpadded data per msg */
- int maxpad; /* maximum padded data per msg */
-
- /* input side */
- OneWay in;
- Block *processed;
- Block *unprocessed;
- /* output side */
- OneWay out;
- /* protections */
- char* user;
- int perm;
- };
- enum
- {
- Maxdmsg= 1<<16,
- Maxdstate= 1<<10,
- };
- Lock dslock;
- int dshiwat;
- int maxdstate = 20;
- Dstate** dstate;
- enum{
- Qtopdir = 1, /* top level directory */
- Qclonus,
- Qconvdir, /* directory for a conversation */
- Qdata,
- Qctl,
- Qsecretin,
- Qsecretout,
- Qencalgs,
- Qhashalgs
- };
- #define TYPE(x) ((ulong)(x).path & 0xf)
- #define CONV(x) (((ulong)(x).path >> 4)&(Maxdstate-1))
- #define QID(c, y) (((c)<<4) | (y))
- static char* encalgs;
- static char* hashalgs;
- void producerand(void);
- static void alglistinit(void);
- static void ensure(Dstate*, Block**, int);
- static void consume(Block**, uchar*, int);
- static void setsecret(OneWay*, uchar*, int);
- static Block* encryptb(Dstate*, Block*, int);
- static Block* decryptb(Dstate*, Block*);
- static Block* digestb(Dstate*, Block*, int);
- static void checkdigestb(Dstate*, Block*);
- static Chan* buftochan(char*);
- static void sslhangup(Dstate*);
- static void dsclone(Chan *c);
- static void dsnew(Chan *c, Dstate **);
- static int
- sslgen(Chan *c, char *dname, Dirtab *d, int nd, int s, Dir *dp)
- {
- Qid q;
- Dstate *ds;
- char *p, *nm;
- USED(dname);
- USED(nd);
- USED(d);
- q.type = QTFILE;
- q.vers = 0;
- if(s == DEVDOTDOT){
- q.path = QID(0, Qtopdir);
- q.type = QTDIR;
- devdir(c, q, "#D", 0, eve, 0555, dp);
- return 1;
- }
- switch(TYPE(c->qid)) {
- case Qtopdir:
- if(s < dshiwat) {
- q.path = QID(s, Qconvdir);
- q.type = QTDIR;
- ds = dstate[s];
- if(ds != 0)
- nm = ds->user;
- else
- nm = eve;
- snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
- devdir(c, q, up->genbuf, 0, nm, DMDIR|0555, dp);
- return 1;
- }
- if(s > dshiwat)
- return -1;
- /* fall through */
- case Qclonus:
- q.path = QID(0, Qclonus);
- devdir(c, q, "clone", 0, eve, 0666, 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;
- case 4:
- q.path = QID(CONV(c->qid), Qencalgs);
- p = "encalgs";
- break;
- case 5:
- q.path = QID(CONV(c->qid), Qhashalgs);
- p = "hashalgs";
- break;
- }
- devdir(c, q, p, 0, nm, 0660, dp);
- return 1;
- }
- return -1;
- }
- static void
- sslinit(void)
- {
- if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0)
- panic("sslinit");
- alglistinit();
- }
- static Chan *
- sslattach(char *spec)
- {
- Chan *c;
- c = devattach('D', spec);
- c->qid.path = QID(0, Qtopdir);
- c->qid.vers = 0;
- c->qid.type = QTDIR;
- return c;
- }
- static Walkqid*
- sslwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, 0, 0, sslgen);
- }
- static int
- sslstat(Chan *c, uchar *db, int n)
- {
- return devstat(c, db, n, 0, 0, sslgen);
- }
- static Chan*
- sslopen(Chan *c, int omode)
- {
- Dstate *s, **pp;
- int perm;
- perm = 0;
- omode &= 3;
- switch(omode) {
- case OREAD:
- perm = 4;
- break;
- case OWRITE:
- perm = 2;
- break;
- case ORDWR:
- perm = 6;
- break;
- }
- switch(TYPE(c->qid)) {
- default:
- panic("sslopen");
- case Qtopdir:
- case Qconvdir:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qclonus:
- dsclone(c);
- 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->env->user, s->user) != 0
- || (perm & s->perm) != perm))
- error(Eperm);
- s->ref++;
- }
- unlock(&dslock);
- poperror();
- break;
- case Qencalgs:
- case Qhashalgs:
- if(omode != OREAD)
- error(Eperm);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- static int
- sslwstat(Chan *c, uchar *db, int n)
- {
- Dir *dir;
- Dstate *s;
- int m;
- s = dstate[CONV(c->qid)];
- if(s == 0)
- error(Ebadusefd);
- if(strcmp(s->user, up->env->user) != 0)
- error(Eperm);
- dir = smalloc(sizeof(Dir)+n);
- m = convM2D(db, n, &dir[0], (char*)&dir[1]);
- if(m == 0){
- free(dir);
- error(Eshortstat);
- }
- if(!emptystr(dir->uid))
- kstrdup(&s->user, dir->uid);
- if(dir->mode != ~0UL)
- s->perm = dir->mode;
- free(dir);
- return m;
- }
- static void
- sslclose(Chan *c)
- {
- Dstate *s;
- 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);
- if(s->c)
- cclose(s->c);
- free(s->user);
- free(s->in.secret);
- free(s->out.secret);
- free(s->in.state);
- free(s->out.state);
- free(s);
- }
- }
- /*
- * 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);
- }
- }
- /*
- * remove at most n bytes from the queue, if discard is set
- * dump the remainder
- */
- static Block*
- qtake(Block **l, int n, int discard)
- {
- Block *nb, *b, *first;
- int i;
- first = *l;
- for(b = first; b; b = b->next){
- i = BLEN(b);
- if(i == n){
- if(discard){
- freeblist(b->next);
- *l = 0;
- } else
- *l = b->next;
- b->next = 0;
- return first;
- } else if(i > n){
- i -= n;
- if(discard){
- freeblist(b->next);
- *l = 0;
- } else {
- nb = allocb(i);
- memmove(nb->wp, b->rp+n, i);
- nb->wp += i;
- nb->next = b->next;
- *l = nb;
- }
- b->wp -= i;
- b->next = 0;
- if(BLEN(b) < 0)
- panic("qtake");
- return first;
- } else
- n -= i;
- if(BLEN(b) < 0)
- panic("qtake");
- }
- *l = 0;
- return first;
- }
- static Block*
- sslbread(Chan *c, long n, ulong offset)
- {
- volatile struct { Dstate *s; } s;
- volatile struct { int nc; } nc;
- Block *b;
- uchar count[3];
- int len, pad;
- USED(offset);
- s.s = dstate[CONV(c->qid)];
- if(s.s == 0)
- panic("sslbread");
- if(s.s->state == Sincomplete)
- error(Ebadusefd);
- nc.nc = 0;
- if(waserror()){
- qunlock(&s.s->in.q);
- if(strcmp(up->env->errstr, "interrupted") == 0){
- if(nc.nc > 0){
- b = allocb(nc.nc);
- memmove(b->wp, count, nc.nc);
- b->wp += nc.nc;
- b->next = s.s->unprocessed;
- s.s->unprocessed = b;
- }
- } else
- sslhangup(s.s);
- nexterror();
- }
- qlock(&s.s->in.q);
- if(s.s->processed == 0){
- /* read in the whole message */
- ensure(s.s, &s.s->unprocessed, 2);
- consume(&s.s->unprocessed, count, 2);
- nc.nc += 2;
- if(count[0] & 0x80){
- len = ((count[0] & 0x7f)<<8) | count[1];
- ensure(s.s, &s.s->unprocessed, len);
- pad = 0;
- } else {
- len = ((count[0] & 0x3f)<<8) | count[1];
- ensure(s.s, &s.s->unprocessed, len+1);
- consume(&s.s->unprocessed, count + nc.nc, 1);
- pad = count[nc.nc];
- nc.nc++;
- if(pad > len){
- print("pad %d buf len %d\n", pad, len);
- error("bad pad in ssl message");
- }
- }
- nc.nc = 0;
- /* put extra on unprocessed queue */
- s.s->processed = qtake(&s.s->unprocessed, len, 0);
- if(waserror()){
- qunlock(&s.s->in.ctlq);
- nexterror();
- }
- 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;
- 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;
- len -= s.s->diglen;
- break;
- }
- s.s->in.mid++;
- qunlock(&s.s->in.ctlq);
- poperror();
- /* remove pad */
- if(pad)
- s.s->processed = qtake(&s.s->processed, len - pad, 1);
- }
- /* return at most what was asked for */
- b = qtake(&s.s->processed, n, 0);
- qunlock(&s.s->in.q);
- poperror();
- return b;
- }
- static long
- sslread(Chan *c, void *a, long n, vlong offset)
- {
- volatile struct { Block *b; } b;
- Block *nb;
- uchar *va;
- int i;
- char buf[128];
- if(c->qid.type & QTDIR)
- return devdirread(c, a, n, 0, 0, sslgen);
- switch(TYPE(c->qid)) {
- default:
- error(Ebadusefd);
- case Qctl:
- sprint(buf, "%ld", CONV(c->qid));
- return readstr(offset, a, n, buf);
- case Qdata:
- b.b = sslbread(c, n, offset);
- break;
- case Qencalgs:
- return readstr(offset, a, n, encalgs);
- case Qhashalgs:
- return readstr(offset, a, n, hashalgs);
- }
- n = 0;
- va = a;
- for(nb = b.b; nb; nb = nb->next){
- i = BLEN(nb);
- memmove(va+n, nb->rp, i);
- n += i;
- }
- freeblist(b.b);
- return n;
- }
- /*
- * 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)
- {
- while(len-- > 0)
- *buf++ = nrand(256);
- }
- /*
- * use SSL record format, add in count and digest or encrypt
- */
- static long
- sslbwrite(Chan *c, Block *b, ulong offset)
- {
- volatile struct { Dstate *s; } s;
- volatile struct { Block *b; } bb;
- Block *nb;
- int h, n, m, pad, rv;
- uchar *p;
- bb.b = b;
- s.s = dstate[CONV(c->qid)];
- if(s.s == 0)
- panic("sslbwrite");
- if(s.s->state == Sincomplete){
- freeb(b);
- error(Ebadusefd);
- }
- if(waserror()){
- qunlock(&s.s->out.q);
- if(bb.b)
- freeb(bb.b);
- sslhangup(s.s);
- nexterror();
- }
- qlock(&s.s->out.q);
- rv = 0;
- while(bb.b){
- m = n = BLEN(bb.b);
- h = s.s->diglen + 2;
- /* trim to maximum block size */
- pad = 0;
- if(m > s.s->max){
- m = s.s->max;
- } else if(s.s->blocklen != 1){
- pad = (m + s.s->diglen)%s.s->blocklen;
- if(pad){
- if(m > s.s->maxpad){
- pad = 0;
- m = s.s->maxpad;
- } else {
- pad = s.s->blocklen - pad;
- h++;
- }
- }
- }
- rv += m;
- if(m != n){
- nb = allocb(m + h + pad);
- memmove(nb->wp + h, bb.b->rp, m);
- nb->wp += m + h;
- bb.b->rp += m;
- } else {
- /* add header space */
- nb = padblock(bb.b, h);
- bb.b = 0;
- }
- m += s.s->diglen;
- /* SSLv2 style count */
- if(pad){
- nb = padblock(nb, -pad);
- randfill(nb->wp, pad);
- nb->wp += pad;
- m += pad;
- p = nb->rp;
- p[0] = (m>>8);
- p[1] = m;
- p[2] = pad;
- offset = 3;
- } else {
- p = nb->rp;
- p[0] = (m>>8) | 0x80;
- p[1] = m;
- offset = 2;
- }
- switch(s.s->state){
- case Sencrypting:
- nb = encryptb(s.s, nb, offset);
- break;
- case Sdigesting:
- nb = digestb(s.s, nb, offset);
- break;
- case Sdigenc:
- nb = digestb(s.s, nb, offset);
- nb = encryptb(s.s, nb, offset);
- break;
- }
- s.s->out.mid++;
- m = BLEN(nb);
- devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset);
- s.s->c->offset += m;
- }
- qunlock(&s.s->out.q);
- poperror();
- return rv;
- }
- static void
- setsecret(OneWay *w, uchar *secret, int n)
- {
- free(w->secret);
- w->secret = mallocz(n, 0);
- if(w->secret == nil)
- error(Enomem);
- memmove(w->secret, secret, n);
- w->slen = n;
- }
- static void
- initIDEAkey(OneWay *w)
- {
- free(w->state);
- w->state = malloc(sizeof(IDEAstate));
- if(w->state == nil)
- error(Enomem);
- if(w->slen >= 24)
- setupIDEAstate(w->state, w->secret, w->secret+16);
- else if(w->slen >= 16)
- setupIDEAstate(w->state, w->secret, 0);
- else
- error("secret too short");
- }
- static void
- initDESkey(OneWay *w)
- {
- free(w->state);
- w->state = malloc(sizeof(DESstate));
- if (!w->state)
- error(Enomem);
- 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");
- }
- /*
- * 40 bit DES is the same as 56 bit DES. However,
- * 16 bits of the key are masked to zero.
- */
- static void
- initDESkey_40(OneWay *w)
- {
- uchar key[8];
- if(w->slen >= 8) {
- memmove(key, w->secret, 8);
- key[0] &= 0x0f;
- key[2] &= 0x0f;
- key[4] &= 0x0f;
- key[6] &= 0x0f;
- }
- free(w->state);
- w->state = malloc(sizeof(DESstate));
- if (!w->state)
- error(Enomem);
- if(w->slen >= 16)
- setupDESstate(w->state, key, w->secret+8);
- else if(w->slen >= 8)
- setupDESstate(w->state, key, 0);
- else
- error("secret too short");
- }
- static void
- initRC4key(OneWay *w)
- {
- free(w->state);
- w->state = malloc(sizeof(RC4state));
- if (!w->state)
- error(Enomem);
- setupRC4state(w->state, w->secret, w->slen);
- }
- /*
- * 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)
- {
- int slen = w->slen;
- if(slen > 5)
- slen = 5;
- free(w->state);
- w->state = malloc(sizeof(RC4state));
- if (!w->state)
- error(Enomem);
- setupRC4state(w->state, w->secret, slen);
- }
- /*
- * 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)
- {
- int slen = w->slen;
- if(slen > 16)
- slen = 16;
- free(w->state);
- w->state = malloc(sizeof(RC4state));
- if (!w->state)
- error(Enomem);
- setupRC4state(w->state, w->secret, slen);
- }
- typedef struct Hashalg Hashalg;
- struct Hashalg
- {
- char *name;
- int diglen;
- DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
- };
- Hashalg hashtab[] =
- {
- { "md4", MD4dlen, md4, },
- { "md5", MD5dlen, md5, },
- { "sha1", SHA1dlen, sha1, },
- { "sha", SHA1dlen, sha1, },
- { 0 }
- };
- static int
- parsehashalg(char *p, Dstate *s)
- {
- 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;
- }
- typedef struct Encalg Encalg;
- struct Encalg
- {
- char *name;
- int blocklen;
- int alg;
- void (*keyinit)(OneWay*);
- };
- Encalg encrypttab[] =
- {
- { "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, },
- { "rc4_40", 1, RC4, initRC4key_40, },
- { "ideacbc", 8, IDEACBC, initIDEAkey, },
- { "ideaecb", 8, IDEAECB, initIDEAkey, },
- { 0 }
- };
- static int
- parseencryptalg(char *p, Dstate *s)
- {
- 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;
- }
- static void
- alglistinit(void)
- {
- Hashalg *h;
- Encalg *e;
- int n;
- n = 1;
- for(e = encrypttab; e->name != nil; e++)
- n += strlen(e->name) + 1;
- encalgs = malloc(n);
- if(encalgs == nil)
- panic("sslinit");
- n = 0;
- for(e = encrypttab; e->name != nil; e++){
- strcpy(encalgs+n, e->name);
- n += strlen(e->name);
- if(e[1].name == nil)
- break;
- encalgs[n++] = ' ';
- }
- encalgs[n] = 0;
- n = 1;
- for(h = hashtab; h->name != nil; h++)
- n += strlen(h->name) + 1;
- hashalgs = malloc(n);
- if(hashalgs == nil)
- panic("sslinit");
- n = 0;
- for(h = hashtab; h->name != nil; h++){
- strcpy(hashalgs+n, h->name);
- n += strlen(h->name);
- if(h[1].name == nil)
- break;
- hashalgs[n++] = ' ';
- }
- hashalgs[n] = 0;
- }
- static long
- sslwrite(Chan *c, void *a, long n, vlong offset)
- {
- volatile struct { Dstate *s; } s;
- volatile struct { Block *b; } b;
- int m, t;
- char *p, *np, *e, buf[32];
- uchar *x;
- s.s = dstate[CONV(c->qid)];
- if(s.s == 0)
- panic("sslwrite");
- t = TYPE(c->qid);
- if(t == Qdata){
- if(s.s->state == Sincomplete)
- error(Ebadusefd);
-
- p = a;
- e = p + n;
- do {
- m = e - p;
- if(m > s.s->max)
- m = s.s->max;
-
- b.b = allocb(m);
- memmove(b.b->wp, p, m);
- b.b->wp += m;
- sslbwrite(c, b.b, offset);
- 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){
- default:
- panic("sslwrite");
- case Qsecretin:
- setsecret(&s.s->in, a, n);
- goto out;
- case Qsecretout:
- setsecret(&s.s->out, a, n);
- goto out;
- case Qctl:
- break;
- }
- 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;
- if(strcmp(buf, "fd") == 0){
- s.s->c = buftochan(p);
- /* 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;
- s.s->in.mid = 0;
- s.s->out.mid = 0;
- } else if(strcmp(buf, "alg") == 0 && p != 0){
- s.s->blocklen = 1;
- s.s->diglen = 0;
- 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;
- }
- 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(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;
- else{
- np = strchr(p, '/');
- if(np)
- *np++ = 0;
- }
- if(parsehashalg(p, s.s) < 0)
- if(parseencryptalg(p, s.s) < 0)
- error(Ebadarg);
- if(np == 0)
- break;
- p = np;
- }
- if(s.s->hf == 0 && s.s->encryptalg == Noencryption)
- error(Ebadarg);
- if(s.s->blocklen != 1){
- /* make multiple of blocklen */
- 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 if(strcmp(buf, "secretin") == 0 && p != 0) {
- m = (strlen(p)*3)/2;
- x = smalloc(m);
- if(waserror()){
- free(x);
- nexterror();
- }
- t = dec64(x, m, p, strlen(p));
- setsecret(&s.s->in, x, t);
- poperror();
- free(x);
- } else if(strcmp(buf, "secretout") == 0 && p != 0) {
- m = (strlen(p)*3)/2;
- x = smalloc(m);
- if(waserror()){
- free(x);
- nexterror();
- }
- t = dec64(x, m, p, strlen(p));
- setsecret(&s.s->out, x, t);
- poperror();
- free(x);
- } else
- error(Ebadarg);
- out:
- qunlock(&s.s->in.ctlq);
- qunlock(&s.s->out.q);
- poperror();
- return n;
- }
- static Block*
- encryptb(Dstate *s, Block *b, int offset)
- {
- uchar *p, *ep, *p2, *ip, *eip;
- DESstate *ds;
- IDEAstate *is;
- switch(s->encryptalg){
- case DESECB:
- 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){
- p2 = p;
- ip = ds->ivec;
- for(eip = ip+8; ip < eip; )
- *p2++ ^= *ip++;
- block_cipher(ds->expanded, p, 0);
- memmove(ds->ivec, p, 8);
- }
- break;
- case IDEAECB:
- is = s->out.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp + offset; p < ep; p += 8)
- idea_cipher(is->edkey, p, 0);
- break;
- case IDEACBC:
- is = s->out.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp + offset; p < ep; p += 8){
- p2 = p;
- ip = is->ivec;
- for(eip = ip+8; ip < eip; )
- *p2++ ^= *ip++;
- idea_cipher(is->edkey, p, 0);
- memmove(is->ivec, p, 8);
- }
- break;
- case RC4:
- rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
- break;
- }
- return b;
- }
- static Block*
- decryptb(Dstate *s, Block *inb)
- {
- Block *b, **l;
- uchar *p, *ep, *tp, *ip, *eip;
- DESstate *ds;
- IDEAstate *is;
- uchar tmp[8];
- int i;
- 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");
- }
- }
- l = &b->next;
- /* decrypt */
- switch(s->encryptalg){
- case DESECB:
- ds = s->in.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp; 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; 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;
- case IDEAECB:
- is = s->in.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp; p < ep; p += 8)
- idea_cipher(is->edkey, p, 1);
- break;
- case IDEACBC:
- is = s->in.state;
- ep = b->rp + BLEN(b);
- for(p = b->rp; p < ep;){
- memmove(tmp, p, 8);
- idea_cipher(is->edkey, p, 1);
- tp = tmp;
- ip = is->ivec;
- for(eip = ip+8; ip < eip; ){
- *p++ ^= *ip;
- *ip++ = *tp++;
- }
- }
- break;
- case RC4:
- rc4(s->in.state, b->rp, BLEN(b));
- break;
- }
- }
- return inb;
- }
- static Block*
- digestb(Dstate *s, Block *b, int offset)
- {
- uchar *p;
- DigestState ss;
- uchar msgid[4];
- ulong n, h;
- OneWay *w;
- w = &s->out;
- memset(&ss, 0, sizeof(ss));
- h = s->diglen + offset;
- n = BLEN(b) - h;
- /* hash secret + message */
- (*s->hf)(w->secret, w->slen, 0, &ss);
- (*s->hf)(b->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->hf)(msgid, 4, b->rp + offset, &ss);
- return b;
- }
- static void
- checkdigestb(Dstate *s, Block *inb)
- {
- uchar *p;
- DigestState ss;
- uchar msgid[4];
- int n, h;
- OneWay *w;
- uchar digest[128];
- Block *b;
- w = &s->in;
- memset(&ss, 0, sizeof(ss));
- /* hash secret */
- (*s->hf)(w->secret, w->slen, 0, &ss);
- /* 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;
- }
- /* hash message id */
- p = msgid;
- n = w->mid;
- *p++ = n>>24;
- *p++ = n>>16;
- *p++ = n>>8;
- *p = n;
- (*s->hf)(msgid, 4, digest, &ss);
- /* requires pullupblock */
- if(memcmp(digest, inb->rp, s->diglen) != 0)
- error("bad digest");
- }
- /* get channel associated with an fd */
- static Chan*
- buftochan(char *p)
- {
- Chan *c;
- int fd;
- if(p == 0)
- error(Ebadarg);
- fd = strtoul(p, 0, 0);
- if(fd < 0)
- error(Ebadarg);
- c = fdtochan(up->env->fgrp, fd, -1, 0, 1); /* error check and inc ref */
- return c;
- }
- /* hang up a digest connection */
- static void
- sslhangup(Dstate *s)
- {
- qlock(&s->in.q);
- freeblist(s->processed);
- s->processed = 0;
- freeblist(s->unprocessed);
- s->unprocessed = 0;
- s->state = Sincomplete;
- qunlock(&s->in.q);
- }
- static void
- dsclone(Chan *ch)
- {
- Dstate **pp, **ep, **np;
- int newmax;
- lock(&dslock);
- if(waserror()) {
- unlock(&dslock);
- nexterror();
- }
- ep = &dstate[maxdstate];
- for(pp = dstate; pp < ep; pp++) {
- if(*pp == 0) {
- dsnew(ch, pp);
- break;
- }
- }
- if(pp >= ep) {
- if(maxdstate >= Maxdstate)
- error(Enodev);
- newmax = 2 * maxdstate;
- if(newmax > Maxdstate)
- newmax = Maxdstate;
- np = realloc(dstate, sizeof(Dstate*) * newmax);
- if(np == 0)
- error(Enomem);
- dstate = np;
- pp = &dstate[maxdstate];
- memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate));
- maxdstate = newmax;
- dsnew(ch, pp);
- }
- poperror();
- unlock(&dslock);
- }
- static void
- dsnew(Chan *ch, Dstate **pp)
- {
- Dstate *s;
- int t;
- *pp = s = mallocz(sizeof(*s), 1);
- if(s == nil)
- error(Enomem);
- if(pp - dstate >= dshiwat)
- dshiwat++;
- s->state = Sincomplete;
- s->ref = 1;
- kstrdup(&s->user, up->env->user);
- s->perm = 0660;
- t = TYPE(ch->qid);
- if(t == Qclonus)
- t = Qctl;
- ch->qid.path = QID(pp - dstate, t);
- ch->qid.vers = 0;
- ch->qid.type = QTFILE;
- }
- Dev ssldevtab = {
- 'D',
- "ssl",
- sslinit,
- sslattach,
- sslwalk,
- sslstat,
- sslopen,
- devcreate,
- sslclose,
- sslread,
- sslbread,
- sslwrite,
- sslbwrite,
- devremove,
- sslwstat
- };
|