devssl.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devssl.c (26110B)
       ---
            1 /*
            2  *  devssl - secure sockets layer
            3  */
            4 #include        "u.h"
            5 #include        "lib.h"
            6 #include        "mem.h"
            7 #include        "dat.h"
            8 #include        "fns.h"
            9 #include        "error.h"
           10 
           11 #include        "libsec.h"
           12 
           13 #define NOSPOOKS 1
           14 
           15 typedef struct OneWay OneWay;
           16 struct OneWay
           17 {
           18         QLock        q;
           19         QLock        ctlq;
           20 
           21         void        *state;                /* encryption state */
           22         int        slen;                /* hash data length */
           23         uchar        *secret;        /* secret */
           24         ulong        mid;                /* message id */
           25 };
           26 
           27 enum
           28 {
           29         /* connection states */
           30         Sincomplete=        0,
           31         Sclear=                1,
           32         Sencrypting=        2,
           33         Sdigesting=        4,
           34         Sdigenc=        Sencrypting|Sdigesting,
           35 
           36         /* encryption algorithms */
           37         Noencryption=        0,
           38         DESCBC=                1,
           39         DESECB=                2,
           40         RC4=                3
           41 };
           42 
           43 typedef struct Dstate Dstate;
           44 struct Dstate
           45 {
           46         Chan        *c;                /* io channel */
           47         uchar        state;                /* state of connection */
           48         int        ref;                /* serialized by dslock for atomic destroy */
           49 
           50         uchar        encryptalg;        /* encryption algorithm */
           51         ushort        blocklen;        /* blocking length */
           52 
           53         ushort        diglen;                /* length of digest */
           54         DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);        /* hash func */
           55 
           56         /* for SSL format */
           57         int        max;                /* maximum unpadded data per msg */
           58         int        maxpad;                /* maximum padded data per msg */
           59 
           60         /* input side */
           61         OneWay        in;
           62         Block        *processed;
           63         Block        *unprocessed;
           64 
           65         /* output side */
           66         OneWay        out;
           67 
           68         /* protections */
           69         char        *user;
           70         int        perm;
           71 };
           72 
           73 enum
           74 {
           75         Maxdmsg=        1<<16,
           76         Maxdstate=        128,        /* must be a power of 2 */
           77 };
           78 
           79 Lock        dslock;
           80 int        dshiwat;
           81 char        *dsname[Maxdstate];
           82 Dstate        *dstate[Maxdstate];
           83 char        *encalgs;
           84 char        *hashalgs;
           85 
           86 enum{
           87         Qtopdir                = 1,        /* top level directory */
           88         Qprotodir,
           89         Qclonus,
           90         Qconvdir,                /* directory for a conversation */
           91         Qdata,
           92         Qctl,
           93         Qsecretin,
           94         Qsecretout,
           95         Qencalgs,
           96         Qhashalgs,
           97 };
           98 
           99 #define TYPE(x)         ((x).path & 0xf)
          100 #define CONV(x)         (((x).path >> 5)&(Maxdstate-1))
          101 #define QID(c, y)         (((c)<<5) | (y))
          102 
          103 static void        ensure(Dstate*, Block**, int);
          104 static void        consume(Block**, uchar*, int);
          105 static void        setsecret(OneWay*, uchar*, int);
          106 static Block*        encryptb(Dstate*, Block*, int);
          107 static Block*        decryptb(Dstate*, Block*);
          108 static Block*        digestb(Dstate*, Block*, int);
          109 static void        checkdigestb(Dstate*, Block*);
          110 static Chan*        buftochan(char*);
          111 static void        sslhangup(Dstate*);
          112 static Dstate*        dsclone(Chan *c);
          113 static void        dsnew(Chan *c, Dstate **);
          114 static long        sslput(Dstate *s, Block * volatile b);
          115 
          116 char *sslnames[] = {
          117 [Qclonus]        "clone",
          118 [Qdata]                "data",
          119 [Qctl]                "ctl",
          120 [Qsecretin]        "secretin",
          121 [Qsecretout]        "secretout",
          122 [Qencalgs]        "encalgs",
          123 [Qhashalgs]        "hashalgs",
          124 };
          125 
          126 static int
          127 sslgen(Chan *c, char *_, Dirtab *d, int nd, int s, Dir *dp)
          128 {
          129         Qid q;
          130         Dstate *ds;
          131         char name[16], *p, *nm;
          132         int ft;
          133 
          134         USED(nd);
          135         USED(d);
          136 
          137         q.type = QTFILE;
          138         q.vers = 0;
          139 
          140         ft = TYPE(c->qid);
          141         switch(ft) {
          142         case Qtopdir:
          143                 if(s == DEVDOTDOT){
          144                         q.path = QID(0, Qtopdir);
          145                         q.type = QTDIR;
          146                         devdir(c, q, "#D", 0, eve, 0555, dp);
          147                         return 1;
          148                 }
          149                 if(s > 0)
          150                         return -1;
          151                 q.path = QID(0, Qprotodir);
          152                 q.type = QTDIR;
          153                 devdir(c, q, "ssl", 0, eve, 0555, dp);
          154                 return 1;
          155         case Qprotodir:
          156                 if(s == DEVDOTDOT){
          157                         q.path = QID(0, Qtopdir);
          158                         q.type = QTDIR;
          159                         devdir(c, q, ".", 0, eve, 0555, dp);
          160                         return 1;
          161                 }
          162                 if(s < dshiwat) {
          163                         q.path = QID(s, Qconvdir);
          164                         q.type = QTDIR;
          165                         ds = dstate[s];
          166                         if(ds != 0)
          167                                 nm = ds->user;
          168                         else
          169                                 nm = eve;
          170                         if(dsname[s] == nil){
          171                                 sprint(name, "%d", s);
          172                                 kstrdup(&dsname[s], name);
          173                         }
          174                         devdir(c, q, dsname[s], 0, nm, 0555, dp);
          175                         return 1;
          176                 }
          177                 if(s > dshiwat)
          178                         return -1;
          179                 q.path = QID(0, Qclonus);
          180                 devdir(c, q, "clone", 0, eve, 0555, dp);
          181                 return 1;
          182         case Qconvdir:
          183                 if(s == DEVDOTDOT){
          184                         q.path = QID(0, Qprotodir);
          185                         q.type = QTDIR;
          186                         devdir(c, q, "ssl", 0, eve, 0555, dp);
          187                         return 1;
          188                 }
          189                 ds = dstate[CONV(c->qid)];
          190                 if(ds != 0)
          191                         nm = ds->user;
          192                 else
          193                         nm = eve;
          194                 switch(s) {
          195                 default:
          196                         return -1;
          197                 case 0:
          198                         q.path = QID(CONV(c->qid), Qctl);
          199                         p = "ctl";
          200                         break;
          201                 case 1:
          202                         q.path = QID(CONV(c->qid), Qdata);
          203                         p = "data";
          204                         break;
          205                 case 2:
          206                         q.path = QID(CONV(c->qid), Qsecretin);
          207                         p = "secretin";
          208                         break;
          209                 case 3:
          210                         q.path = QID(CONV(c->qid), Qsecretout);
          211                         p = "secretout";
          212                         break;
          213                 case 4:
          214                         q.path = QID(CONV(c->qid), Qencalgs);
          215                         p = "encalgs";
          216                         break;
          217                 case 5:
          218                         q.path = QID(CONV(c->qid), Qhashalgs);
          219                         p = "hashalgs";
          220                         break;
          221                 }
          222                 devdir(c, q, p, 0, nm, 0660, dp);
          223                 return 1;
          224         case Qclonus:
          225                 devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
          226                 return 1;
          227         default:
          228                 ds = dstate[CONV(c->qid)];
          229                 if(ds != 0)
          230                         nm = ds->user;
          231                 else
          232                         nm = eve;
          233                 devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
          234                 return 1;
          235         }
          236 }
          237 
          238 static Chan*
          239 sslattach(char *spec)
          240 {
          241         Chan *c;
          242 
          243         c = devattach('D', spec);
          244         c->qid.path = QID(0, Qtopdir);
          245         c->qid.vers = 0;
          246         c->qid.type = QTDIR;
          247         return c;
          248 }
          249 
          250 static Walkqid*
          251 sslwalk(Chan *c, Chan *nc, char **name, int nname)
          252 {
          253         return devwalk(c, nc, name, nname, nil, 0, sslgen);
          254 }
          255 
          256 static int
          257 sslstat(Chan *c, uchar *db, int n)
          258 {
          259         return devstat(c, db, n, nil, 0, sslgen);
          260 }
          261 
          262 static Chan*
          263 sslopen(Chan *c, int omode)
          264 {
          265         Dstate *s, **pp;
          266         int perm;
          267         int ft;
          268 
          269         perm = 0;
          270         omode &= 3;
          271         switch(omode) {
          272         case OREAD:
          273                 perm = 4;
          274                 break;
          275         case OWRITE:
          276                 perm = 2;
          277                 break;
          278         case ORDWR:
          279                 perm = 6;
          280                 break;
          281         }
          282 
          283         ft = TYPE(c->qid);
          284         switch(ft) {
          285         default:
          286                 panic("sslopen");
          287         case Qtopdir:
          288         case Qprotodir:
          289         case Qconvdir:
          290                 if(omode != OREAD)
          291                         error(Eperm);
          292                 break;
          293         case Qclonus:
          294                 s = dsclone(c);
          295                 if(s == 0)
          296                         error(Enodev);
          297                 break;
          298         case Qctl:
          299         case Qdata:
          300         case Qsecretin:
          301         case Qsecretout:
          302                 if(waserror()) {
          303                         unlock(&dslock);
          304                         nexterror();
          305                 }
          306                 lock(&dslock);
          307                 pp = &dstate[CONV(c->qid)];
          308                 s = *pp;
          309                 if(s == 0)
          310                         dsnew(c, pp);
          311                 else {
          312                         if((perm & (s->perm>>6)) != perm
          313                            && (strcmp(up->user, s->user) != 0
          314                              || (perm & s->perm) != perm))
          315                                 error(Eperm);
          316 
          317                         s->ref++;
          318                 }
          319                 unlock(&dslock);
          320                 poperror();
          321                 break;
          322         case Qencalgs:
          323         case Qhashalgs:
          324                 if(omode != OREAD)
          325                         error(Eperm);
          326                 break;
          327         }
          328         c->mode = openmode(omode);
          329         c->flag |= COPEN;
          330         c->offset = 0;
          331         return c;
          332 }
          333 
          334 static int
          335 sslwstat(Chan *c, uchar *db, int n)
          336 {
          337         Dir *dir;
          338         Dstate *s;
          339         int m;
          340 
          341         s = dstate[CONV(c->qid)];
          342         if(s == 0)
          343                 error(Ebadusefd);
          344         if(strcmp(s->user, up->user) != 0)
          345                 error(Eperm);
          346 
          347         dir = smalloc(sizeof(Dir)+n);
          348         m = convM2D(db, n, &dir[0], (char*)&dir[1]);
          349         if(m == 0){
          350                 free(dir);
          351                 error(Eshortstat);
          352         }
          353 
          354         if(!emptystr(dir->uid))
          355                 kstrdup(&s->user, dir->uid);
          356         if(dir->mode != ~0UL)
          357                 s->perm = dir->mode;
          358 
          359         free(dir);
          360         return m;
          361 }
          362 
          363 static void
          364 sslclose(Chan *c)
          365 {
          366         Dstate *s;
          367         int ft;
          368 
          369         ft = TYPE(c->qid);
          370         switch(ft) {
          371         case Qctl:
          372         case Qdata:
          373         case Qsecretin:
          374         case Qsecretout:
          375                 if((c->flag & COPEN) == 0)
          376                         break;
          377 
          378                 s = dstate[CONV(c->qid)];
          379                 if(s == 0)
          380                         break;
          381 
          382                 lock(&dslock);
          383                 if(--s->ref > 0) {
          384                         unlock(&dslock);
          385                         break;
          386                 }
          387                 dstate[CONV(c->qid)] = 0;
          388                 unlock(&dslock);
          389 
          390                 if(s->user != nil)
          391                         free(s->user);
          392                 sslhangup(s);
          393                 if(s->c)
          394                         cclose(s->c);
          395                 if(s->in.secret)
          396                         free(s->in.secret);
          397                 if(s->out.secret)
          398                         free(s->out.secret);
          399                 if(s->in.state)
          400                         free(s->in.state);
          401                 if(s->out.state)
          402                         free(s->out.state);
          403                 free(s);
          404 
          405         }
          406 }
          407 
          408 /*
          409  *  make sure we have at least 'n' bytes in list 'l'
          410  */
          411 static void
          412 ensure(Dstate *s, Block **l, int n)
          413 {
          414         int sofar, i;
          415         Block *b, *bl;
          416 
          417         sofar = 0;
          418         for(b = *l; b; b = b->next){
          419                 sofar += BLEN(b);
          420                 if(sofar >= n)
          421                         return;
          422                 l = &b->next;
          423         }
          424 
          425         while(sofar < n){
          426                 bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
          427                 if(bl == 0)
          428                         nexterror();
          429                 *l = bl;
          430                 i = 0;
          431                 for(b = bl; b; b = b->next){
          432                         i += BLEN(b);
          433                         l = &b->next;
          434                 }
          435                 if(i == 0)
          436                         error(Ehungup);
          437                 sofar += i;
          438         }
          439 }
          440 
          441 /*
          442  *  copy 'n' bytes from 'l' into 'p' and free
          443  *  the bytes in 'l'
          444  */
          445 static void
          446 consume(Block **l, uchar *p, int n)
          447 {
          448         Block *b;
          449         int i;
          450 
          451         for(; *l && n > 0; n -= i){
          452                 b = *l;
          453                 i = BLEN(b);
          454                 if(i > n)
          455                         i = n;
          456                 memmove(p, b->rp, i);
          457                 b->rp += i;
          458                 p += i;
          459                 if(BLEN(b) < 0)
          460                         panic("consume");
          461                 if(BLEN(b))
          462                         break;
          463                 *l = b->next;
          464                 freeb(b);
          465         }
          466 }
          467 
          468 /*
          469  *  give back n bytes
          470 static void
          471 regurgitate(Dstate *s, uchar *p, int n)
          472 {
          473         Block *b;
          474 
          475         if(n <= 0)
          476                 return;
          477         b = s->unprocessed;
          478         if(s->unprocessed == nil || b->rp - b->base < n) {
          479                 b = allocb(n);
          480                 memmove(b->wp, p, n);
          481                 b->wp += n;
          482                 b->next = s->unprocessed;
          483                 s->unprocessed = b;
          484         } else {
          485                 b->rp -= n;
          486                 memmove(b->rp, p, n);
          487         }
          488 }
          489  */
          490 
          491 /*
          492  *  remove at most n bytes from the queue, if discard is set
          493  *  dump the remainder
          494  */
          495 static Block*
          496 qtake(Block **l, int n, int discard)
          497 {
          498         Block *nb, *b, *first;
          499         int i;
          500 
          501         first = *l;
          502         for(b = first; b; b = b->next){
          503                 i = BLEN(b);
          504                 if(i == n){
          505                         if(discard){
          506                                 freeblist(b->next);
          507                                 *l = 0;
          508                         } else
          509                                 *l = b->next;
          510                         b->next = 0;
          511                         return first;
          512                 } else if(i > n){
          513                         i -= n;
          514                         if(discard){
          515                                 freeblist(b->next);
          516                                 b->wp -= i;
          517                                 *l = 0;
          518                         } else {
          519                                 nb = allocb(i);
          520                                 memmove(nb->wp, b->rp+n, i);
          521                                 nb->wp += i;
          522                                 b->wp -= i;
          523                                 nb->next = b->next;
          524                                 *l = nb;
          525                         }
          526                         b->next = 0;
          527                         if(BLEN(b) < 0)
          528                                 panic("qtake");
          529                         return first;
          530                 } else
          531                         n -= i;
          532                 if(BLEN(b) < 0)
          533                         panic("qtake");
          534         }
          535         *l = 0;
          536         return first;
          537 }
          538 
          539 /*
          540  *  We can't let Eintr's lose data since the program
          541  *  doing the read may be able to handle it.  The only
          542  *  places Eintr is possible is during the read's in consume.
          543  *  Therefore, we make sure we can always put back the bytes
          544  *  consumed before the last ensure.
          545  */
          546 static Block*
          547 sslbread(Chan *c, long n, ulong _)
          548 {
          549         Dstate * volatile s;
          550         Block *b;
          551         uchar consumed[3], *p;
          552         int toconsume;
          553         int len, pad;
          554 
          555         s = dstate[CONV(c->qid)];
          556         if(s == 0)
          557                 panic("sslbread");
          558         if(s->state == Sincomplete)
          559                 error(Ebadusefd);
          560 
          561         qlock(&s->in.q);
          562         if(waserror()){
          563                 qunlock(&s->in.q);
          564                 nexterror();
          565         }
          566 
          567         if(s->processed == 0){
          568                 /*
          569                  * Read in the whole message.  Until we've got it all,
          570                  * it stays on s->unprocessed, so that if we get Eintr,
          571                  * we'll pick up where we left off.
          572                  */
          573                 ensure(s, &s->unprocessed, 3);
          574                 s->unprocessed = pullupblock(s->unprocessed, 2);
          575                 p = s->unprocessed->rp;
          576                 if(p[0] & 0x80){
          577                         len = ((p[0] & 0x7f)<<8) | p[1];
          578                         ensure(s, &s->unprocessed, len);
          579                         pad = 0;
          580                         toconsume = 2;
          581                 } else {
          582                         s->unprocessed = pullupblock(s->unprocessed, 3);
          583                         len = ((p[0] & 0x3f)<<8) | p[1];
          584                         pad = p[2];
          585                         if(pad > len){
          586                                 print("pad %d buf len %d\n", pad, len);
          587                                 error("bad pad in ssl message");
          588                         }
          589                         toconsume = 3;
          590                 }
          591                 ensure(s, &s->unprocessed, toconsume+len);
          592 
          593                 /* skip header */
          594                 consume(&s->unprocessed, consumed, toconsume);
          595 
          596                 /* grab the next message and decode/decrypt it */
          597                 b = qtake(&s->unprocessed, len, 0);
          598 
          599                 if(blocklen(b) != len)
          600                         print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
          601 
          602                 if(waserror()){
          603                         qunlock(&s->in.ctlq);
          604                         if(b != nil)
          605                                 freeb(b);
          606                         nexterror();
          607                 }
          608                 qlock(&s->in.ctlq);
          609                 switch(s->state){
          610                 case Sencrypting:
          611                         if(b == nil)
          612                                 error("ssl message too short (encrypting)");
          613                         b = decryptb(s, b);
          614                         break;
          615                 case Sdigesting:
          616                         b = pullupblock(b, s->diglen);
          617                         if(b == nil)
          618                                 error("ssl message too short (digesting)");
          619                         checkdigestb(s, b);
          620                         pullblock(&b, s->diglen);
          621                         len -= s->diglen;
          622                         break;
          623                 case Sdigenc:
          624                         b = decryptb(s, b);
          625                         b = pullupblock(b, s->diglen);
          626                         if(b == nil)
          627                                 error("ssl message too short (dig+enc)");
          628                         checkdigestb(s, b);
          629                         pullblock(&b, s->diglen);
          630                         len -= s->diglen;
          631                         break;
          632                 }
          633 
          634                 /* remove pad */
          635                 if(pad)
          636                         s->processed = qtake(&b, len - pad, 1);
          637                 else
          638                         s->processed = b;
          639                 b = nil;
          640                 s->in.mid++;
          641                 qunlock(&s->in.ctlq);
          642                 poperror();
          643         }
          644 
          645         /* return at most what was asked for */
          646         b = qtake(&s->processed, n, 0);
          647 
          648         qunlock(&s->in.q);
          649         poperror();
          650 
          651         return b;
          652 }
          653 
          654 static long
          655 sslread(Chan *c, void *a, long n, vlong off)
          656 {
          657         Block * volatile b;
          658         Block *nb;
          659         uchar *va;
          660         int i;
          661         char buf[128];
          662         ulong offset = off;
          663         int ft;
          664 
          665         if(c->qid.type & QTDIR)
          666                 return devdirread(c, a, n, 0, 0, sslgen);
          667 
          668         ft = TYPE(c->qid);
          669         switch(ft) {
          670         default:
          671                 error(Ebadusefd);
          672         case Qctl:
          673                 ft = CONV(c->qid);
          674                 sprint(buf, "%d", ft);
          675                 return readstr(offset, a, n, buf);
          676         case Qdata:
          677                 b = sslbread(c, n, offset);
          678                 break;
          679         case Qencalgs:
          680                 return readstr(offset, a, n, encalgs);
          681                 break;
          682         case Qhashalgs:
          683                 return readstr(offset, a, n, hashalgs);
          684                 break;
          685         }
          686 
          687         if(waserror()){
          688                 freeblist(b);
          689                 nexterror();
          690         }
          691 
          692         n = 0;
          693         va = a;
          694         for(nb = b; nb; nb = nb->next){
          695                 i = BLEN(nb);
          696                 memmove(va+n, nb->rp, i);
          697                 n += i;
          698         }
          699 
          700         freeblist(b);
          701         poperror();
          702 
          703         return n;
          704 }
          705 
          706 /*
          707  *  this algorithm doesn't have to be great since we're just
          708  *  trying to obscure the block fill
          709  */
          710 static void
          711 randfill(uchar *buf, int len)
          712 {
          713         while(len-- > 0)
          714                 *buf++ = nrand(256);
          715 }
          716 
          717 static long
          718 sslbwrite(Chan *c, Block *b, ulong _)
          719 {
          720         Dstate * volatile s;
          721         long rv;
          722 
          723         s = dstate[CONV(c->qid)];
          724         if(s == nil)
          725                 panic("sslbwrite");
          726 
          727         if(s->state == Sincomplete){
          728                 freeb(b);
          729                 error(Ebadusefd);
          730         }
          731 
          732         /* lock so split writes won't interleave */
          733         if(waserror()){
          734                 qunlock(&s->out.q);
          735                 nexterror();
          736         }
          737         qlock(&s->out.q);
          738 
          739         rv = sslput(s, b);
          740 
          741         poperror();
          742         qunlock(&s->out.q);
          743 
          744         return rv;
          745 }
          746 
          747 /*
          748  *  use SSL record format, add in count, digest and/or encrypt.
          749  *  the write is interruptable.  if it is interrupted, we'll
          750  *  get out of sync with the far side.  not much we can do about
          751  *  it since we don't know if any bytes have been written.
          752  */
          753 static long
          754 sslput(Dstate *s, Block * volatile b)
          755 {
          756         Block *nb;
          757         int h, n, m, pad, rv;
          758         uchar *p;
          759         int offset;
          760 
          761         if(waserror()){
          762                 if(b != nil)
          763                         free(b);
          764                 nexterror();
          765         }
          766 
          767         rv = 0;
          768         while(b != nil){
          769                 m = n = BLEN(b);
          770                 h = s->diglen + 2;
          771 
          772                 /* trim to maximum block size */
          773                 pad = 0;
          774                 if(m > s->max){
          775                         m = s->max;
          776                 } else if(s->blocklen != 1){
          777                         pad = (m + s->diglen)%s->blocklen;
          778                         if(pad){
          779                                 if(m > s->maxpad){
          780                                         pad = 0;
          781                                         m = s->maxpad;
          782                                 } else {
          783                                         pad = s->blocklen - pad;
          784                                         h++;
          785                                 }
          786                         }
          787                 }
          788 
          789                 rv += m;
          790                 if(m != n){
          791                         nb = allocb(m + h + pad);
          792                         memmove(nb->wp + h, b->rp, m);
          793                         nb->wp += m + h;
          794                         b->rp += m;
          795                 } else {
          796                         /* add header space */
          797                         nb = padblock(b, h);
          798                         b = 0;
          799                 }
          800                 m += s->diglen;
          801 
          802                 /* SSL style count */
          803                 if(pad){
          804                         nb = padblock(nb, -pad);
          805                         randfill(nb->wp, pad);
          806                         nb->wp += pad;
          807                         m += pad;
          808 
          809                         p = nb->rp;
          810                         p[0] = (m>>8);
          811                         p[1] = m;
          812                         p[2] = pad;
          813                         offset = 3;
          814                 } else {
          815                         p = nb->rp;
          816                         p[0] = (m>>8) | 0x80;
          817                         p[1] = m;
          818                         offset = 2;
          819                 }
          820 
          821                 switch(s->state){
          822                 case Sencrypting:
          823                         nb = encryptb(s, nb, offset);
          824                         break;
          825                 case Sdigesting:
          826                         nb = digestb(s, nb, offset);
          827                         break;
          828                 case Sdigenc:
          829                         nb = digestb(s, nb, offset);
          830                         nb = encryptb(s, nb, offset);
          831                         break;
          832                 }
          833 
          834                 s->out.mid++;
          835 
          836                 m = BLEN(nb);
          837                 devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
          838                 s->c->offset += m;
          839         }
          840 
          841         poperror();
          842         return rv;
          843 }
          844 
          845 static void
          846 setsecret(OneWay *w, uchar *secret, int n)
          847 {
          848         if(w->secret)
          849                 free(w->secret);
          850 
          851         w->secret = smalloc(n);
          852         memmove(w->secret, secret, n);
          853         w->slen = n;
          854 }
          855 
          856 static void
          857 initDESkey(OneWay *w)
          858 {
          859         if(w->state){
          860                 free(w->state);
          861                 w->state = 0;
          862         }
          863 
          864         w->state = smalloc(sizeof(DESstate));
          865         if(w->slen >= 16)
          866                 setupDESstate(w->state, w->secret, w->secret+8);
          867         else if(w->slen >= 8)
          868                 setupDESstate(w->state, w->secret, 0);
          869         else
          870                 error("secret too short");
          871 }
          872 
          873 /*
          874  *  40 bit DES is the same as 56 bit DES.  However,
          875  *  16 bits of the key are masked to zero.
          876  */
          877 static void
          878 initDESkey_40(OneWay *w)
          879 {
          880         uchar key[8];
          881 
          882         if(w->state){
          883                 free(w->state);
          884                 w->state = 0;
          885         }
          886 
          887         if(w->slen >= 8){
          888                 memmove(key, w->secret, 8);
          889                 key[0] &= 0x0f;
          890                 key[2] &= 0x0f;
          891                 key[4] &= 0x0f;
          892                 key[6] &= 0x0f;
          893         }
          894 
          895         w->state = malloc(sizeof(DESstate));
          896         if(w->slen >= 16)
          897                 setupDESstate(w->state, key, w->secret+8);
          898         else if(w->slen >= 8)
          899                 setupDESstate(w->state, key, 0);
          900         else
          901                 error("secret too short");
          902 }
          903 
          904 static void
          905 initRC4key(OneWay *w)
          906 {
          907         if(w->state){
          908                 free(w->state);
          909                 w->state = 0;
          910         }
          911 
          912         w->state = smalloc(sizeof(RC4state));
          913         setupRC4state(w->state, w->secret, w->slen);
          914 }
          915 
          916 /*
          917  *  40 bit RC4 is the same as n-bit RC4.  However,
          918  *  we ignore all but the first 40 bits of the key.
          919  */
          920 static void
          921 initRC4key_40(OneWay *w)
          922 {
          923         if(w->state){
          924                 free(w->state);
          925                 w->state = 0;
          926         }
          927 
          928         if(w->slen > 5)
          929                 w->slen = 5;
          930 
          931         w->state = malloc(sizeof(RC4state));
          932         setupRC4state(w->state, w->secret, w->slen);
          933 }
          934 
          935 /*
          936  *  128 bit RC4 is the same as n-bit RC4.  However,
          937  *  we ignore all but the first 128 bits of the key.
          938  */
          939 static void
          940 initRC4key_128(OneWay *w)
          941 {
          942         if(w->state){
          943                 free(w->state);
          944                 w->state = 0;
          945         }
          946 
          947         if(w->slen > 16)
          948                 w->slen = 16;
          949 
          950         w->state = malloc(sizeof(RC4state));
          951         setupRC4state(w->state, w->secret, w->slen);
          952 }
          953 
          954 
          955 typedef struct Hashalg Hashalg;
          956 struct Hashalg
          957 {
          958         char        *name;
          959         int        diglen;
          960         DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
          961 };
          962 
          963 Hashalg hashtab[] =
          964 {
          965         { "md4", MD4dlen, md4, },
          966         { "md5", MD5dlen, md5, },
          967         { "sha1", SHA1dlen, sha1, },
          968         { "sha", SHA1dlen, sha1, },
          969         { 0 }
          970 };
          971 
          972 static int
          973 parsehashalg(char *p, Dstate *s)
          974 {
          975         Hashalg *ha;
          976 
          977         for(ha = hashtab; ha->name; ha++){
          978                 if(strcmp(p, ha->name) == 0){
          979                         s->hf = ha->hf;
          980                         s->diglen = ha->diglen;
          981                         s->state &= ~Sclear;
          982                         s->state |= Sdigesting;
          983                         return 0;
          984                 }
          985         }
          986         return -1;
          987 }
          988 
          989 typedef struct Encalg Encalg;
          990 struct Encalg
          991 {
          992         char        *name;
          993         int        blocklen;
          994         int        alg;
          995         void        (*keyinit)(OneWay*);
          996 };
          997 
          998 #ifdef NOSPOOKS
          999 Encalg encrypttab[] =
         1000 {
         1001         { "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
         1002         { "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
         1003         { "des_56_cbc", 8, DESCBC, initDESkey, },
         1004         { "des_56_ecb", 8, DESECB, initDESkey, },
         1005         { "des_40_cbc", 8, DESCBC, initDESkey_40, },
         1006         { "des_40_ecb", 8, DESECB, initDESkey_40, },
         1007         { "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
         1008         { "rc4_256", 1, RC4, initRC4key, },
         1009         { "rc4_128", 1, RC4, initRC4key_128, },
         1010         { "rc4_40", 1, RC4, initRC4key_40, },
         1011         { 0 }
         1012 };
         1013 #else
         1014 Encalg encrypttab[] =
         1015 {
         1016         { "des_40_cbc", 8, DESCBC, initDESkey_40, },
         1017         { "des_40_ecb", 8, DESECB, initDESkey_40, },
         1018         { "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
         1019         { "rc4_40", 1, RC4, initRC4key_40, },
         1020         { 0 }
         1021 };
         1022 #endif 
         1023 
         1024 static int
         1025 parseencryptalg(char *p, Dstate *s)
         1026 {
         1027         Encalg *ea;
         1028 
         1029         for(ea = encrypttab; ea->name; ea++){
         1030                 if(strcmp(p, ea->name) == 0){
         1031                         s->encryptalg = ea->alg;
         1032                         s->blocklen = ea->blocklen;
         1033                         (*ea->keyinit)(&s->in);
         1034                         (*ea->keyinit)(&s->out);
         1035                         s->state &= ~Sclear;
         1036                         s->state |= Sencrypting;
         1037                         return 0;
         1038                 }
         1039         }
         1040         return -1;
         1041 }
         1042 
         1043 static long
         1044 sslwrite(Chan *c, void *a, long n, vlong offset)
         1045 {
         1046         Dstate * volatile s;
         1047         Block * volatile b;
         1048         int m, t;
         1049         char *p, *np, *e, buf[128];
         1050         uchar *x;
         1051 
         1052         s = dstate[CONV(c->qid)];
         1053         if(s == 0)
         1054                 panic("sslwrite");
         1055 
         1056         t = TYPE(c->qid);
         1057         if(t == Qdata){
         1058                 if(s->state == Sincomplete)
         1059                         error(Ebadusefd);
         1060 
         1061                 /* lock should a write gets split over multiple records */
         1062                 if(waserror()){
         1063                         qunlock(&s->out.q);
         1064                         nexterror();
         1065                 }
         1066                 qlock(&s->out.q);
         1067 
         1068                 p = a;
         1069                 e = p + n;
         1070                 do {
         1071                         m = e - p;
         1072                         if(m > s->max)
         1073                                 m = s->max;
         1074 
         1075                         b = allocb(m);
         1076                         if(waserror()){
         1077                                 freeb(b);
         1078                                 nexterror();
         1079                         }
         1080                         memmove(b->wp, p, m);
         1081                         poperror();
         1082                         b->wp += m;
         1083 
         1084                         sslput(s, b);
         1085 
         1086                         p += m;
         1087                 } while(p < e);
         1088 
         1089                 poperror();
         1090                 qunlock(&s->out.q);
         1091                 return n;
         1092         }
         1093 
         1094         /* mutex with operations using what we're about to change */
         1095         if(waserror()){
         1096                 qunlock(&s->in.ctlq);
         1097                 qunlock(&s->out.q);
         1098                 nexterror();
         1099         }
         1100         qlock(&s->in.ctlq);
         1101         qlock(&s->out.q);
         1102 
         1103         switch(t){
         1104         default:
         1105                 panic("sslwrite");
         1106         case Qsecretin:
         1107                 setsecret(&s->in, a, n);
         1108                 goto out;
         1109         case Qsecretout:
         1110                 setsecret(&s->out, a, n);
         1111                 goto out;
         1112         case Qctl:
         1113                 break;
         1114         }
         1115 
         1116         if(n >= sizeof(buf))
         1117                 error("arg too long");
         1118         strncpy(buf, a, n);
         1119         buf[n] = 0;
         1120         p = strchr(buf, '\n');
         1121         if(p)
         1122                 *p = 0;
         1123         p = strchr(buf, ' ');
         1124         if(p)
         1125                 *p++ = 0;
         1126 
         1127         if(strcmp(buf, "fd") == 0){
         1128                 s->c = buftochan(p);
         1129 
         1130                 /* default is clear (msg delimiters only) */
         1131                 s->state = Sclear;
         1132                 s->blocklen = 1;
         1133                 s->diglen = 0;
         1134                 s->maxpad = s->max = (1<<15) - s->diglen - 1;
         1135                 s->in.mid = 0;
         1136                 s->out.mid = 0;
         1137         } else if(strcmp(buf, "alg") == 0 && p != 0){
         1138                 s->blocklen = 1;
         1139                 s->diglen = 0;
         1140 
         1141                 if(s->c == 0)
         1142                         error("must set fd before algorithm");
         1143 
         1144                 s->state = Sclear;
         1145                 s->maxpad = s->max = (1<<15) - s->diglen - 1;
         1146                 if(strcmp(p, "clear") == 0){
         1147                         goto out;
         1148                 }
         1149 
         1150                 if(s->in.secret && s->out.secret == 0)
         1151                         setsecret(&s->out, s->in.secret, s->in.slen);
         1152                 if(s->out.secret && s->in.secret == 0)
         1153                         setsecret(&s->in, s->out.secret, s->out.slen);
         1154                 if(s->in.secret == 0 || s->out.secret == 0)
         1155                         error("algorithm but no secret");
         1156 
         1157                 s->hf = 0;
         1158                 s->encryptalg = Noencryption;
         1159                 s->blocklen = 1;
         1160 
         1161                 for(;;){
         1162                         np = strchr(p, ' ');
         1163                         if(np)
         1164                                 *np++ = 0;
         1165 
         1166                         if(parsehashalg(p, s) < 0)
         1167                         if(parseencryptalg(p, s) < 0)
         1168                                 error("bad algorithm");
         1169 
         1170                         if(np == 0)
         1171                                 break;
         1172                         p = np;
         1173                 }
         1174 
         1175                 if(s->hf == 0 && s->encryptalg == Noencryption)
         1176                         error("bad algorithm");
         1177 
         1178                 if(s->blocklen != 1){
         1179                         s->max = (1<<15) - s->diglen - 1;
         1180                         s->max -= s->max % s->blocklen;
         1181                         s->maxpad = (1<<14) - s->diglen - 1;
         1182                         s->maxpad -= s->maxpad % s->blocklen;
         1183                 } else
         1184                         s->maxpad = s->max = (1<<15) - s->diglen - 1;
         1185         } else if(strcmp(buf, "secretin") == 0 && p != 0) {
         1186                 m = (strlen(p)*3)/2;
         1187                 x = smalloc(m);
         1188                 t = dec64(x, m, p, strlen(p));
         1189                 setsecret(&s->in, x, t);
         1190                 free(x);
         1191         } else if(strcmp(buf, "secretout") == 0 && p != 0) {
         1192                 m = (strlen(p)*3)/2 + 1;
         1193                 x = smalloc(m);
         1194                 t = dec64(x, m, p, strlen(p));
         1195                 setsecret(&s->out, x, t);
         1196                 free(x);
         1197         } else
         1198                 error(Ebadarg);
         1199 
         1200 out:
         1201         qunlock(&s->in.ctlq);
         1202         qunlock(&s->out.q);
         1203         poperror();
         1204         return n;
         1205 }
         1206 
         1207 static void
         1208 sslinit(void)
         1209 {
         1210         struct Encalg *e;
         1211         struct Hashalg *h;
         1212         int n;
         1213         char *cp;
         1214 
         1215         n = 1;
         1216         for(e = encrypttab; e->name != nil; e++)
         1217                 n += strlen(e->name) + 1;
         1218         cp = encalgs = smalloc(n);
         1219         for(e = encrypttab;;){
         1220                 strcpy(cp, e->name);
         1221                 cp += strlen(e->name);
         1222                 e++;
         1223                 if(e->name == nil)
         1224                         break;
         1225                 *cp++ = ' ';
         1226         }
         1227         *cp = 0;
         1228 
         1229         n = 1;
         1230         for(h = hashtab; h->name != nil; h++)
         1231                 n += strlen(h->name) + 1;
         1232         cp = hashalgs = smalloc(n);
         1233         for(h = hashtab;;){
         1234                 strcpy(cp, h->name);
         1235                 cp += strlen(h->name);
         1236                 h++;
         1237                 if(h->name == nil)
         1238                         break;
         1239                 *cp++ = ' ';
         1240         }
         1241         *cp = 0;
         1242 }
         1243 
         1244 Dev ssldevtab = {
         1245         'D',
         1246         "ssl",
         1247 
         1248         devreset,
         1249         sslinit,
         1250         devshutdown,
         1251         sslattach,
         1252         sslwalk,
         1253         sslstat,
         1254         sslopen,
         1255         devcreate,
         1256         sslclose,
         1257         sslread,
         1258         sslbread,
         1259         sslwrite,
         1260         sslbwrite,
         1261         devremove,
         1262         sslwstat,
         1263 };
         1264 
         1265 static Block*
         1266 encryptb(Dstate *s, Block *b, int offset)
         1267 {
         1268         uchar *p, *ep, *p2, *ip, *eip;
         1269         DESstate *ds;
         1270 
         1271         switch(s->encryptalg){
         1272         case DESECB:
         1273                 ds = s->out.state;
         1274                 ep = b->rp + BLEN(b);
         1275                 for(p = b->rp + offset; p < ep; p += 8)
         1276                         block_cipher(ds->expanded, p, 0);
         1277                 break;
         1278         case DESCBC:
         1279                 ds = s->out.state;
         1280                 ep = b->rp + BLEN(b);
         1281                 for(p = b->rp + offset; p < ep; p += 8){
         1282                         p2 = p;
         1283                         ip = ds->ivec;
         1284                         for(eip = ip+8; ip < eip; )
         1285                                 *p2++ ^= *ip++;
         1286                         block_cipher(ds->expanded, p, 0);
         1287                         memmove(ds->ivec, p, 8);
         1288                 }
         1289                 break;
         1290         case RC4:
         1291                 rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
         1292                 break;
         1293         }
         1294         return b;
         1295 }
         1296 
         1297 static Block*
         1298 decryptb(Dstate *s, Block *bin)
         1299 {
         1300         Block *b, **l;
         1301         uchar *p, *ep, *tp, *ip, *eip;
         1302         DESstate *ds;
         1303         uchar tmp[8];
         1304         int i;
         1305 
         1306         l = &bin;
         1307         for(b = bin; b; b = b->next){
         1308                 /* make sure we have a multiple of s->blocklen */
         1309                 if(s->blocklen > 1){
         1310                         i = BLEN(b);
         1311                         if(i % s->blocklen){
         1312                                 *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
         1313                                 if(b == 0)
         1314                                         error("ssl encrypted message too short");
         1315                         }
         1316                 }
         1317                 l = &b->next;
         1318 
         1319                 /* decrypt */
         1320                 switch(s->encryptalg){
         1321                 case DESECB:
         1322                         ds = s->in.state;
         1323                         ep = b->rp + BLEN(b);
         1324                         for(p = b->rp; p < ep; p += 8)
         1325                                 block_cipher(ds->expanded, p, 1);
         1326                         break;
         1327                 case DESCBC:
         1328                         ds = s->in.state;
         1329                         ep = b->rp + BLEN(b);
         1330                         for(p = b->rp; p < ep;){
         1331                                 memmove(tmp, p, 8);
         1332                                 block_cipher(ds->expanded, p, 1);
         1333                                 tp = tmp;
         1334                                 ip = ds->ivec;
         1335                                 for(eip = ip+8; ip < eip; ){
         1336                                         *p++ ^= *ip;
         1337                                         *ip++ = *tp++;
         1338                                 }
         1339                         }
         1340                         break;
         1341                 case RC4:
         1342                         rc4(s->in.state, b->rp, BLEN(b));
         1343                         break;
         1344                 }
         1345         }
         1346         return bin;
         1347 }
         1348 
         1349 static Block*
         1350 digestb(Dstate *s, Block *b, int offset)
         1351 {
         1352         uchar *p;
         1353         DigestState ss;
         1354         uchar msgid[4];
         1355         ulong n, h;
         1356         OneWay *w;
         1357 
         1358         w = &s->out;
         1359 
         1360         memset(&ss, 0, sizeof(ss));
         1361         h = s->diglen + offset;
         1362         n = BLEN(b) - h;
         1363 
         1364         /* hash secret + message */
         1365         (*s->hf)(w->secret, w->slen, 0, &ss);
         1366         (*s->hf)(b->rp + h, n, 0, &ss);
         1367 
         1368         /* hash message id */
         1369         p = msgid;
         1370         n = w->mid;
         1371         *p++ = n>>24;
         1372         *p++ = n>>16;
         1373         *p++ = n>>8;
         1374         *p = n;
         1375         (*s->hf)(msgid, 4, b->rp + offset, &ss);
         1376 
         1377         return b;
         1378 }
         1379 
         1380 static void
         1381 checkdigestb(Dstate *s, Block *bin)
         1382 {
         1383         uchar *p;
         1384         DigestState ss;
         1385         uchar msgid[4];
         1386         int n, h;
         1387         OneWay *w;
         1388         uchar digest[128];
         1389         Block *b;
         1390 
         1391         w = &s->in;
         1392 
         1393         memset(&ss, 0, sizeof(ss));
         1394 
         1395         /* hash secret */
         1396         (*s->hf)(w->secret, w->slen, 0, &ss);
         1397 
         1398         /* hash message */
         1399         h = s->diglen;
         1400         for(b = bin; b; b = b->next){
         1401                 n = BLEN(b) - h;
         1402                 if(n < 0)
         1403                         panic("checkdigestb");
         1404                 (*s->hf)(b->rp + h, n, 0, &ss);
         1405                 h = 0;
         1406         }
         1407 
         1408         /* hash message id */
         1409         p = msgid;
         1410         n = w->mid;
         1411         *p++ = n>>24;
         1412         *p++ = n>>16;
         1413         *p++ = n>>8;
         1414         *p = n;
         1415         (*s->hf)(msgid, 4, digest, &ss);
         1416 
         1417         if(memcmp(digest, bin->rp, s->diglen) != 0)
         1418                 error("bad digest");
         1419 }
         1420 
         1421 /* get channel associated with an fd */
         1422 static Chan*
         1423 buftochan(char *p)
         1424 {
         1425         Chan *c;
         1426         int fd;
         1427 
         1428         if(p == 0)
         1429                 error(Ebadarg);
         1430         fd = strtoul(p, 0, 0);
         1431         if(fd < 0)
         1432                 error(Ebadarg);
         1433         c = fdtochan(fd, -1, 0, 1);        /* error check and inc ref */
         1434         if(devtab[c->type] == &ssldevtab){
         1435                 cclose(c);
         1436                 error("cannot ssl encrypt devssl files");
         1437         }
         1438         return c;
         1439 }
         1440 
         1441 /* hand up a digest connection */
         1442 static void
         1443 sslhangup(Dstate *s)
         1444 {
         1445         Block *b;
         1446 
         1447         qlock(&s->in.q);
         1448         for(b = s->processed; b; b = s->processed){
         1449                 s->processed = b->next;
         1450                 freeb(b);
         1451         }
         1452         if(s->unprocessed){
         1453                 freeb(s->unprocessed);
         1454                 s->unprocessed = 0;
         1455         }
         1456         s->state = Sincomplete;
         1457         qunlock(&s->in.q);
         1458 }
         1459 
         1460 static Dstate*
         1461 dsclone(Chan *ch)
         1462 {
         1463         int i;
         1464         Dstate *ret;
         1465 
         1466         if(waserror()) {
         1467                 unlock(&dslock);
         1468                 nexterror();
         1469         }
         1470         lock(&dslock);
         1471         ret = nil;
         1472         for(i=0; i<Maxdstate; i++){
         1473                 if(dstate[i] == nil){
         1474                         dsnew(ch, &dstate[i]);
         1475                         ret = dstate[i];
         1476                         break;
         1477                 }
         1478         }
         1479         unlock(&dslock);
         1480         poperror();
         1481         return ret;
         1482 }
         1483 
         1484 static void
         1485 dsnew(Chan *ch, Dstate **pp)
         1486 {
         1487         Dstate *s;
         1488         int t;
         1489 
         1490         *pp = s = malloc(sizeof(*s));
         1491         if(!s)
         1492                 error(Enomem);
         1493         if(pp - dstate >= dshiwat)
         1494                 dshiwat++;
         1495         memset(s, 0, sizeof(*s));
         1496         s->state = Sincomplete;
         1497         s->ref = 1;
         1498         kstrdup(&s->user, up->user);
         1499         s->perm = 0660;
         1500         t = TYPE(ch->qid);
         1501         if(t == Qclonus)
         1502                 t = Qctl;
         1503         ch->qid.path = QID(pp - dstate, t);
         1504         ch->qid.vers = 0;
         1505 }