/* * devssl - secure sockets layer */#include "u.h"#include "../port/lib.h"#include "../port/error.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "kernel.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;}; Lock dslock;int dshiwat;int maxdstate = 20;Dstate** dstate; enum{ Maxdmsg= 1<<16, Maxdstate= 1<<10,}; 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)) /* for generating random fill */ulong badlong;uchar *badarray = (uchar*)&badlong;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 intsslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp){ Qid q; Dstate *ds; char *p, *nm; 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 voidsslinit(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 intsslstat(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 intsslwstat(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 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); 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 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*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; Block *b; uchar count[2]; int len, pad; USED(offset); 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);Lines 1–500 of 1432. Load more
/* * devssl - secure sockets layer */ #include "u.h" #include "../port/lib.h" #include "../port/error.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "kernel.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; }; Lock dslock; int dshiwat; int maxdstate = 20; Dstate** dstate; enum { Maxdmsg= 1<<16, Maxdstate= 1<<10, }; 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)) /* for generating random fill */ ulong badlong; uchar *badarray = (uchar*)&badlong; 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*, Dirtab *d, int nd, int s, Dir *dp) { Qid q; Dstate *ds; char *p, *nm; 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; Block *b; uchar count[2]; int len, pad; USED(offset); 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);