19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier * devssl - secure sockets layer
39ef1f84bSDavid du Colombier */
49ef1f84bSDavid du Colombier #include "u.h"
59ef1f84bSDavid du Colombier #include "../port/lib.h"
69ef1f84bSDavid du Colombier #include "mem.h"
79ef1f84bSDavid du Colombier #include "dat.h"
89ef1f84bSDavid du Colombier #include "fns.h"
99ef1f84bSDavid du Colombier #include "../port/error.h"
109ef1f84bSDavid du Colombier
119ef1f84bSDavid du Colombier #include <libsec.h>
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier #define NOSPOOKS 1
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier typedef struct OneWay OneWay;
169ef1f84bSDavid du Colombier struct OneWay
179ef1f84bSDavid du Colombier {
189ef1f84bSDavid du Colombier QLock q;
199ef1f84bSDavid du Colombier QLock ctlq;
209ef1f84bSDavid du Colombier
219ef1f84bSDavid du Colombier void *state; /* encryption state */
229ef1f84bSDavid du Colombier int slen; /* hash data length */
239ef1f84bSDavid du Colombier uchar *secret; /* secret */
249ef1f84bSDavid du Colombier ulong mid; /* message id */
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier
279ef1f84bSDavid du Colombier enum
289ef1f84bSDavid du Colombier {
299ef1f84bSDavid du Colombier /* connection states */
309ef1f84bSDavid du Colombier Sincomplete= 0,
319ef1f84bSDavid du Colombier Sclear= 1,
329ef1f84bSDavid du Colombier Sencrypting= 2,
339ef1f84bSDavid du Colombier Sdigesting= 4,
349ef1f84bSDavid du Colombier Sdigenc= Sencrypting|Sdigesting,
359ef1f84bSDavid du Colombier
369ef1f84bSDavid du Colombier /* encryption algorithms */
379ef1f84bSDavid du Colombier Noencryption= 0,
389ef1f84bSDavid du Colombier DESCBC= 1,
399ef1f84bSDavid du Colombier DESECB= 2,
409ef1f84bSDavid du Colombier RC4= 3
419ef1f84bSDavid du Colombier };
429ef1f84bSDavid du Colombier
439ef1f84bSDavid du Colombier typedef struct Dstate Dstate;
449ef1f84bSDavid du Colombier struct Dstate
459ef1f84bSDavid du Colombier {
469ef1f84bSDavid du Colombier Chan *c; /* io channel */
479ef1f84bSDavid du Colombier uchar state; /* state of connection */
489ef1f84bSDavid du Colombier int ref; /* serialized by dslock for atomic destroy */
499ef1f84bSDavid du Colombier
509ef1f84bSDavid du Colombier uchar encryptalg; /* encryption algorithm */
519ef1f84bSDavid du Colombier ushort blocklen; /* blocking length */
529ef1f84bSDavid du Colombier
539ef1f84bSDavid du Colombier ushort diglen; /* length of digest */
549ef1f84bSDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
559ef1f84bSDavid du Colombier
569ef1f84bSDavid du Colombier /* for SSL format */
579ef1f84bSDavid du Colombier int max; /* maximum unpadded data per msg */
589ef1f84bSDavid du Colombier int maxpad; /* maximum padded data per msg */
599ef1f84bSDavid du Colombier
609ef1f84bSDavid du Colombier /* input side */
619ef1f84bSDavid du Colombier OneWay in;
629ef1f84bSDavid du Colombier Block *processed;
639ef1f84bSDavid du Colombier Block *unprocessed;
649ef1f84bSDavid du Colombier
659ef1f84bSDavid du Colombier /* output side */
669ef1f84bSDavid du Colombier OneWay out;
679ef1f84bSDavid du Colombier
689ef1f84bSDavid du Colombier /* protections */
699ef1f84bSDavid du Colombier char *user;
709ef1f84bSDavid du Colombier int perm;
719ef1f84bSDavid du Colombier };
729ef1f84bSDavid du Colombier
739ef1f84bSDavid du Colombier enum
749ef1f84bSDavid du Colombier {
759ef1f84bSDavid du Colombier Maxdmsg= 1<<16,
76*406c76faSDavid du Colombier Maxdstate= 512, /* max. open ssl conn's; must be a power of 2 */
779ef1f84bSDavid du Colombier };
789ef1f84bSDavid du Colombier
79*406c76faSDavid du Colombier static Lock dslock;
80*406c76faSDavid du Colombier static int dshiwat;
81*406c76faSDavid du Colombier static char *dsname[Maxdstate];
82*406c76faSDavid du Colombier static Dstate *dstate[Maxdstate];
83*406c76faSDavid du Colombier static char *encalgs;
84*406c76faSDavid du Colombier static char *hashalgs;
859ef1f84bSDavid du Colombier
869ef1f84bSDavid du Colombier enum{
879ef1f84bSDavid du Colombier Qtopdir = 1, /* top level directory */
889ef1f84bSDavid du Colombier Qprotodir,
899ef1f84bSDavid du Colombier Qclonus,
909ef1f84bSDavid du Colombier Qconvdir, /* directory for a conversation */
919ef1f84bSDavid du Colombier Qdata,
929ef1f84bSDavid du Colombier Qctl,
939ef1f84bSDavid du Colombier Qsecretin,
949ef1f84bSDavid du Colombier Qsecretout,
959ef1f84bSDavid du Colombier Qencalgs,
969ef1f84bSDavid du Colombier Qhashalgs,
979ef1f84bSDavid du Colombier };
989ef1f84bSDavid du Colombier
999ef1f84bSDavid du Colombier #define TYPE(x) ((x).path & 0xf)
1009ef1f84bSDavid du Colombier #define CONV(x) (((x).path >> 5)&(Maxdstate-1))
1019ef1f84bSDavid du Colombier #define QID(c, y) (((c)<<5) | (y))
1029ef1f84bSDavid du Colombier
1039ef1f84bSDavid du Colombier static void ensure(Dstate*, Block**, int);
1049ef1f84bSDavid du Colombier static void consume(Block**, uchar*, int);
1059ef1f84bSDavid du Colombier static void setsecret(OneWay*, uchar*, int);
1069ef1f84bSDavid du Colombier static Block* encryptb(Dstate*, Block*, int);
1079ef1f84bSDavid du Colombier static Block* decryptb(Dstate*, Block*);
1089ef1f84bSDavid du Colombier static Block* digestb(Dstate*, Block*, int);
1099ef1f84bSDavid du Colombier static void checkdigestb(Dstate*, Block*);
1109ef1f84bSDavid du Colombier static Chan* buftochan(char*);
1119ef1f84bSDavid du Colombier static void sslhangup(Dstate*);
1129ef1f84bSDavid du Colombier static Dstate* dsclone(Chan *c);
1139ef1f84bSDavid du Colombier static void dsnew(Chan *c, Dstate **);
1149ef1f84bSDavid du Colombier static long sslput(Dstate *s, Block * volatile b);
1159ef1f84bSDavid du Colombier
1169ef1f84bSDavid du Colombier char *sslnames[] = {
1179ef1f84bSDavid du Colombier [Qclonus] "clone",
1189ef1f84bSDavid du Colombier [Qdata] "data",
1199ef1f84bSDavid du Colombier [Qctl] "ctl",
1209ef1f84bSDavid du Colombier [Qsecretin] "secretin",
1219ef1f84bSDavid du Colombier [Qsecretout] "secretout",
1229ef1f84bSDavid du Colombier [Qencalgs] "encalgs",
1239ef1f84bSDavid du Colombier [Qhashalgs] "hashalgs",
1249ef1f84bSDavid du Colombier };
1259ef1f84bSDavid du Colombier
1269ef1f84bSDavid du Colombier static int
sslgen(Chan * c,char *,Dirtab * d,int nd,int s,Dir * dp)1279ef1f84bSDavid du Colombier sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
1289ef1f84bSDavid du Colombier {
1299ef1f84bSDavid du Colombier Qid q;
1309ef1f84bSDavid du Colombier Dstate *ds;
1319ef1f84bSDavid du Colombier char name[16], *p, *nm;
1329ef1f84bSDavid du Colombier int ft;
1339ef1f84bSDavid du Colombier
1349ef1f84bSDavid du Colombier USED(nd);
1359ef1f84bSDavid du Colombier USED(d);
1369ef1f84bSDavid du Colombier
1379ef1f84bSDavid du Colombier q.type = QTFILE;
1389ef1f84bSDavid du Colombier q.vers = 0;
1399ef1f84bSDavid du Colombier
1409ef1f84bSDavid du Colombier ft = TYPE(c->qid);
1419ef1f84bSDavid du Colombier switch(ft) {
1429ef1f84bSDavid du Colombier case Qtopdir:
1439ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
1449ef1f84bSDavid du Colombier q.path = QID(0, Qtopdir);
1459ef1f84bSDavid du Colombier q.type = QTDIR;
1469ef1f84bSDavid du Colombier devdir(c, q, "#D", 0, eve, 0555, dp);
1479ef1f84bSDavid du Colombier return 1;
1489ef1f84bSDavid du Colombier }
1499ef1f84bSDavid du Colombier if(s > 0)
1509ef1f84bSDavid du Colombier return -1;
1519ef1f84bSDavid du Colombier q.path = QID(0, Qprotodir);
1529ef1f84bSDavid du Colombier q.type = QTDIR;
1539ef1f84bSDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1549ef1f84bSDavid du Colombier return 1;
1559ef1f84bSDavid du Colombier case Qprotodir:
1569ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
1579ef1f84bSDavid du Colombier q.path = QID(0, Qtopdir);
1589ef1f84bSDavid du Colombier q.type = QTDIR;
1599ef1f84bSDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp);
1609ef1f84bSDavid du Colombier return 1;
1619ef1f84bSDavid du Colombier }
1629ef1f84bSDavid du Colombier if(s < dshiwat) {
1639ef1f84bSDavid du Colombier q.path = QID(s, Qconvdir);
1649ef1f84bSDavid du Colombier q.type = QTDIR;
1659ef1f84bSDavid du Colombier ds = dstate[s];
1669ef1f84bSDavid du Colombier if(ds != 0)
1679ef1f84bSDavid du Colombier nm = ds->user;
1689ef1f84bSDavid du Colombier else
1699ef1f84bSDavid du Colombier nm = eve;
1709ef1f84bSDavid du Colombier if(dsname[s] == nil){
171*406c76faSDavid du Colombier snprint(name, sizeof name, "%d", s);
1729ef1f84bSDavid du Colombier kstrdup(&dsname[s], name);
1739ef1f84bSDavid du Colombier }
1749ef1f84bSDavid du Colombier devdir(c, q, dsname[s], 0, nm, 0555, dp);
1759ef1f84bSDavid du Colombier return 1;
1769ef1f84bSDavid du Colombier }
1779ef1f84bSDavid du Colombier if(s > dshiwat)
1789ef1f84bSDavid du Colombier return -1;
1799ef1f84bSDavid du Colombier q.path = QID(0, Qclonus);
1809ef1f84bSDavid du Colombier devdir(c, q, "clone", 0, eve, 0555, dp);
1819ef1f84bSDavid du Colombier return 1;
1829ef1f84bSDavid du Colombier case Qconvdir:
1839ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
1849ef1f84bSDavid du Colombier q.path = QID(0, Qprotodir);
1859ef1f84bSDavid du Colombier q.type = QTDIR;
1869ef1f84bSDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1879ef1f84bSDavid du Colombier return 1;
1889ef1f84bSDavid du Colombier }
1899ef1f84bSDavid du Colombier ds = dstate[CONV(c->qid)];
1909ef1f84bSDavid du Colombier if(ds != 0)
1919ef1f84bSDavid du Colombier nm = ds->user;
1929ef1f84bSDavid du Colombier else
1939ef1f84bSDavid du Colombier nm = eve;
1949ef1f84bSDavid du Colombier switch(s) {
1959ef1f84bSDavid du Colombier default:
1969ef1f84bSDavid du Colombier return -1;
1979ef1f84bSDavid du Colombier case 0:
1989ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qctl);
1999ef1f84bSDavid du Colombier p = "ctl";
2009ef1f84bSDavid du Colombier break;
2019ef1f84bSDavid du Colombier case 1:
2029ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qdata);
2039ef1f84bSDavid du Colombier p = "data";
2049ef1f84bSDavid du Colombier break;
2059ef1f84bSDavid du Colombier case 2:
2069ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qsecretin);
2079ef1f84bSDavid du Colombier p = "secretin";
2089ef1f84bSDavid du Colombier break;
2099ef1f84bSDavid du Colombier case 3:
2109ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qsecretout);
2119ef1f84bSDavid du Colombier p = "secretout";
2129ef1f84bSDavid du Colombier break;
2139ef1f84bSDavid du Colombier case 4:
2149ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qencalgs);
2159ef1f84bSDavid du Colombier p = "encalgs";
2169ef1f84bSDavid du Colombier break;
2179ef1f84bSDavid du Colombier case 5:
2189ef1f84bSDavid du Colombier q.path = QID(CONV(c->qid), Qhashalgs);
2199ef1f84bSDavid du Colombier p = "hashalgs";
2209ef1f84bSDavid du Colombier break;
2219ef1f84bSDavid du Colombier }
2229ef1f84bSDavid du Colombier devdir(c, q, p, 0, nm, 0660, dp);
2239ef1f84bSDavid du Colombier return 1;
2249ef1f84bSDavid du Colombier case Qclonus:
2259ef1f84bSDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
2269ef1f84bSDavid du Colombier return 1;
2279ef1f84bSDavid du Colombier default:
2289ef1f84bSDavid du Colombier ds = dstate[CONV(c->qid)];
2299ef1f84bSDavid du Colombier if(ds != 0)
2309ef1f84bSDavid du Colombier nm = ds->user;
2319ef1f84bSDavid du Colombier else
2329ef1f84bSDavid du Colombier nm = eve;
2339ef1f84bSDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
2349ef1f84bSDavid du Colombier return 1;
2359ef1f84bSDavid du Colombier }
2369ef1f84bSDavid du Colombier }
2379ef1f84bSDavid du Colombier
2389ef1f84bSDavid du Colombier static Chan*
sslattach(char * spec)2399ef1f84bSDavid du Colombier sslattach(char *spec)
2409ef1f84bSDavid du Colombier {
2419ef1f84bSDavid du Colombier Chan *c;
2429ef1f84bSDavid du Colombier
2439ef1f84bSDavid du Colombier c = devattach('D', spec);
2449ef1f84bSDavid du Colombier c->qid.path = QID(0, Qtopdir);
2459ef1f84bSDavid du Colombier c->qid.vers = 0;
2469ef1f84bSDavid du Colombier c->qid.type = QTDIR;
2479ef1f84bSDavid du Colombier return c;
2489ef1f84bSDavid du Colombier }
2499ef1f84bSDavid du Colombier
2509ef1f84bSDavid du Colombier static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)2519ef1f84bSDavid du Colombier sslwalk(Chan *c, Chan *nc, char **name, int nname)
2529ef1f84bSDavid du Colombier {
2539ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, sslgen);
2549ef1f84bSDavid du Colombier }
2559ef1f84bSDavid du Colombier
2569ef1f84bSDavid du Colombier static long
sslstat(Chan * c,uchar * db,long n)2579ef1f84bSDavid du Colombier sslstat(Chan *c, uchar *db, long n)
2589ef1f84bSDavid du Colombier {
2599ef1f84bSDavid du Colombier return devstat(c, db, n, nil, 0, sslgen);
2609ef1f84bSDavid du Colombier }
2619ef1f84bSDavid du Colombier
2629ef1f84bSDavid du Colombier static Chan*
sslopen(Chan * c,int omode)2639ef1f84bSDavid du Colombier sslopen(Chan *c, int omode)
2649ef1f84bSDavid du Colombier {
2659ef1f84bSDavid du Colombier Dstate *s, **pp;
2669ef1f84bSDavid du Colombier int perm;
2679ef1f84bSDavid du Colombier int ft;
2689ef1f84bSDavid du Colombier
2699ef1f84bSDavid du Colombier perm = 0;
2709ef1f84bSDavid du Colombier omode &= 3;
2719ef1f84bSDavid du Colombier switch(omode) {
2729ef1f84bSDavid du Colombier case OREAD:
2739ef1f84bSDavid du Colombier perm = 4;
2749ef1f84bSDavid du Colombier break;
2759ef1f84bSDavid du Colombier case OWRITE:
2769ef1f84bSDavid du Colombier perm = 2;
2779ef1f84bSDavid du Colombier break;
2789ef1f84bSDavid du Colombier case ORDWR:
2799ef1f84bSDavid du Colombier perm = 6;
2809ef1f84bSDavid du Colombier break;
2819ef1f84bSDavid du Colombier }
2829ef1f84bSDavid du Colombier
2839ef1f84bSDavid du Colombier ft = TYPE(c->qid);
2849ef1f84bSDavid du Colombier switch(ft) {
2859ef1f84bSDavid du Colombier default:
2869ef1f84bSDavid du Colombier panic("sslopen");
2879ef1f84bSDavid du Colombier case Qtopdir:
2889ef1f84bSDavid du Colombier case Qprotodir:
2899ef1f84bSDavid du Colombier case Qconvdir:
2909ef1f84bSDavid du Colombier if(omode != OREAD)
2919ef1f84bSDavid du Colombier error(Eperm);
2929ef1f84bSDavid du Colombier break;
2939ef1f84bSDavid du Colombier case Qclonus:
2949ef1f84bSDavid du Colombier s = dsclone(c);
2959ef1f84bSDavid du Colombier if(s == 0)
2969ef1f84bSDavid du Colombier error(Enodev);
2979ef1f84bSDavid du Colombier break;
2989ef1f84bSDavid du Colombier case Qctl:
2999ef1f84bSDavid du Colombier case Qdata:
3009ef1f84bSDavid du Colombier case Qsecretin:
3019ef1f84bSDavid du Colombier case Qsecretout:
3029ef1f84bSDavid du Colombier if(waserror()) {
3039ef1f84bSDavid du Colombier unlock(&dslock);
3049ef1f84bSDavid du Colombier nexterror();
3059ef1f84bSDavid du Colombier }
3069ef1f84bSDavid du Colombier lock(&dslock);
3079ef1f84bSDavid du Colombier pp = &dstate[CONV(c->qid)];
3089ef1f84bSDavid du Colombier s = *pp;
3099ef1f84bSDavid du Colombier if(s == 0)
3109ef1f84bSDavid du Colombier dsnew(c, pp);
3119ef1f84bSDavid du Colombier else {
3129ef1f84bSDavid du Colombier if((perm & (s->perm>>6)) != perm
3139ef1f84bSDavid du Colombier && (strcmp(up->user, s->user) != 0
3149ef1f84bSDavid du Colombier || (perm & s->perm) != perm))
3159ef1f84bSDavid du Colombier error(Eperm);
3169ef1f84bSDavid du Colombier
3179ef1f84bSDavid du Colombier s->ref++;
3189ef1f84bSDavid du Colombier }
3199ef1f84bSDavid du Colombier unlock(&dslock);
3209ef1f84bSDavid du Colombier poperror();
3219ef1f84bSDavid du Colombier break;
3229ef1f84bSDavid du Colombier case Qencalgs:
3239ef1f84bSDavid du Colombier case Qhashalgs:
3249ef1f84bSDavid du Colombier if(omode != OREAD)
3259ef1f84bSDavid du Colombier error(Eperm);
3269ef1f84bSDavid du Colombier break;
3279ef1f84bSDavid du Colombier }
3289ef1f84bSDavid du Colombier c->mode = openmode(omode);
3299ef1f84bSDavid du Colombier c->flag |= COPEN;
3309ef1f84bSDavid du Colombier c->offset = 0;
3319ef1f84bSDavid du Colombier return c;
3329ef1f84bSDavid du Colombier }
3339ef1f84bSDavid du Colombier
3349ef1f84bSDavid du Colombier static long
sslwstat(Chan * c,uchar * db,long n)3359ef1f84bSDavid du Colombier sslwstat(Chan *c, uchar *db, long n)
3369ef1f84bSDavid du Colombier {
3379ef1f84bSDavid du Colombier Dir *dir;
3389ef1f84bSDavid du Colombier Dstate *s;
3399ef1f84bSDavid du Colombier int l;
3409ef1f84bSDavid du Colombier
3419ef1f84bSDavid du Colombier s = dstate[CONV(c->qid)];
3429ef1f84bSDavid du Colombier if(s == 0)
3439ef1f84bSDavid du Colombier error(Ebadusefd);
3449ef1f84bSDavid du Colombier if(strcmp(s->user, up->user) != 0)
3459ef1f84bSDavid du Colombier error(Eperm);
3469ef1f84bSDavid du Colombier
3479ef1f84bSDavid du Colombier dir = smalloc(sizeof(Dir)+n);
3489ef1f84bSDavid du Colombier l = convM2D(db, n, &dir[0], (char*)&dir[1]);
3499ef1f84bSDavid du Colombier if(l == 0){
3509ef1f84bSDavid du Colombier free(dir);
3519ef1f84bSDavid du Colombier error(Eshortstat);
3529ef1f84bSDavid du Colombier }
3539ef1f84bSDavid du Colombier
3549ef1f84bSDavid du Colombier if(!emptystr(dir->uid))
3559ef1f84bSDavid du Colombier kstrdup(&s->user, dir->uid);
3569ef1f84bSDavid du Colombier if(dir->mode != ~0UL)
3579ef1f84bSDavid du Colombier s->perm = dir->mode;
3589ef1f84bSDavid du Colombier
3599ef1f84bSDavid du Colombier free(dir);
3609ef1f84bSDavid du Colombier return l;
3619ef1f84bSDavid du Colombier }
3629ef1f84bSDavid du Colombier
3639ef1f84bSDavid du Colombier static void
sslclose(Chan * c)3649ef1f84bSDavid du Colombier sslclose(Chan *c)
3659ef1f84bSDavid du Colombier {
3669ef1f84bSDavid du Colombier Dstate *s;
3679ef1f84bSDavid du Colombier int ft;
3689ef1f84bSDavid du Colombier
3699ef1f84bSDavid du Colombier ft = TYPE(c->qid);
3709ef1f84bSDavid du Colombier switch(ft) {
3719ef1f84bSDavid du Colombier case Qctl:
3729ef1f84bSDavid du Colombier case Qdata:
3739ef1f84bSDavid du Colombier case Qsecretin:
3749ef1f84bSDavid du Colombier case Qsecretout:
3759ef1f84bSDavid du Colombier if((c->flag & COPEN) == 0)
3769ef1f84bSDavid du Colombier break;
3779ef1f84bSDavid du Colombier
3789ef1f84bSDavid du Colombier s = dstate[CONV(c->qid)];
3799ef1f84bSDavid du Colombier if(s == 0)
3809ef1f84bSDavid du Colombier break;
3819ef1f84bSDavid du Colombier
3829ef1f84bSDavid du Colombier lock(&dslock);
3839ef1f84bSDavid du Colombier if(--s->ref > 0) {
3849ef1f84bSDavid du Colombier unlock(&dslock);
3859ef1f84bSDavid du Colombier break;
3869ef1f84bSDavid du Colombier }
3879ef1f84bSDavid du Colombier dstate[CONV(c->qid)] = 0;
3889ef1f84bSDavid du Colombier unlock(&dslock);
3899ef1f84bSDavid du Colombier
3909ef1f84bSDavid du Colombier if(s->user != nil)
3919ef1f84bSDavid du Colombier free(s->user);
3929ef1f84bSDavid du Colombier sslhangup(s);
3939ef1f84bSDavid du Colombier if(s->c)
3949ef1f84bSDavid du Colombier cclose(s->c);
3959ef1f84bSDavid du Colombier if(s->in.secret)
3969ef1f84bSDavid du Colombier free(s->in.secret);
3979ef1f84bSDavid du Colombier if(s->out.secret)
3989ef1f84bSDavid du Colombier free(s->out.secret);
3999ef1f84bSDavid du Colombier if(s->in.state)
4009ef1f84bSDavid du Colombier free(s->in.state);
4019ef1f84bSDavid du Colombier if(s->out.state)
4029ef1f84bSDavid du Colombier free(s->out.state);
4039ef1f84bSDavid du Colombier free(s);
4049ef1f84bSDavid du Colombier
4059ef1f84bSDavid du Colombier }
4069ef1f84bSDavid du Colombier }
4079ef1f84bSDavid du Colombier
4089ef1f84bSDavid du Colombier /*
4099ef1f84bSDavid du Colombier * make sure we have at least 'n' bytes in list 'l'
4109ef1f84bSDavid du Colombier */
4119ef1f84bSDavid du Colombier static void
ensure(Dstate * s,Block ** l,int n)4129ef1f84bSDavid du Colombier ensure(Dstate *s, Block **l, int n)
4139ef1f84bSDavid du Colombier {
4149ef1f84bSDavid du Colombier int sofar, i;
4159ef1f84bSDavid du Colombier Block *b, *bl;
4169ef1f84bSDavid du Colombier
4179ef1f84bSDavid du Colombier sofar = 0;
4189ef1f84bSDavid du Colombier for(b = *l; b; b = b->next){
4199ef1f84bSDavid du Colombier sofar += BLEN(b);
4209ef1f84bSDavid du Colombier if(sofar >= n)
4219ef1f84bSDavid du Colombier return;
4229ef1f84bSDavid du Colombier l = &b->next;
4239ef1f84bSDavid du Colombier }
4249ef1f84bSDavid du Colombier
4259ef1f84bSDavid du Colombier while(sofar < n){
4269ef1f84bSDavid du Colombier bl = s->c->dev->bread(s->c, Maxdmsg, 0);
4279ef1f84bSDavid du Colombier if(bl == 0)
4289ef1f84bSDavid du Colombier nexterror();
4299ef1f84bSDavid du Colombier *l = bl;
4309ef1f84bSDavid du Colombier i = 0;
4319ef1f84bSDavid du Colombier for(b = bl; b; b = b->next){
4329ef1f84bSDavid du Colombier i += BLEN(b);
4339ef1f84bSDavid du Colombier l = &b->next;
4349ef1f84bSDavid du Colombier }
4359ef1f84bSDavid du Colombier if(i == 0)
4369ef1f84bSDavid du Colombier error(Ehungup);
4379ef1f84bSDavid du Colombier sofar += i;
4389ef1f84bSDavid du Colombier }
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier
4419ef1f84bSDavid du Colombier /*
4429ef1f84bSDavid du Colombier * copy 'n' bytes from 'l' into 'p' and free
4439ef1f84bSDavid du Colombier * the bytes in 'l'
4449ef1f84bSDavid du Colombier */
4459ef1f84bSDavid du Colombier static void
consume(Block ** l,uchar * p,int n)4469ef1f84bSDavid du Colombier consume(Block **l, uchar *p, int n)
4479ef1f84bSDavid du Colombier {
4489ef1f84bSDavid du Colombier Block *b;
4499ef1f84bSDavid du Colombier int i;
4509ef1f84bSDavid du Colombier
4519ef1f84bSDavid du Colombier for(; *l && n > 0; n -= i){
4529ef1f84bSDavid du Colombier b = *l;
4539ef1f84bSDavid du Colombier i = BLEN(b);
4549ef1f84bSDavid du Colombier if(i > n)
4559ef1f84bSDavid du Colombier i = n;
4569ef1f84bSDavid du Colombier memmove(p, b->rp, i);
4579ef1f84bSDavid du Colombier b->rp += i;
4589ef1f84bSDavid du Colombier p += i;
4599ef1f84bSDavid du Colombier if(BLEN(b) < 0)
4609ef1f84bSDavid du Colombier panic("consume");
4619ef1f84bSDavid du Colombier if(BLEN(b))
4629ef1f84bSDavid du Colombier break;
4639ef1f84bSDavid du Colombier *l = b->next;
4649ef1f84bSDavid du Colombier freeb(b);
4659ef1f84bSDavid du Colombier }
4669ef1f84bSDavid du Colombier }
4679ef1f84bSDavid du Colombier
4689ef1f84bSDavid du Colombier /*
4699ef1f84bSDavid du Colombier * give back n bytes
4709ef1f84bSDavid du Colombier static void
4719ef1f84bSDavid du Colombier regurgitate(Dstate *s, uchar *p, int n)
4729ef1f84bSDavid du Colombier {
4739ef1f84bSDavid du Colombier Block *b;
4749ef1f84bSDavid du Colombier
4759ef1f84bSDavid du Colombier if(n <= 0)
4769ef1f84bSDavid du Colombier return;
4779ef1f84bSDavid du Colombier b = s->unprocessed;
4789ef1f84bSDavid du Colombier if(s->unprocessed == nil || b->rp - b->base < n) {
4799ef1f84bSDavid du Colombier b = allocb(n);
4809ef1f84bSDavid du Colombier memmove(b->wp, p, n);
4819ef1f84bSDavid du Colombier b->wp += n;
4829ef1f84bSDavid du Colombier b->next = s->unprocessed;
4839ef1f84bSDavid du Colombier s->unprocessed = b;
4849ef1f84bSDavid du Colombier } else {
4859ef1f84bSDavid du Colombier b->rp -= n;
4869ef1f84bSDavid du Colombier memmove(b->rp, p, n);
4879ef1f84bSDavid du Colombier }
4889ef1f84bSDavid du Colombier }
4899ef1f84bSDavid du Colombier */
4909ef1f84bSDavid du Colombier
4919ef1f84bSDavid du Colombier /*
4929ef1f84bSDavid du Colombier * remove at most n bytes from the queue, if discard is set
4939ef1f84bSDavid du Colombier * dump the remainder
4949ef1f84bSDavid du Colombier */
4959ef1f84bSDavid du Colombier static Block*
qtake(Block ** l,int n,int discard)4969ef1f84bSDavid du Colombier qtake(Block **l, int n, int discard)
4979ef1f84bSDavid du Colombier {
4989ef1f84bSDavid du Colombier Block *nb, *b, *first;
4999ef1f84bSDavid du Colombier int i;
5009ef1f84bSDavid du Colombier
5019ef1f84bSDavid du Colombier first = *l;
5029ef1f84bSDavid du Colombier for(b = first; b; b = b->next){
5039ef1f84bSDavid du Colombier i = BLEN(b);
5049ef1f84bSDavid du Colombier if(i == n){
5059ef1f84bSDavid du Colombier if(discard){
5069ef1f84bSDavid du Colombier freeblist(b->next);
5079ef1f84bSDavid du Colombier *l = 0;
5089ef1f84bSDavid du Colombier } else
5099ef1f84bSDavid du Colombier *l = b->next;
5109ef1f84bSDavid du Colombier b->next = 0;
5119ef1f84bSDavid du Colombier return first;
5129ef1f84bSDavid du Colombier } else if(i > n){
5139ef1f84bSDavid du Colombier i -= n;
5149ef1f84bSDavid du Colombier if(discard){
5159ef1f84bSDavid du Colombier freeblist(b->next);
5169ef1f84bSDavid du Colombier b->wp -= i;
5179ef1f84bSDavid du Colombier *l = 0;
5189ef1f84bSDavid du Colombier } else {
5199ef1f84bSDavid du Colombier nb = allocb(i);
5209ef1f84bSDavid du Colombier memmove(nb->wp, b->rp+n, i);
5219ef1f84bSDavid du Colombier nb->wp += i;
5229ef1f84bSDavid du Colombier b->wp -= i;
5239ef1f84bSDavid du Colombier nb->next = b->next;
5249ef1f84bSDavid du Colombier *l = nb;
5259ef1f84bSDavid du Colombier }
5269ef1f84bSDavid du Colombier b->next = 0;
5279ef1f84bSDavid du Colombier if(BLEN(b) < 0)
5289ef1f84bSDavid du Colombier panic("qtake");
5299ef1f84bSDavid du Colombier return first;
5309ef1f84bSDavid du Colombier } else
5319ef1f84bSDavid du Colombier n -= i;
5329ef1f84bSDavid du Colombier if(BLEN(b) < 0)
5339ef1f84bSDavid du Colombier panic("qtake");
5349ef1f84bSDavid du Colombier }
5359ef1f84bSDavid du Colombier *l = 0;
5369ef1f84bSDavid du Colombier return first;
5379ef1f84bSDavid du Colombier }
5389ef1f84bSDavid du Colombier
5399ef1f84bSDavid du Colombier /*
5409ef1f84bSDavid du Colombier * We can't let Eintr's lose data since the program
5419ef1f84bSDavid du Colombier * doing the read may be able to handle it. The only
5429ef1f84bSDavid du Colombier * places Eintr is possible is during the read's in consume.
5439ef1f84bSDavid du Colombier * Therefore, we make sure we can always put back the bytes
5449ef1f84bSDavid du Colombier * consumed before the last ensure.
5459ef1f84bSDavid du Colombier */
5469ef1f84bSDavid du Colombier static Block*
sslbread(Chan * c,long n,vlong)5479ef1f84bSDavid du Colombier sslbread(Chan *c, long n, vlong)
5489ef1f84bSDavid du Colombier {
5499ef1f84bSDavid du Colombier Dstate * volatile s;
5509ef1f84bSDavid du Colombier Block *b;
5519ef1f84bSDavid du Colombier uchar consumed[3], *p;
5529ef1f84bSDavid du Colombier int toconsume;
5539ef1f84bSDavid du Colombier int len, pad;
5549ef1f84bSDavid du Colombier
5559ef1f84bSDavid du Colombier s = dstate[CONV(c->qid)];
5569ef1f84bSDavid du Colombier if(s == 0)
5579ef1f84bSDavid du Colombier panic("sslbread");
5589ef1f84bSDavid du Colombier if(s->state == Sincomplete)
5599ef1f84bSDavid du Colombier error(Ebadusefd);
5609ef1f84bSDavid du Colombier
5619ef1f84bSDavid du Colombier qlock(&s->in.q);
5629ef1f84bSDavid du Colombier if(waserror()){
5639ef1f84bSDavid du Colombier qunlock(&s->in.q);
5649ef1f84bSDavid du Colombier nexterror();
5659ef1f84bSDavid du Colombier }
5669ef1f84bSDavid du Colombier
5679ef1f84bSDavid du Colombier if(s->processed == 0){
5689ef1f84bSDavid du Colombier /*
5699ef1f84bSDavid du Colombier * Read in the whole message. Until we've got it all,
5709ef1f84bSDavid du Colombier * it stays on s->unprocessed, so that if we get Eintr,
5719ef1f84bSDavid du Colombier * we'll pick up where we left off.
5729ef1f84bSDavid du Colombier */
5739ef1f84bSDavid du Colombier ensure(s, &s->unprocessed, 3);
5749ef1f84bSDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 2);
5759ef1f84bSDavid du Colombier p = s->unprocessed->rp;
5769ef1f84bSDavid du Colombier if(p[0] & 0x80){
5779ef1f84bSDavid du Colombier len = ((p[0] & 0x7f)<<8) | p[1];
5789ef1f84bSDavid du Colombier ensure(s, &s->unprocessed, len);
5799ef1f84bSDavid du Colombier pad = 0;
5809ef1f84bSDavid du Colombier toconsume = 2;
5819ef1f84bSDavid du Colombier } else {
5829ef1f84bSDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 3);
5839ef1f84bSDavid du Colombier len = ((p[0] & 0x3f)<<8) | p[1];
5849ef1f84bSDavid du Colombier pad = p[2];
5859ef1f84bSDavid du Colombier if(pad > len){
5869ef1f84bSDavid du Colombier print("pad %d buf len %d\n", pad, len);
5879ef1f84bSDavid du Colombier error("bad pad in ssl message");
5889ef1f84bSDavid du Colombier }
5899ef1f84bSDavid du Colombier toconsume = 3;
5909ef1f84bSDavid du Colombier }
5919ef1f84bSDavid du Colombier ensure(s, &s->unprocessed, toconsume+len);
5929ef1f84bSDavid du Colombier
5939ef1f84bSDavid du Colombier /* skip header */
5949ef1f84bSDavid du Colombier consume(&s->unprocessed, consumed, toconsume);
5959ef1f84bSDavid du Colombier
5969ef1f84bSDavid du Colombier /* grab the next message and decode/decrypt it */
5979ef1f84bSDavid du Colombier b = qtake(&s->unprocessed, len, 0);
5989ef1f84bSDavid du Colombier
5999ef1f84bSDavid du Colombier if(blocklen(b) != len)
6009ef1f84bSDavid du Colombier print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
6019ef1f84bSDavid du Colombier
6029ef1f84bSDavid du Colombier if(waserror()){
6039ef1f84bSDavid du Colombier qunlock(&s->in.ctlq);
6049ef1f84bSDavid du Colombier if(b != nil)
6059ef1f84bSDavid du Colombier freeb(b);
6069ef1f84bSDavid du Colombier nexterror();
6079ef1f84bSDavid du Colombier }
6089ef1f84bSDavid du Colombier qlock(&s->in.ctlq);
6099ef1f84bSDavid du Colombier switch(s->state){
6109ef1f84bSDavid du Colombier case Sencrypting:
6119ef1f84bSDavid du Colombier if(b == nil)
6129ef1f84bSDavid du Colombier error("ssl message too short (encrypting)");
6139ef1f84bSDavid du Colombier b = decryptb(s, b);
6149ef1f84bSDavid du Colombier break;
6159ef1f84bSDavid du Colombier case Sdigesting:
6169ef1f84bSDavid du Colombier b = pullupblock(b, s->diglen);
6179ef1f84bSDavid du Colombier if(b == nil)
6189ef1f84bSDavid du Colombier error("ssl message too short (digesting)");
6199ef1f84bSDavid du Colombier checkdigestb(s, b);
6209ef1f84bSDavid du Colombier pullblock(&b, s->diglen);
6219ef1f84bSDavid du Colombier len -= s->diglen;
6229ef1f84bSDavid du Colombier break;
6239ef1f84bSDavid du Colombier case Sdigenc:
6249ef1f84bSDavid du Colombier b = decryptb(s, b);
6259ef1f84bSDavid du Colombier b = pullupblock(b, s->diglen);
6269ef1f84bSDavid du Colombier if(b == nil)
6279ef1f84bSDavid du Colombier error("ssl message too short (dig+enc)");
6289ef1f84bSDavid du Colombier checkdigestb(s, b);
6299ef1f84bSDavid du Colombier pullblock(&b, s->diglen);
6309ef1f84bSDavid du Colombier len -= s->diglen;
6319ef1f84bSDavid du Colombier break;
6329ef1f84bSDavid du Colombier }
6339ef1f84bSDavid du Colombier
6349ef1f84bSDavid du Colombier /* remove pad */
6359ef1f84bSDavid du Colombier if(pad)
6369ef1f84bSDavid du Colombier s->processed = qtake(&b, len - pad, 1);
6379ef1f84bSDavid du Colombier else
6389ef1f84bSDavid du Colombier s->processed = b;
6399ef1f84bSDavid du Colombier b = nil;
6409ef1f84bSDavid du Colombier s->in.mid++;
6419ef1f84bSDavid du Colombier qunlock(&s->in.ctlq);
6429ef1f84bSDavid du Colombier poperror();
6439ef1f84bSDavid du Colombier }
6449ef1f84bSDavid du Colombier
6459ef1f84bSDavid du Colombier /* return at most what was asked for */
6469ef1f84bSDavid du Colombier b = qtake(&s->processed, n, 0);
6479ef1f84bSDavid du Colombier
6489ef1f84bSDavid du Colombier qunlock(&s->in.q);
6499ef1f84bSDavid du Colombier poperror();
6509ef1f84bSDavid du Colombier
6519ef1f84bSDavid du Colombier return b;
6529ef1f84bSDavid du Colombier }
6539ef1f84bSDavid du Colombier
6549ef1f84bSDavid du Colombier static long
sslread(Chan * c,void * a,long n,vlong off)6559ef1f84bSDavid du Colombier sslread(Chan *c, void *a, long n, vlong off)
6569ef1f84bSDavid du Colombier {
6579ef1f84bSDavid du Colombier Block * volatile b;
6589ef1f84bSDavid du Colombier Block *nb;
6599ef1f84bSDavid du Colombier uchar *va;
6609ef1f84bSDavid du Colombier int i;
6619ef1f84bSDavid du Colombier char buf[128];
6629ef1f84bSDavid du Colombier long offset;
6639ef1f84bSDavid du Colombier int ft;
6649ef1f84bSDavid du Colombier
6659ef1f84bSDavid du Colombier if(c->qid.type & QTDIR)
6669ef1f84bSDavid du Colombier return devdirread(c, a, n, 0, 0, sslgen);
6679ef1f84bSDavid du Colombier
6689ef1f84bSDavid du Colombier ft = TYPE(c->qid);
6699ef1f84bSDavid du Colombier offset = off;
6709ef1f84bSDavid du Colombier switch(ft) {
6719ef1f84bSDavid du Colombier default:
6729ef1f84bSDavid du Colombier error(Ebadusefd);
6739ef1f84bSDavid du Colombier case Qctl:
6749ef1f84bSDavid du Colombier ft = CONV(c->qid);
675*406c76faSDavid du Colombier snprint(buf, sizeof buf, "%d", ft);
6769ef1f84bSDavid du Colombier return readstr(offset, a, n, buf);
6779ef1f84bSDavid du Colombier case Qdata:
6789ef1f84bSDavid du Colombier b = sslbread(c, n, offset);
6799ef1f84bSDavid du Colombier break;
6809ef1f84bSDavid du Colombier case Qencalgs:
6819ef1f84bSDavid du Colombier return readstr(offset, a, n, encalgs);
6829ef1f84bSDavid du Colombier break;
6839ef1f84bSDavid du Colombier case Qhashalgs:
6849ef1f84bSDavid du Colombier return readstr(offset, a, n, hashalgs);
6859ef1f84bSDavid du Colombier break;
6869ef1f84bSDavid du Colombier }
6879ef1f84bSDavid du Colombier
6889ef1f84bSDavid du Colombier if(waserror()){
6899ef1f84bSDavid du Colombier freeblist(b);
6909ef1f84bSDavid du Colombier nexterror();
6919ef1f84bSDavid du Colombier }
6929ef1f84bSDavid du Colombier
6939ef1f84bSDavid du Colombier n = 0;
6949ef1f84bSDavid du Colombier va = a;
6959ef1f84bSDavid du Colombier for(nb = b; nb; nb = nb->next){
6969ef1f84bSDavid du Colombier i = BLEN(nb);
6979ef1f84bSDavid du Colombier memmove(va+n, nb->rp, i);
6989ef1f84bSDavid du Colombier n += i;
6999ef1f84bSDavid du Colombier }
7009ef1f84bSDavid du Colombier
7019ef1f84bSDavid du Colombier freeblist(b);
7029ef1f84bSDavid du Colombier poperror();
7039ef1f84bSDavid du Colombier
7049ef1f84bSDavid du Colombier return n;
7059ef1f84bSDavid du Colombier }
7069ef1f84bSDavid du Colombier
7079ef1f84bSDavid du Colombier /*
7089ef1f84bSDavid du Colombier * this algorithm doesn't have to be great since we're just
7099ef1f84bSDavid du Colombier * trying to obscure the block fill
7109ef1f84bSDavid du Colombier */
7119ef1f84bSDavid du Colombier static void
randfill(uchar * buf,int len)7129ef1f84bSDavid du Colombier randfill(uchar *buf, int len)
7139ef1f84bSDavid du Colombier {
7149ef1f84bSDavid du Colombier while(len-- > 0)
7159ef1f84bSDavid du Colombier *buf++ = nrand(256);
7169ef1f84bSDavid du Colombier }
7179ef1f84bSDavid du Colombier
7189ef1f84bSDavid du Colombier static long
sslbwrite(Chan * c,Block * b,vlong)7199ef1f84bSDavid du Colombier sslbwrite(Chan *c, Block *b, vlong)
7209ef1f84bSDavid du Colombier {
7219ef1f84bSDavid du Colombier Dstate * volatile s;
7229ef1f84bSDavid du Colombier long rv;
7239ef1f84bSDavid du Colombier
7249ef1f84bSDavid du Colombier s = dstate[CONV(c->qid)];
7259ef1f84bSDavid du Colombier if(s == nil)
7269ef1f84bSDavid du Colombier panic("sslbwrite");
7279ef1f84bSDavid du Colombier
7289ef1f84bSDavid du Colombier if(s->state == Sincomplete){
7299ef1f84bSDavid du Colombier freeb(b);
7309ef1f84bSDavid du Colombier error(Ebadusefd);
7319ef1f84bSDavid du Colombier }
7329ef1f84bSDavid du Colombier
7339ef1f84bSDavid du Colombier /* lock so split writes won't interleave */
7349ef1f84bSDavid du Colombier if(waserror()){
7359ef1f84bSDavid du Colombier qunlock(&s->out.q);
7369ef1f84bSDavid du Colombier nexterror();
7379ef1f84bSDavid du Colombier }
7389ef1f84bSDavid du Colombier qlock(&s->out.q);
7399ef1f84bSDavid du Colombier
7409ef1f84bSDavid du Colombier rv = sslput(s, b);
7419ef1f84bSDavid du Colombier
7429ef1f84bSDavid du Colombier poperror();
7439ef1f84bSDavid du Colombier qunlock(&s->out.q);
7449ef1f84bSDavid du Colombier
7459ef1f84bSDavid du Colombier return rv;
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier
7489ef1f84bSDavid du Colombier /*
7499ef1f84bSDavid du Colombier * use SSL record format, add in count, digest and/or encrypt.
7509ef1f84bSDavid du Colombier * the write is interruptable. if it is interrupted, we'll
7519ef1f84bSDavid du Colombier * get out of sync with the far side. not much we can do about
7529ef1f84bSDavid du Colombier * it since we don't know if any bytes have been written.
7539ef1f84bSDavid du Colombier */
7549ef1f84bSDavid du Colombier static long
sslput(Dstate * s,Block * volatile b)7559ef1f84bSDavid du Colombier sslput(Dstate *s, Block * volatile b)
7569ef1f84bSDavid du Colombier {
7579ef1f84bSDavid du Colombier Block *nb;
7589ef1f84bSDavid du Colombier int h, n, l, pad, rv;
7599ef1f84bSDavid du Colombier uchar *p;
7609ef1f84bSDavid du Colombier int offset;
7619ef1f84bSDavid du Colombier
7629ef1f84bSDavid du Colombier if(waserror()){
7639ef1f84bSDavid du Colombier if(b != nil)
764*406c76faSDavid du Colombier freeb(b);
7659ef1f84bSDavid du Colombier nexterror();
7669ef1f84bSDavid du Colombier }
7679ef1f84bSDavid du Colombier
7689ef1f84bSDavid du Colombier rv = 0;
7699ef1f84bSDavid du Colombier while(b != nil){
7709ef1f84bSDavid du Colombier l = n = BLEN(b);
7719ef1f84bSDavid du Colombier h = s->diglen + 2;
7729ef1f84bSDavid du Colombier
7739ef1f84bSDavid du Colombier /* trim to maximum block size */
7749ef1f84bSDavid du Colombier pad = 0;
7759ef1f84bSDavid du Colombier if(l > s->max){
7769ef1f84bSDavid du Colombier l = s->max;
7779ef1f84bSDavid du Colombier } else if(s->blocklen != 1){
7789ef1f84bSDavid du Colombier pad = (l + s->diglen)%s->blocklen;
7799ef1f84bSDavid du Colombier if(pad){
7809ef1f84bSDavid du Colombier if(l > s->maxpad){
7819ef1f84bSDavid du Colombier pad = 0;
7829ef1f84bSDavid du Colombier l = s->maxpad;
7839ef1f84bSDavid du Colombier } else {
7849ef1f84bSDavid du Colombier pad = s->blocklen - pad;
7859ef1f84bSDavid du Colombier h++;
7869ef1f84bSDavid du Colombier }
7879ef1f84bSDavid du Colombier }
7889ef1f84bSDavid du Colombier }
7899ef1f84bSDavid du Colombier
7909ef1f84bSDavid du Colombier rv += l;
7919ef1f84bSDavid du Colombier if(l != n){
7929ef1f84bSDavid du Colombier nb = allocb(l + h + pad);
7939ef1f84bSDavid du Colombier memmove(nb->wp + h, b->rp, l);
7949ef1f84bSDavid du Colombier nb->wp += l + h;
7959ef1f84bSDavid du Colombier b->rp += l;
7969ef1f84bSDavid du Colombier } else {
7979ef1f84bSDavid du Colombier /* add header space */
7989ef1f84bSDavid du Colombier nb = padblock(b, h);
7999ef1f84bSDavid du Colombier b = 0;
8009ef1f84bSDavid du Colombier }
8019ef1f84bSDavid du Colombier l += s->diglen;
8029ef1f84bSDavid du Colombier
8039ef1f84bSDavid du Colombier /* SSL style count */
8049ef1f84bSDavid du Colombier if(pad){
8059ef1f84bSDavid du Colombier nb = padblock(nb, -pad);
8069ef1f84bSDavid du Colombier randfill(nb->wp, pad);
8079ef1f84bSDavid du Colombier nb->wp += pad;
8089ef1f84bSDavid du Colombier l += pad;
8099ef1f84bSDavid du Colombier
8109ef1f84bSDavid du Colombier p = nb->rp;
8119ef1f84bSDavid du Colombier p[0] = (l>>8);
8129ef1f84bSDavid du Colombier p[1] = l;
8139ef1f84bSDavid du Colombier p[2] = pad;
8149ef1f84bSDavid du Colombier offset = 3;
8159ef1f84bSDavid du Colombier } else {
8169ef1f84bSDavid du Colombier p = nb->rp;
8179ef1f84bSDavid du Colombier p[0] = (l>>8) | 0x80;
8189ef1f84bSDavid du Colombier p[1] = l;
8199ef1f84bSDavid du Colombier offset = 2;
8209ef1f84bSDavid du Colombier }
8219ef1f84bSDavid du Colombier
8229ef1f84bSDavid du Colombier switch(s->state){
8239ef1f84bSDavid du Colombier case Sencrypting:
8249ef1f84bSDavid du Colombier nb = encryptb(s, nb, offset);
8259ef1f84bSDavid du Colombier break;
8269ef1f84bSDavid du Colombier case Sdigesting:
8279ef1f84bSDavid du Colombier nb = digestb(s, nb, offset);
8289ef1f84bSDavid du Colombier break;
8299ef1f84bSDavid du Colombier case Sdigenc:
8309ef1f84bSDavid du Colombier nb = digestb(s, nb, offset);
8319ef1f84bSDavid du Colombier nb = encryptb(s, nb, offset);
8329ef1f84bSDavid du Colombier break;
8339ef1f84bSDavid du Colombier }
8349ef1f84bSDavid du Colombier
8359ef1f84bSDavid du Colombier s->out.mid++;
8369ef1f84bSDavid du Colombier
8379ef1f84bSDavid du Colombier l = BLEN(nb);
8389ef1f84bSDavid du Colombier s->c->dev->bwrite(s->c, nb, s->c->offset);
8399ef1f84bSDavid du Colombier s->c->offset += l;
8409ef1f84bSDavid du Colombier }
8419ef1f84bSDavid du Colombier
8429ef1f84bSDavid du Colombier poperror();
8439ef1f84bSDavid du Colombier return rv;
8449ef1f84bSDavid du Colombier }
8459ef1f84bSDavid du Colombier
8469ef1f84bSDavid du Colombier static void
setsecret(OneWay * w,uchar * secret,int n)8479ef1f84bSDavid du Colombier setsecret(OneWay *w, uchar *secret, int n)
8489ef1f84bSDavid du Colombier {
8499ef1f84bSDavid du Colombier if(w->secret)
8509ef1f84bSDavid du Colombier free(w->secret);
8519ef1f84bSDavid du Colombier
8529ef1f84bSDavid du Colombier w->secret = smalloc(n);
8539ef1f84bSDavid du Colombier memmove(w->secret, secret, n);
8549ef1f84bSDavid du Colombier w->slen = n;
8559ef1f84bSDavid du Colombier }
8569ef1f84bSDavid du Colombier
8579ef1f84bSDavid du Colombier static void
initDESkey(OneWay * w)8589ef1f84bSDavid du Colombier initDESkey(OneWay *w)
8599ef1f84bSDavid du Colombier {
8609ef1f84bSDavid du Colombier if(w->state){
8619ef1f84bSDavid du Colombier free(w->state);
8629ef1f84bSDavid du Colombier w->state = 0;
8639ef1f84bSDavid du Colombier }
8649ef1f84bSDavid du Colombier
8659ef1f84bSDavid du Colombier w->state = smalloc(sizeof(DESstate));
8669ef1f84bSDavid du Colombier if(w->slen >= 16)
8679ef1f84bSDavid du Colombier setupDESstate(w->state, w->secret, w->secret+8);
8689ef1f84bSDavid du Colombier else if(w->slen >= 8)
8699ef1f84bSDavid du Colombier setupDESstate(w->state, w->secret, 0);
8709ef1f84bSDavid du Colombier else
8719ef1f84bSDavid du Colombier error("secret too short");
8729ef1f84bSDavid du Colombier }
8739ef1f84bSDavid du Colombier
8749ef1f84bSDavid du Colombier /*
8759ef1f84bSDavid du Colombier * 40 bit DES is the same as 56 bit DES. However,
8769ef1f84bSDavid du Colombier * 16 bits of the key are masked to zero.
8779ef1f84bSDavid du Colombier */
8789ef1f84bSDavid du Colombier static void
initDESkey_40(OneWay * w)8799ef1f84bSDavid du Colombier initDESkey_40(OneWay *w)
8809ef1f84bSDavid du Colombier {
8819ef1f84bSDavid du Colombier uchar key[8];
8829ef1f84bSDavid du Colombier
8839ef1f84bSDavid du Colombier if(w->state){
8849ef1f84bSDavid du Colombier free(w->state);
8859ef1f84bSDavid du Colombier w->state = 0;
8869ef1f84bSDavid du Colombier }
8879ef1f84bSDavid du Colombier
8889ef1f84bSDavid du Colombier if(w->slen >= 8){
8899ef1f84bSDavid du Colombier memmove(key, w->secret, 8);
8909ef1f84bSDavid du Colombier key[0] &= 0x0f;
8919ef1f84bSDavid du Colombier key[2] &= 0x0f;
8929ef1f84bSDavid du Colombier key[4] &= 0x0f;
8939ef1f84bSDavid du Colombier key[6] &= 0x0f;
8949ef1f84bSDavid du Colombier }
8959ef1f84bSDavid du Colombier
8969ef1f84bSDavid du Colombier w->state = malloc(sizeof(DESstate));
897*406c76faSDavid du Colombier if(w->state == nil)
898*406c76faSDavid du Colombier error(Enomem);
8999ef1f84bSDavid du Colombier if(w->slen >= 16)
9009ef1f84bSDavid du Colombier setupDESstate(w->state, key, w->secret+8);
9019ef1f84bSDavid du Colombier else if(w->slen >= 8)
9029ef1f84bSDavid du Colombier setupDESstate(w->state, key, 0);
9039ef1f84bSDavid du Colombier else
9049ef1f84bSDavid du Colombier error("secret too short");
9059ef1f84bSDavid du Colombier }
9069ef1f84bSDavid du Colombier
9079ef1f84bSDavid du Colombier static void
initRC4key(OneWay * w)9089ef1f84bSDavid du Colombier initRC4key(OneWay *w)
9099ef1f84bSDavid du Colombier {
9109ef1f84bSDavid du Colombier if(w->state){
9119ef1f84bSDavid du Colombier free(w->state);
9129ef1f84bSDavid du Colombier w->state = 0;
9139ef1f84bSDavid du Colombier }
9149ef1f84bSDavid du Colombier
9159ef1f84bSDavid du Colombier w->state = smalloc(sizeof(RC4state));
9169ef1f84bSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9179ef1f84bSDavid du Colombier }
9189ef1f84bSDavid du Colombier
9199ef1f84bSDavid du Colombier /*
9209ef1f84bSDavid du Colombier * 40 bit RC4 is the same as n-bit RC4. However,
9219ef1f84bSDavid du Colombier * we ignore all but the first 40 bits of the key.
9229ef1f84bSDavid du Colombier */
9239ef1f84bSDavid du Colombier static void
initRC4key_40(OneWay * w)9249ef1f84bSDavid du Colombier initRC4key_40(OneWay *w)
9259ef1f84bSDavid du Colombier {
9269ef1f84bSDavid du Colombier if(w->state){
9279ef1f84bSDavid du Colombier free(w->state);
9289ef1f84bSDavid du Colombier w->state = 0;
9299ef1f84bSDavid du Colombier }
9309ef1f84bSDavid du Colombier
9319ef1f84bSDavid du Colombier if(w->slen > 5)
9329ef1f84bSDavid du Colombier w->slen = 5;
9339ef1f84bSDavid du Colombier
9349ef1f84bSDavid du Colombier w->state = malloc(sizeof(RC4state));
935*406c76faSDavid du Colombier if(w->state == nil)
936*406c76faSDavid du Colombier error(Enomem);
9379ef1f84bSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9389ef1f84bSDavid du Colombier }
9399ef1f84bSDavid du Colombier
9409ef1f84bSDavid du Colombier /*
9419ef1f84bSDavid du Colombier * 128 bit RC4 is the same as n-bit RC4. However,
9429ef1f84bSDavid du Colombier * we ignore all but the first 128 bits of the key.
9439ef1f84bSDavid du Colombier */
9449ef1f84bSDavid du Colombier static void
initRC4key_128(OneWay * w)9459ef1f84bSDavid du Colombier initRC4key_128(OneWay *w)
9469ef1f84bSDavid du Colombier {
9479ef1f84bSDavid du Colombier if(w->state){
9489ef1f84bSDavid du Colombier free(w->state);
9499ef1f84bSDavid du Colombier w->state = 0;
9509ef1f84bSDavid du Colombier }
9519ef1f84bSDavid du Colombier
9529ef1f84bSDavid du Colombier if(w->slen > 16)
9539ef1f84bSDavid du Colombier w->slen = 16;
9549ef1f84bSDavid du Colombier
9559ef1f84bSDavid du Colombier w->state = malloc(sizeof(RC4state));
956*406c76faSDavid du Colombier if(w->state == nil)
957*406c76faSDavid du Colombier error(Enomem);
9589ef1f84bSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9599ef1f84bSDavid du Colombier }
9609ef1f84bSDavid du Colombier
9619ef1f84bSDavid du Colombier
9629ef1f84bSDavid du Colombier typedef struct Hashalg Hashalg;
9639ef1f84bSDavid du Colombier struct Hashalg
9649ef1f84bSDavid du Colombier {
9659ef1f84bSDavid du Colombier char *name;
9669ef1f84bSDavid du Colombier int diglen;
9679ef1f84bSDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
9689ef1f84bSDavid du Colombier };
9699ef1f84bSDavid du Colombier
9709ef1f84bSDavid du Colombier Hashalg hashtab[] =
9719ef1f84bSDavid du Colombier {
9729ef1f84bSDavid du Colombier { "md4", MD4dlen, md4, },
9739ef1f84bSDavid du Colombier { "md5", MD5dlen, md5, },
9749ef1f84bSDavid du Colombier { "sha1", SHA1dlen, sha1, },
9759ef1f84bSDavid du Colombier { "sha", SHA1dlen, sha1, },
9769ef1f84bSDavid du Colombier { 0 }
9779ef1f84bSDavid du Colombier };
9789ef1f84bSDavid du Colombier
9799ef1f84bSDavid du Colombier static int
parsehashalg(char * p,Dstate * s)9809ef1f84bSDavid du Colombier parsehashalg(char *p, Dstate *s)
9819ef1f84bSDavid du Colombier {
9829ef1f84bSDavid du Colombier Hashalg *ha;
9839ef1f84bSDavid du Colombier
9849ef1f84bSDavid du Colombier for(ha = hashtab; ha->name; ha++){
9859ef1f84bSDavid du Colombier if(strcmp(p, ha->name) == 0){
9869ef1f84bSDavid du Colombier s->hf = ha->hf;
9879ef1f84bSDavid du Colombier s->diglen = ha->diglen;
9889ef1f84bSDavid du Colombier s->state &= ~Sclear;
9899ef1f84bSDavid du Colombier s->state |= Sdigesting;
9909ef1f84bSDavid du Colombier return 0;
9919ef1f84bSDavid du Colombier }
9929ef1f84bSDavid du Colombier }
9939ef1f84bSDavid du Colombier return -1;
9949ef1f84bSDavid du Colombier }
9959ef1f84bSDavid du Colombier
9969ef1f84bSDavid du Colombier typedef struct Encalg Encalg;
9979ef1f84bSDavid du Colombier struct Encalg
9989ef1f84bSDavid du Colombier {
9999ef1f84bSDavid du Colombier char *name;
10009ef1f84bSDavid du Colombier int blocklen;
10019ef1f84bSDavid du Colombier int alg;
10029ef1f84bSDavid du Colombier void (*keyinit)(OneWay*);
10039ef1f84bSDavid du Colombier };
10049ef1f84bSDavid du Colombier
10059ef1f84bSDavid du Colombier #ifdef NOSPOOKS
10069ef1f84bSDavid du Colombier Encalg encrypttab[] =
10079ef1f84bSDavid du Colombier {
10089ef1f84bSDavid du Colombier { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */
10099ef1f84bSDavid du Colombier { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */
10109ef1f84bSDavid du Colombier { "des_56_cbc", 8, DESCBC, initDESkey, },
10119ef1f84bSDavid du Colombier { "des_56_ecb", 8, DESECB, initDESkey, },
10129ef1f84bSDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10139ef1f84bSDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10149ef1f84bSDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10159ef1f84bSDavid du Colombier { "rc4_256", 1, RC4, initRC4key, },
10169ef1f84bSDavid du Colombier { "rc4_128", 1, RC4, initRC4key_128, },
10179ef1f84bSDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10189ef1f84bSDavid du Colombier { 0 }
10199ef1f84bSDavid du Colombier };
10209ef1f84bSDavid du Colombier #else
10219ef1f84bSDavid du Colombier Encalg encrypttab[] =
10229ef1f84bSDavid du Colombier {
10239ef1f84bSDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10249ef1f84bSDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10259ef1f84bSDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10269ef1f84bSDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10279ef1f84bSDavid du Colombier { 0 }
10289ef1f84bSDavid du Colombier };
10299ef1f84bSDavid du Colombier #endif NOSPOOKS
10309ef1f84bSDavid du Colombier
10319ef1f84bSDavid du Colombier static int
parseencryptalg(char * p,Dstate * s)10329ef1f84bSDavid du Colombier parseencryptalg(char *p, Dstate *s)
10339ef1f84bSDavid du Colombier {
10349ef1f84bSDavid du Colombier Encalg *ea;
10359ef1f84bSDavid du Colombier
10369ef1f84bSDavid du Colombier for(ea = encrypttab; ea->name; ea++){
10379ef1f84bSDavid du Colombier if(strcmp(p, ea->name) == 0){
10389ef1f84bSDavid du Colombier s->encryptalg = ea->alg;
10399ef1f84bSDavid du Colombier s->blocklen = ea->blocklen;
10409ef1f84bSDavid du Colombier (*ea->keyinit)(&s->in);
10419ef1f84bSDavid du Colombier (*ea->keyinit)(&s->out);
10429ef1f84bSDavid du Colombier s->state &= ~Sclear;
10439ef1f84bSDavid du Colombier s->state |= Sencrypting;
10449ef1f84bSDavid du Colombier return 0;
10459ef1f84bSDavid du Colombier }
10469ef1f84bSDavid du Colombier }
10479ef1f84bSDavid du Colombier return -1;
10489ef1f84bSDavid du Colombier }
10499ef1f84bSDavid du Colombier
10509ef1f84bSDavid du Colombier static long
sslwrite(Chan * c,void * a,long n,vlong)10519ef1f84bSDavid du Colombier sslwrite(Chan *c, void *a, long n, vlong)
10529ef1f84bSDavid du Colombier {
10539ef1f84bSDavid du Colombier Dstate * volatile s;
10549ef1f84bSDavid du Colombier Block * volatile b;
10559ef1f84bSDavid du Colombier int l, t;
10569ef1f84bSDavid du Colombier char *p, *np, *e, buf[128];
10579ef1f84bSDavid du Colombier uchar *x;
10589ef1f84bSDavid du Colombier
1059*406c76faSDavid du Colombier x = nil;
10609ef1f84bSDavid du Colombier s = dstate[CONV(c->qid)];
10619ef1f84bSDavid du Colombier if(s == 0)
10629ef1f84bSDavid du Colombier panic("sslwrite");
10639ef1f84bSDavid du Colombier
10649ef1f84bSDavid du Colombier t = TYPE(c->qid);
10659ef1f84bSDavid du Colombier if(t == Qdata){
10669ef1f84bSDavid du Colombier if(s->state == Sincomplete)
10679ef1f84bSDavid du Colombier error(Ebadusefd);
10689ef1f84bSDavid du Colombier
10699ef1f84bSDavid du Colombier /* lock should a write gets split over multiple records */
10709ef1f84bSDavid du Colombier if(waserror()){
10719ef1f84bSDavid du Colombier qunlock(&s->out.q);
10729ef1f84bSDavid du Colombier nexterror();
10739ef1f84bSDavid du Colombier }
10749ef1f84bSDavid du Colombier qlock(&s->out.q);
10759ef1f84bSDavid du Colombier
10769ef1f84bSDavid du Colombier p = a;
10779ef1f84bSDavid du Colombier e = p + n;
10789ef1f84bSDavid du Colombier do {
10799ef1f84bSDavid du Colombier l = e - p;
10809ef1f84bSDavid du Colombier if(l > s->max)
10819ef1f84bSDavid du Colombier l = s->max;
10829ef1f84bSDavid du Colombier
10839ef1f84bSDavid du Colombier b = allocb(l);
10849ef1f84bSDavid du Colombier if(waserror()){
10859ef1f84bSDavid du Colombier freeb(b);
10869ef1f84bSDavid du Colombier nexterror();
10879ef1f84bSDavid du Colombier }
10889ef1f84bSDavid du Colombier memmove(b->wp, p, l);
10899ef1f84bSDavid du Colombier poperror();
10909ef1f84bSDavid du Colombier b->wp += l;
10919ef1f84bSDavid du Colombier
10929ef1f84bSDavid du Colombier sslput(s, b);
10939ef1f84bSDavid du Colombier
10949ef1f84bSDavid du Colombier p += l;
10959ef1f84bSDavid du Colombier } while(p < e);
10969ef1f84bSDavid du Colombier
10979ef1f84bSDavid du Colombier poperror();
10989ef1f84bSDavid du Colombier qunlock(&s->out.q);
10999ef1f84bSDavid du Colombier return n;
11009ef1f84bSDavid du Colombier }
11019ef1f84bSDavid du Colombier
11029ef1f84bSDavid du Colombier /* mutex with operations using what we're about to change */
11039ef1f84bSDavid du Colombier if(waserror()){
11049ef1f84bSDavid du Colombier qunlock(&s->in.ctlq);
11059ef1f84bSDavid du Colombier qunlock(&s->out.q);
11069ef1f84bSDavid du Colombier nexterror();
11079ef1f84bSDavid du Colombier }
11089ef1f84bSDavid du Colombier qlock(&s->in.ctlq);
11099ef1f84bSDavid du Colombier qlock(&s->out.q);
11109ef1f84bSDavid du Colombier
11119ef1f84bSDavid du Colombier switch(t){
11129ef1f84bSDavid du Colombier default:
11139ef1f84bSDavid du Colombier panic("sslwrite");
11149ef1f84bSDavid du Colombier case Qsecretin:
11159ef1f84bSDavid du Colombier setsecret(&s->in, a, n);
11169ef1f84bSDavid du Colombier goto out;
11179ef1f84bSDavid du Colombier case Qsecretout:
11189ef1f84bSDavid du Colombier setsecret(&s->out, a, n);
11199ef1f84bSDavid du Colombier goto out;
11209ef1f84bSDavid du Colombier case Qctl:
11219ef1f84bSDavid du Colombier break;
11229ef1f84bSDavid du Colombier }
11239ef1f84bSDavid du Colombier
11249ef1f84bSDavid du Colombier if(n >= sizeof(buf))
11259ef1f84bSDavid du Colombier error("arg too long");
11269ef1f84bSDavid du Colombier strncpy(buf, a, n);
11279ef1f84bSDavid du Colombier buf[n] = 0;
11289ef1f84bSDavid du Colombier p = strchr(buf, '\n');
11299ef1f84bSDavid du Colombier if(p)
11309ef1f84bSDavid du Colombier *p = 0;
11319ef1f84bSDavid du Colombier p = strchr(buf, ' ');
11329ef1f84bSDavid du Colombier if(p)
11339ef1f84bSDavid du Colombier *p++ = 0;
11349ef1f84bSDavid du Colombier
1135*406c76faSDavid du Colombier if(waserror()){
1136*406c76faSDavid du Colombier free(x);
1137*406c76faSDavid du Colombier nexterror();
1138*406c76faSDavid du Colombier }
11399ef1f84bSDavid du Colombier if(strcmp(buf, "fd") == 0){
11409ef1f84bSDavid du Colombier s->c = buftochan(p);
11419ef1f84bSDavid du Colombier
11429ef1f84bSDavid du Colombier /* default is clear (msg delimiters only) */
11439ef1f84bSDavid du Colombier s->state = Sclear;
11449ef1f84bSDavid du Colombier s->blocklen = 1;
11459ef1f84bSDavid du Colombier s->diglen = 0;
11469ef1f84bSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11479ef1f84bSDavid du Colombier s->in.mid = 0;
11489ef1f84bSDavid du Colombier s->out.mid = 0;
11499ef1f84bSDavid du Colombier } else if(strcmp(buf, "alg") == 0 && p != 0){
11509ef1f84bSDavid du Colombier s->blocklen = 1;
11519ef1f84bSDavid du Colombier s->diglen = 0;
11529ef1f84bSDavid du Colombier
11539ef1f84bSDavid du Colombier if(s->c == 0)
11549ef1f84bSDavid du Colombier error("must set fd before algorithm");
11559ef1f84bSDavid du Colombier
11569ef1f84bSDavid du Colombier s->state = Sclear;
11579ef1f84bSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
1158*406c76faSDavid du Colombier if(strcmp(p, "clear") == 0)
1159*406c76faSDavid du Colombier goto outx;
11609ef1f84bSDavid du Colombier
11619ef1f84bSDavid du Colombier if(s->in.secret && s->out.secret == 0)
11629ef1f84bSDavid du Colombier setsecret(&s->out, s->in.secret, s->in.slen);
11639ef1f84bSDavid du Colombier if(s->out.secret && s->in.secret == 0)
11649ef1f84bSDavid du Colombier setsecret(&s->in, s->out.secret, s->out.slen);
11659ef1f84bSDavid du Colombier if(s->in.secret == 0 || s->out.secret == 0)
11669ef1f84bSDavid du Colombier error("algorithm but no secret");
11679ef1f84bSDavid du Colombier
11689ef1f84bSDavid du Colombier s->hf = 0;
11699ef1f84bSDavid du Colombier s->encryptalg = Noencryption;
11709ef1f84bSDavid du Colombier s->blocklen = 1;
11719ef1f84bSDavid du Colombier
11729ef1f84bSDavid du Colombier for(;;){
11739ef1f84bSDavid du Colombier np = strchr(p, ' ');
11749ef1f84bSDavid du Colombier if(np)
11759ef1f84bSDavid du Colombier *np++ = 0;
11769ef1f84bSDavid du Colombier
11779ef1f84bSDavid du Colombier if(parsehashalg(p, s) < 0)
11789ef1f84bSDavid du Colombier if(parseencryptalg(p, s) < 0)
11799ef1f84bSDavid du Colombier error("bad algorithm");
11809ef1f84bSDavid du Colombier
11819ef1f84bSDavid du Colombier if(np == 0)
11829ef1f84bSDavid du Colombier break;
11839ef1f84bSDavid du Colombier p = np;
11849ef1f84bSDavid du Colombier }
11859ef1f84bSDavid du Colombier
11869ef1f84bSDavid du Colombier if(s->hf == 0 && s->encryptalg == Noencryption)
11879ef1f84bSDavid du Colombier error("bad algorithm");
11889ef1f84bSDavid du Colombier
11899ef1f84bSDavid du Colombier if(s->blocklen != 1){
11909ef1f84bSDavid du Colombier s->max = (1<<15) - s->diglen - 1;
11919ef1f84bSDavid du Colombier s->max -= s->max % s->blocklen;
11929ef1f84bSDavid du Colombier s->maxpad = (1<<14) - s->diglen - 1;
11939ef1f84bSDavid du Colombier s->maxpad -= s->maxpad % s->blocklen;
11949ef1f84bSDavid du Colombier } else
11959ef1f84bSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11969ef1f84bSDavid du Colombier } else if(strcmp(buf, "secretin") == 0 && p != 0) {
11979ef1f84bSDavid du Colombier l = (strlen(p)*3)/2;
11989ef1f84bSDavid du Colombier x = smalloc(l);
11999ef1f84bSDavid du Colombier t = dec64(x, l, p, strlen(p));
1200*406c76faSDavid du Colombier if(t <= 0)
1201*406c76faSDavid du Colombier error(Ebadarg);
12029ef1f84bSDavid du Colombier setsecret(&s->in, x, t);
12039ef1f84bSDavid du Colombier } else if(strcmp(buf, "secretout") == 0 && p != 0) {
12049ef1f84bSDavid du Colombier l = (strlen(p)*3)/2 + 1;
12059ef1f84bSDavid du Colombier x = smalloc(l);
12069ef1f84bSDavid du Colombier t = dec64(x, l, p, strlen(p));
1207*406c76faSDavid du Colombier if(t <= 0)
1208*406c76faSDavid du Colombier error(Ebadarg);
12099ef1f84bSDavid du Colombier setsecret(&s->out, x, t);
12109ef1f84bSDavid du Colombier } else
12119ef1f84bSDavid du Colombier error(Ebadarg);
1212*406c76faSDavid du Colombier outx:
1213*406c76faSDavid du Colombier free(x);
1214*406c76faSDavid du Colombier poperror();
12159ef1f84bSDavid du Colombier out:
12169ef1f84bSDavid du Colombier qunlock(&s->in.ctlq);
12179ef1f84bSDavid du Colombier qunlock(&s->out.q);
12189ef1f84bSDavid du Colombier poperror();
12199ef1f84bSDavid du Colombier return n;
12209ef1f84bSDavid du Colombier }
12219ef1f84bSDavid du Colombier
12229ef1f84bSDavid du Colombier static void
sslinit(void)12239ef1f84bSDavid du Colombier sslinit(void)
12249ef1f84bSDavid du Colombier {
12259ef1f84bSDavid du Colombier struct Encalg *e;
12269ef1f84bSDavid du Colombier struct Hashalg *h;
12279ef1f84bSDavid du Colombier int n;
12289ef1f84bSDavid du Colombier char *cp;
12299ef1f84bSDavid du Colombier
12309ef1f84bSDavid du Colombier n = 1;
12319ef1f84bSDavid du Colombier for(e = encrypttab; e->name != nil; e++)
12329ef1f84bSDavid du Colombier n += strlen(e->name) + 1;
12339ef1f84bSDavid du Colombier cp = encalgs = smalloc(n);
12349ef1f84bSDavid du Colombier for(e = encrypttab;;){
12359ef1f84bSDavid du Colombier strcpy(cp, e->name);
12369ef1f84bSDavid du Colombier cp += strlen(e->name);
12379ef1f84bSDavid du Colombier e++;
12389ef1f84bSDavid du Colombier if(e->name == nil)
12399ef1f84bSDavid du Colombier break;
12409ef1f84bSDavid du Colombier *cp++ = ' ';
12419ef1f84bSDavid du Colombier }
12429ef1f84bSDavid du Colombier *cp = 0;
12439ef1f84bSDavid du Colombier
12449ef1f84bSDavid du Colombier n = 1;
12459ef1f84bSDavid du Colombier for(h = hashtab; h->name != nil; h++)
12469ef1f84bSDavid du Colombier n += strlen(h->name) + 1;
12479ef1f84bSDavid du Colombier cp = hashalgs = smalloc(n);
12489ef1f84bSDavid du Colombier for(h = hashtab;;){
12499ef1f84bSDavid du Colombier strcpy(cp, h->name);
12509ef1f84bSDavid du Colombier cp += strlen(h->name);
12519ef1f84bSDavid du Colombier h++;
12529ef1f84bSDavid du Colombier if(h->name == nil)
12539ef1f84bSDavid du Colombier break;
12549ef1f84bSDavid du Colombier *cp++ = ' ';
12559ef1f84bSDavid du Colombier }
12569ef1f84bSDavid du Colombier *cp = 0;
12579ef1f84bSDavid du Colombier }
12589ef1f84bSDavid du Colombier
12599ef1f84bSDavid du Colombier Dev ssldevtab = {
12609ef1f84bSDavid du Colombier 'D',
12619ef1f84bSDavid du Colombier "ssl",
12629ef1f84bSDavid du Colombier
12639ef1f84bSDavid du Colombier devreset,
12649ef1f84bSDavid du Colombier sslinit,
12659ef1f84bSDavid du Colombier devshutdown,
12669ef1f84bSDavid du Colombier sslattach,
12679ef1f84bSDavid du Colombier sslwalk,
12689ef1f84bSDavid du Colombier sslstat,
12699ef1f84bSDavid du Colombier sslopen,
12709ef1f84bSDavid du Colombier devcreate,
12719ef1f84bSDavid du Colombier sslclose,
12729ef1f84bSDavid du Colombier sslread,
12739ef1f84bSDavid du Colombier sslbread,
12749ef1f84bSDavid du Colombier sslwrite,
12759ef1f84bSDavid du Colombier sslbwrite,
12769ef1f84bSDavid du Colombier devremove,
12779ef1f84bSDavid du Colombier sslwstat,
12789ef1f84bSDavid du Colombier };
12799ef1f84bSDavid du Colombier
12809ef1f84bSDavid du Colombier static Block*
encryptb(Dstate * s,Block * b,int offset)12819ef1f84bSDavid du Colombier encryptb(Dstate *s, Block *b, int offset)
12829ef1f84bSDavid du Colombier {
12839ef1f84bSDavid du Colombier uchar *p, *ep, *p2, *ip, *eip;
12849ef1f84bSDavid du Colombier DESstate *ds;
12859ef1f84bSDavid du Colombier
12869ef1f84bSDavid du Colombier switch(s->encryptalg){
12879ef1f84bSDavid du Colombier case DESECB:
12889ef1f84bSDavid du Colombier ds = s->out.state;
12899ef1f84bSDavid du Colombier ep = b->rp + BLEN(b);
12909ef1f84bSDavid du Colombier for(p = b->rp + offset; p < ep; p += 8)
12919ef1f84bSDavid du Colombier block_cipher(ds->expanded, p, 0);
12929ef1f84bSDavid du Colombier break;
12939ef1f84bSDavid du Colombier case DESCBC:
12949ef1f84bSDavid du Colombier ds = s->out.state;
12959ef1f84bSDavid du Colombier ep = b->rp + BLEN(b);
12969ef1f84bSDavid du Colombier for(p = b->rp + offset; p < ep; p += 8){
12979ef1f84bSDavid du Colombier p2 = p;
12989ef1f84bSDavid du Colombier ip = ds->ivec;
12999ef1f84bSDavid du Colombier for(eip = ip+8; ip < eip; )
13009ef1f84bSDavid du Colombier *p2++ ^= *ip++;
13019ef1f84bSDavid du Colombier block_cipher(ds->expanded, p, 0);
13029ef1f84bSDavid du Colombier memmove(ds->ivec, p, 8);
13039ef1f84bSDavid du Colombier }
13049ef1f84bSDavid du Colombier break;
13059ef1f84bSDavid du Colombier case RC4:
13069ef1f84bSDavid du Colombier rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
13079ef1f84bSDavid du Colombier break;
13089ef1f84bSDavid du Colombier }
13099ef1f84bSDavid du Colombier return b;
13109ef1f84bSDavid du Colombier }
13119ef1f84bSDavid du Colombier
13129ef1f84bSDavid du Colombier static Block*
decryptb(Dstate * s,Block * bin)13139ef1f84bSDavid du Colombier decryptb(Dstate *s, Block *bin)
13149ef1f84bSDavid du Colombier {
13159ef1f84bSDavid du Colombier Block *b, **l;
13169ef1f84bSDavid du Colombier uchar *p, *ep, *tp, *ip, *eip;
13179ef1f84bSDavid du Colombier DESstate *ds;
13189ef1f84bSDavid du Colombier uchar tmp[8];
13199ef1f84bSDavid du Colombier int i;
13209ef1f84bSDavid du Colombier
13219ef1f84bSDavid du Colombier l = &bin;
13229ef1f84bSDavid du Colombier for(b = bin; b; b = b->next){
13239ef1f84bSDavid du Colombier /* make sure we have a multiple of s->blocklen */
13249ef1f84bSDavid du Colombier if(s->blocklen > 1){
13259ef1f84bSDavid du Colombier i = BLEN(b);
13269ef1f84bSDavid du Colombier if(i % s->blocklen){
13279ef1f84bSDavid du Colombier *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
13289ef1f84bSDavid du Colombier if(b == 0)
13299ef1f84bSDavid du Colombier error("ssl encrypted message too short");
13309ef1f84bSDavid du Colombier }
13319ef1f84bSDavid du Colombier }
13329ef1f84bSDavid du Colombier l = &b->next;
13339ef1f84bSDavid du Colombier
13349ef1f84bSDavid du Colombier /* decrypt */
13359ef1f84bSDavid du Colombier switch(s->encryptalg){
13369ef1f84bSDavid du Colombier case DESECB:
13379ef1f84bSDavid du Colombier ds = s->in.state;
13389ef1f84bSDavid du Colombier ep = b->rp + BLEN(b);
13399ef1f84bSDavid du Colombier for(p = b->rp; p < ep; p += 8)
13409ef1f84bSDavid du Colombier block_cipher(ds->expanded, p, 1);
13419ef1f84bSDavid du Colombier break;
13429ef1f84bSDavid du Colombier case DESCBC:
13439ef1f84bSDavid du Colombier ds = s->in.state;
13449ef1f84bSDavid du Colombier ep = b->rp + BLEN(b);
13459ef1f84bSDavid du Colombier for(p = b->rp; p < ep;){
13469ef1f84bSDavid du Colombier memmove(tmp, p, 8);
13479ef1f84bSDavid du Colombier block_cipher(ds->expanded, p, 1);
13489ef1f84bSDavid du Colombier tp = tmp;
13499ef1f84bSDavid du Colombier ip = ds->ivec;
13509ef1f84bSDavid du Colombier for(eip = ip+8; ip < eip; ){
13519ef1f84bSDavid du Colombier *p++ ^= *ip;
13529ef1f84bSDavid du Colombier *ip++ = *tp++;
13539ef1f84bSDavid du Colombier }
13549ef1f84bSDavid du Colombier }
13559ef1f84bSDavid du Colombier break;
13569ef1f84bSDavid du Colombier case RC4:
13579ef1f84bSDavid du Colombier rc4(s->in.state, b->rp, BLEN(b));
13589ef1f84bSDavid du Colombier break;
13599ef1f84bSDavid du Colombier }
13609ef1f84bSDavid du Colombier }
13619ef1f84bSDavid du Colombier return bin;
13629ef1f84bSDavid du Colombier }
13639ef1f84bSDavid du Colombier
13649ef1f84bSDavid du Colombier static Block*
digestb(Dstate * s,Block * b,int offset)13659ef1f84bSDavid du Colombier digestb(Dstate *s, Block *b, int offset)
13669ef1f84bSDavid du Colombier {
13679ef1f84bSDavid du Colombier uchar *p;
13689ef1f84bSDavid du Colombier DigestState ss;
13699ef1f84bSDavid du Colombier uchar msgid[4];
13709ef1f84bSDavid du Colombier ulong n, h;
13719ef1f84bSDavid du Colombier OneWay *w;
13729ef1f84bSDavid du Colombier
13739ef1f84bSDavid du Colombier w = &s->out;
13749ef1f84bSDavid du Colombier
13759ef1f84bSDavid du Colombier memset(&ss, 0, sizeof(ss));
13769ef1f84bSDavid du Colombier h = s->diglen + offset;
13779ef1f84bSDavid du Colombier n = BLEN(b) - h;
13789ef1f84bSDavid du Colombier
13799ef1f84bSDavid du Colombier /* hash secret + message */
13809ef1f84bSDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
13819ef1f84bSDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
13829ef1f84bSDavid du Colombier
13839ef1f84bSDavid du Colombier /* hash message id */
13849ef1f84bSDavid du Colombier p = msgid;
13859ef1f84bSDavid du Colombier n = w->mid;
13869ef1f84bSDavid du Colombier *p++ = n>>24;
13879ef1f84bSDavid du Colombier *p++ = n>>16;
13889ef1f84bSDavid du Colombier *p++ = n>>8;
13899ef1f84bSDavid du Colombier *p = n;
13909ef1f84bSDavid du Colombier (*s->hf)(msgid, 4, b->rp + offset, &ss);
13919ef1f84bSDavid du Colombier
13929ef1f84bSDavid du Colombier return b;
13939ef1f84bSDavid du Colombier }
13949ef1f84bSDavid du Colombier
13959ef1f84bSDavid du Colombier static void
checkdigestb(Dstate * s,Block * bin)13969ef1f84bSDavid du Colombier checkdigestb(Dstate *s, Block *bin)
13979ef1f84bSDavid du Colombier {
13989ef1f84bSDavid du Colombier uchar *p;
13999ef1f84bSDavid du Colombier DigestState ss;
14009ef1f84bSDavid du Colombier uchar msgid[4];
14019ef1f84bSDavid du Colombier int n, h;
14029ef1f84bSDavid du Colombier OneWay *w;
14039ef1f84bSDavid du Colombier uchar digest[128];
14049ef1f84bSDavid du Colombier Block *b;
14059ef1f84bSDavid du Colombier
14069ef1f84bSDavid du Colombier w = &s->in;
14079ef1f84bSDavid du Colombier
14089ef1f84bSDavid du Colombier memset(&ss, 0, sizeof(ss));
14099ef1f84bSDavid du Colombier
14109ef1f84bSDavid du Colombier /* hash secret */
14119ef1f84bSDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
14129ef1f84bSDavid du Colombier
14139ef1f84bSDavid du Colombier /* hash message */
14149ef1f84bSDavid du Colombier h = s->diglen;
14159ef1f84bSDavid du Colombier for(b = bin; b; b = b->next){
14169ef1f84bSDavid du Colombier n = BLEN(b) - h;
14179ef1f84bSDavid du Colombier if(n < 0)
14189ef1f84bSDavid du Colombier panic("checkdigestb");
14199ef1f84bSDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
14209ef1f84bSDavid du Colombier h = 0;
14219ef1f84bSDavid du Colombier }
14229ef1f84bSDavid du Colombier
14239ef1f84bSDavid du Colombier /* hash message id */
14249ef1f84bSDavid du Colombier p = msgid;
14259ef1f84bSDavid du Colombier n = w->mid;
14269ef1f84bSDavid du Colombier *p++ = n>>24;
14279ef1f84bSDavid du Colombier *p++ = n>>16;
14289ef1f84bSDavid du Colombier *p++ = n>>8;
14299ef1f84bSDavid du Colombier *p = n;
14309ef1f84bSDavid du Colombier (*s->hf)(msgid, 4, digest, &ss);
14319ef1f84bSDavid du Colombier
14329ef1f84bSDavid du Colombier if(memcmp(digest, bin->rp, s->diglen) != 0)
14339ef1f84bSDavid du Colombier error("bad digest");
14349ef1f84bSDavid du Colombier }
14359ef1f84bSDavid du Colombier
14369ef1f84bSDavid du Colombier /* get channel associated with an fd */
14379ef1f84bSDavid du Colombier static Chan*
buftochan(char * p)14389ef1f84bSDavid du Colombier buftochan(char *p)
14399ef1f84bSDavid du Colombier {
14409ef1f84bSDavid du Colombier Chan *c;
14419ef1f84bSDavid du Colombier int fd;
14429ef1f84bSDavid du Colombier
14439ef1f84bSDavid du Colombier if(p == 0)
14449ef1f84bSDavid du Colombier error(Ebadarg);
14459ef1f84bSDavid du Colombier fd = strtoul(p, 0, 0);
14469ef1f84bSDavid du Colombier if(fd < 0)
14479ef1f84bSDavid du Colombier error(Ebadarg);
14489ef1f84bSDavid du Colombier c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
14499ef1f84bSDavid du Colombier if(c->dev == &ssldevtab){
14509ef1f84bSDavid du Colombier cclose(c);
14519ef1f84bSDavid du Colombier error("cannot ssl encrypt devssl files");
14529ef1f84bSDavid du Colombier }
14539ef1f84bSDavid du Colombier return c;
14549ef1f84bSDavid du Colombier }
14559ef1f84bSDavid du Colombier
14569ef1f84bSDavid du Colombier /* hand up a digest connection */
14579ef1f84bSDavid du Colombier static void
sslhangup(Dstate * s)14589ef1f84bSDavid du Colombier sslhangup(Dstate *s)
14599ef1f84bSDavid du Colombier {
14609ef1f84bSDavid du Colombier Block *b;
14619ef1f84bSDavid du Colombier
14629ef1f84bSDavid du Colombier qlock(&s->in.q);
14639ef1f84bSDavid du Colombier for(b = s->processed; b; b = s->processed){
14649ef1f84bSDavid du Colombier s->processed = b->next;
14659ef1f84bSDavid du Colombier freeb(b);
14669ef1f84bSDavid du Colombier }
14679ef1f84bSDavid du Colombier if(s->unprocessed){
14689ef1f84bSDavid du Colombier freeb(s->unprocessed);
14699ef1f84bSDavid du Colombier s->unprocessed = 0;
14709ef1f84bSDavid du Colombier }
14719ef1f84bSDavid du Colombier s->state = Sincomplete;
14729ef1f84bSDavid du Colombier qunlock(&s->in.q);
14739ef1f84bSDavid du Colombier }
14749ef1f84bSDavid du Colombier
14759ef1f84bSDavid du Colombier static Dstate*
dsclone(Chan * ch)14769ef1f84bSDavid du Colombier dsclone(Chan *ch)
14779ef1f84bSDavid du Colombier {
14789ef1f84bSDavid du Colombier int i;
14799ef1f84bSDavid du Colombier Dstate *ret;
14809ef1f84bSDavid du Colombier
14819ef1f84bSDavid du Colombier if(waserror()) {
14829ef1f84bSDavid du Colombier unlock(&dslock);
14839ef1f84bSDavid du Colombier nexterror();
14849ef1f84bSDavid du Colombier }
14859ef1f84bSDavid du Colombier lock(&dslock);
14869ef1f84bSDavid du Colombier ret = nil;
14879ef1f84bSDavid du Colombier for(i=0; i<Maxdstate; i++){
14889ef1f84bSDavid du Colombier if(dstate[i] == nil){
14899ef1f84bSDavid du Colombier dsnew(ch, &dstate[i]);
14909ef1f84bSDavid du Colombier ret = dstate[i];
14919ef1f84bSDavid du Colombier break;
14929ef1f84bSDavid du Colombier }
14939ef1f84bSDavid du Colombier }
14949ef1f84bSDavid du Colombier unlock(&dslock);
14959ef1f84bSDavid du Colombier poperror();
14969ef1f84bSDavid du Colombier return ret;
14979ef1f84bSDavid du Colombier }
14989ef1f84bSDavid du Colombier
14999ef1f84bSDavid du Colombier static void
dsnew(Chan * ch,Dstate ** pp)15009ef1f84bSDavid du Colombier dsnew(Chan *ch, Dstate **pp)
15019ef1f84bSDavid du Colombier {
15029ef1f84bSDavid du Colombier Dstate *s;
15039ef1f84bSDavid du Colombier int t;
15049ef1f84bSDavid du Colombier
15059ef1f84bSDavid du Colombier *pp = s = malloc(sizeof(*s));
15069ef1f84bSDavid du Colombier if(!s)
15079ef1f84bSDavid du Colombier error(Enomem);
15089ef1f84bSDavid du Colombier if(pp - dstate >= dshiwat)
15099ef1f84bSDavid du Colombier dshiwat++;
15109ef1f84bSDavid du Colombier memset(s, 0, sizeof(*s));
15119ef1f84bSDavid du Colombier s->state = Sincomplete;
15129ef1f84bSDavid du Colombier s->ref = 1;
15139ef1f84bSDavid du Colombier kstrdup(&s->user, up->user);
15149ef1f84bSDavid du Colombier s->perm = 0660;
15159ef1f84bSDavid du Colombier t = TYPE(ch->qid);
15169ef1f84bSDavid du Colombier if(t == Qclonus)
15179ef1f84bSDavid du Colombier t = Qctl;
15189ef1f84bSDavid du Colombier ch->qid.path = QID(pp - dstate, t);
15199ef1f84bSDavid du Colombier ch->qid.vers = 0;
15209ef1f84bSDavid du Colombier }
1521