📄 devssl.c
字号:
/* * devssl - secure sockets layer emulation */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include <libsec.h>#define NOSPOOKS 1typedef struct OneWay OneWay;struct OneWay{ QLock q; QLock ctlq; void *state; /* encryption state */ int slen; /* hash 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};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[NAMELEN]; int perm;};Lock dslock;int dshiwat;int maxdstate = 20;Dstate** dstate;char *encalgs;char *hashalgs;enum{ Maxdmsg= 1<<16, Maxdstate= 64};enum{ Qtopdir = 1, /* top level directory */ Qprotodir, Qclonus, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qsecretin, Qsecretout, Qencalgs, Qhashalgs,};#define TYPE(x) ((x).path & 0xf)#define CONV(x) (((x).path >> 5)&(Maxdstate-1))#define QID(c, y) (((c)<<5) | (y))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 Dstate* dsclone(Chan *c);static void dsnew(Chan *c, Dstate **);char *sslnames[] = {[Qclonus] "clone",[Qdata] "data",[Qctl] "ctl",[Qsecretin] "secretin",[Qsecretout] "secretout",[Qencalgs] "encalgs",[Qhashalgs] "hashalgs",};static intsslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp){ Qid q; Dstate *ds; char name[16], *p, *nm; USED(nd); USED(d); q.vers = 0; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir)|CHDIR; devdir(c, q, "#D", 0, eve, CHDIR|0555, dp); return 1; } if(s > 0) return -1; q.path = QID(0, Qprotodir)|CHDIR; devdir(c, q, "ssl", 0, eve, CHDIR|0555, dp); return 1; case Qprotodir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir)|CHDIR; devdir(c, q, ".", 0, eve, CHDIR|0555, dp); return 1; } if(s < dshiwat) { sprint(name, "%d", s); q.path = QID(s, Qconvdir)|CHDIR; ds = dstate[s]; if(ds != 0) nm = ds->user; else nm = eve; devdir(c, q, name, 0, nm, CHDIR|0555, dp); return 1; } if(s > dshiwat) return -1; q.path = QID(0, Qclonus); devdir(c, q, "clone", 0, eve, 0555, dp); return 1; case Qconvdir: if(s == DEVDOTDOT){ q.path = QID(0, Qprotodir)|CHDIR; devdir(c, q, "ssl", 0, eve, CHDIR|0555, dp); return 1; } 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; case Qclonus: devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp); return 1; default: ds = dstate[CONV(c->qid)]; devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, ds->user, 0660, dp); return 1; } return -1;}static Chan*sslattach(char *spec){ Chan *c; c = devattach('D', spec); c->qid.path = QID(0, Qtopdir)|CHDIR; c->qid.vers = 0; return c;}static intsslwalk(Chan *c, char *name){ return devwalk(c, name, 0, 0, sslgen);}static voidsslstat(Chan *c, char *db){ devstat(c, db, 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 Qprotodir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qclonus: s = dsclone(c); if(s == 0) error(Enodev); break; case Qctl: case Qdata: case Qsecretin: case Qsecretout: if(waserror()) { unlock(&dslock); nexterror(); } lock(&dslock); pp = &dstate[CONV(c->qid)]; s = *pp; if(s == 0) dsnew(c, pp); else { if((perm & (s->perm>>6)) != perm && (strcmp(up->user, s->user) != 0 || (perm & s->perm) != perm)) error(Eperm); s->ref++; } unlock(&dslock); poperror(); break; case Qencalgs: case Qhashalgs: if(omode != OREAD) error(Eperm); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;}static voidsslwstat(Chan *c, char *dp){ Dir d; Dstate *s; convM2D(dp, &d); s = dstate[CONV(c->qid)]; if(s == 0) error(Ebadusefd); if(strcmp(s->user, up->user) != 0) error(Eperm); memmove(s->user, d.uid, NAMELEN); s->perm = d.mode;}static voidsslclose(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); if(s->in.secret) free(s->in.secret); if(s->out.secret) free(s->out.secret); if(s->in.state) free(s->in.state); if(s->out.state) free(s->out.state); free(s); }}/* * make sure we have at least 'n' bytes in list 'l' */static voidensure(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 voidconsume(Block **l, uchar *p, int n){ Block *b; int i; for(; *l && n > 0; n -= i){ b = *l; i = BLEN(b); if(i > n) i = n; memmove(p, b->rp, i); b->rp += i; p += i; if(BLEN(b) < 0) panic("consume"); if(BLEN(b)) break; *l = b->next; freeb(b); }}/* * remove at most n bytes from the queue, if discard is set * dump the remainder */static Block*qremove(Block **l, int n, int discard){ Block *nb, *b, *first; int i; first = *l; for(b = first; b; b = b->next){ i = BLEN(b); if(i == n){ if(discard){ freeblist(b->next); *l = 0; } else *l = b->next; b->next = 0; return first; } else if(i > n){ i -= n; if(discard){ freeblist(b->next); b->wp -= i; *l = 0; } else { nb = allocb(i); memmove(nb->wp, b->rp+n, i); nb->wp += i; b->wp -= i; nb->next = b->next; *l = nb; } b->next = 0; if(BLEN(b) < 0) panic("qremove"); return first; } else n -= i; if(BLEN(b) < 0) panic("qremove"); } *l = 0; return first;}static Block*sslbread(Chan *c, long n, ulong){ volatile struct { Dstate *s; } s; Block *b; uchar count[2]; int len, pad; s.s = dstate[CONV(c->qid)]; if(s.s == 0) panic("sslbread"); if(s.s->state == Sincomplete) error(Ebadusefd); if(waserror()){ qunlock(&s.s->in.q); 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); 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, 1); pad = count[0]; if(pad > len){ print("pad %d buf len %d\n", pad, len); error("bad pad in ssl message"); } } /* put extra on unprocessed queue */ s.s->processed = qremove(&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 = qremove(&s.s->processed, len - pad, 1); } /* return at most what was asked for */ b = qremove(&s.s->processed, n, 0); qunlock(&s.s->in.q); poperror(); return b;}static longsslread(Chan *c, void *a, long n, vlong off){ volatile struct { Block *b; } b; Block *nb; uchar *va; int i; char buf[128]; ulong offset = off; if(c->qid.path & CHDIR) return devdirread(c, a, n, 0, 0, sslgen); switch(TYPE(c->qid)) { default: error(Ebadusefd); case Qctl: sprint(buf, "%lud", 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); break; case Qhashalgs: return readstr(offset, a, n, hashalgs); break; } if(waserror()){ freeblist(b.b); nexterror(); } 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); poperror(); return n;}/* * this algorithm doesn't have to be great since we're just * trying to obscure the block fill */static voidrandfill(uchar *buf, int len){ while(len-- > 0) *buf++ = nrand(256);}/* * use SSL record format, add in count and digest or encrypt */static longsslbwrite(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; /* SSL 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -