18ccd4a63SDavid du Colombier /*
28ccd4a63SDavid du Colombier * devssl - secure sockets layer
38ccd4a63SDavid du Colombier */
48ccd4a63SDavid du Colombier #include "u.h"
58ccd4a63SDavid du Colombier #include "lib.h"
68ccd4a63SDavid du Colombier #include "dat.h"
78ccd4a63SDavid du Colombier #include "fns.h"
88ccd4a63SDavid du Colombier #include "error.h"
98ccd4a63SDavid du Colombier
108ccd4a63SDavid du Colombier #include "libsec.h"
118ccd4a63SDavid du Colombier
128ccd4a63SDavid du Colombier #define NOSPOOKS 1
138ccd4a63SDavid du Colombier
148ccd4a63SDavid du Colombier typedef struct OneWay OneWay;
158ccd4a63SDavid du Colombier struct OneWay
168ccd4a63SDavid du Colombier {
178ccd4a63SDavid du Colombier QLock q;
188ccd4a63SDavid du Colombier QLock ctlq;
198ccd4a63SDavid du Colombier
208ccd4a63SDavid du Colombier void *state; /* encryption state */
218ccd4a63SDavid du Colombier int slen; /* hash data length */
228ccd4a63SDavid du Colombier uchar *secret; /* secret */
238ccd4a63SDavid du Colombier ulong mid; /* message id */
248ccd4a63SDavid du Colombier };
258ccd4a63SDavid du Colombier
268ccd4a63SDavid du Colombier enum
278ccd4a63SDavid du Colombier {
288ccd4a63SDavid du Colombier /* connection states */
298ccd4a63SDavid du Colombier Sincomplete= 0,
308ccd4a63SDavid du Colombier Sclear= 1,
318ccd4a63SDavid du Colombier Sencrypting= 2,
328ccd4a63SDavid du Colombier Sdigesting= 4,
338ccd4a63SDavid du Colombier Sdigenc= Sencrypting|Sdigesting,
348ccd4a63SDavid du Colombier
358ccd4a63SDavid du Colombier /* encryption algorithms */
368ccd4a63SDavid du Colombier Noencryption= 0,
378ccd4a63SDavid du Colombier DESCBC= 1,
388ccd4a63SDavid du Colombier DESECB= 2,
398ccd4a63SDavid du Colombier RC4= 3
408ccd4a63SDavid du Colombier };
418ccd4a63SDavid du Colombier
428ccd4a63SDavid du Colombier typedef struct Dstate Dstate;
438ccd4a63SDavid du Colombier struct Dstate
448ccd4a63SDavid du Colombier {
458ccd4a63SDavid du Colombier Chan *c; /* io channel */
468ccd4a63SDavid du Colombier uchar state; /* state of connection */
478ccd4a63SDavid du Colombier int ref; /* serialized by dslock for atomic destroy */
488ccd4a63SDavid du Colombier
498ccd4a63SDavid du Colombier uchar encryptalg; /* encryption algorithm */
508ccd4a63SDavid du Colombier ushort blocklen; /* blocking length */
518ccd4a63SDavid du Colombier
528ccd4a63SDavid du Colombier ushort diglen; /* length of digest */
538ccd4a63SDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
548ccd4a63SDavid du Colombier
558ccd4a63SDavid du Colombier /* for SSL format */
568ccd4a63SDavid du Colombier int max; /* maximum unpadded data per msg */
578ccd4a63SDavid du Colombier int maxpad; /* maximum padded data per msg */
588ccd4a63SDavid du Colombier
598ccd4a63SDavid du Colombier /* input side */
608ccd4a63SDavid du Colombier OneWay in;
618ccd4a63SDavid du Colombier Block *processed;
628ccd4a63SDavid du Colombier Block *unprocessed;
638ccd4a63SDavid du Colombier
648ccd4a63SDavid du Colombier /* output side */
658ccd4a63SDavid du Colombier OneWay out;
668ccd4a63SDavid du Colombier
678ccd4a63SDavid du Colombier /* protections */
688ccd4a63SDavid du Colombier char *user;
698ccd4a63SDavid du Colombier int perm;
708ccd4a63SDavid du Colombier };
718ccd4a63SDavid du Colombier
728ccd4a63SDavid du Colombier enum
738ccd4a63SDavid du Colombier {
748ccd4a63SDavid du Colombier Maxdmsg= 1<<16,
758ccd4a63SDavid du Colombier Maxdstate= 128, /* must be a power of 2 */
768ccd4a63SDavid du Colombier };
778ccd4a63SDavid du Colombier
788ccd4a63SDavid du Colombier Lock dslock;
798ccd4a63SDavid du Colombier int dshiwat;
808ccd4a63SDavid du Colombier char *dsname[Maxdstate];
818ccd4a63SDavid du Colombier Dstate *dstate[Maxdstate];
828ccd4a63SDavid du Colombier char *encalgs;
838ccd4a63SDavid du Colombier char *hashalgs;
848ccd4a63SDavid du Colombier
858ccd4a63SDavid du Colombier enum{
868ccd4a63SDavid du Colombier Qtopdir = 1, /* top level directory */
878ccd4a63SDavid du Colombier Qprotodir,
888ccd4a63SDavid du Colombier Qclonus,
898ccd4a63SDavid du Colombier Qconvdir, /* directory for a conversation */
908ccd4a63SDavid du Colombier Qdata,
918ccd4a63SDavid du Colombier Qctl,
928ccd4a63SDavid du Colombier Qsecretin,
938ccd4a63SDavid du Colombier Qsecretout,
948ccd4a63SDavid du Colombier Qencalgs,
958ccd4a63SDavid du Colombier Qhashalgs,
968ccd4a63SDavid du Colombier };
978ccd4a63SDavid du Colombier
988ccd4a63SDavid du Colombier #define TYPE(x) ((x).path & 0xf)
998ccd4a63SDavid du Colombier #define CONV(x) (((x).path >> 5)&(Maxdstate-1))
1008ccd4a63SDavid du Colombier #define QID(c, y) (((c)<<5) | (y))
1018ccd4a63SDavid du Colombier
1028ccd4a63SDavid du Colombier static void ensure(Dstate*, Block**, int);
1038ccd4a63SDavid du Colombier static void consume(Block**, uchar*, int);
1048ccd4a63SDavid du Colombier static void setsecret(OneWay*, uchar*, int);
1058ccd4a63SDavid du Colombier static Block* encryptb(Dstate*, Block*, int);
1068ccd4a63SDavid du Colombier static Block* decryptb(Dstate*, Block*);
1078ccd4a63SDavid du Colombier static Block* digestb(Dstate*, Block*, int);
1088ccd4a63SDavid du Colombier static void checkdigestb(Dstate*, Block*);
1098ccd4a63SDavid du Colombier static Chan* buftochan(char*);
1108ccd4a63SDavid du Colombier static void sslhangup(Dstate*);
1118ccd4a63SDavid du Colombier static Dstate* dsclone(Chan *c);
1128ccd4a63SDavid du Colombier static void dsnew(Chan *c, Dstate **);
1138ccd4a63SDavid du Colombier static long sslput(Dstate *s, Block * volatile b);
1148ccd4a63SDavid du Colombier
1158ccd4a63SDavid du Colombier char *sslnames[] = {
1168ccd4a63SDavid du Colombier /* unused */ 0,
1178ccd4a63SDavid du Colombier /* topdir */ 0,
1188ccd4a63SDavid du Colombier /* protodir */ 0,
1198ccd4a63SDavid du Colombier "clone",
1208ccd4a63SDavid du Colombier /* convdir */ 0,
1218ccd4a63SDavid du Colombier "data",
1228ccd4a63SDavid du Colombier "ctl",
1238ccd4a63SDavid du Colombier "secretin",
1248ccd4a63SDavid du Colombier "secretout",
1258ccd4a63SDavid du Colombier "encalgs",
1268ccd4a63SDavid du Colombier "hashalgs",
1278ccd4a63SDavid du Colombier };
1288ccd4a63SDavid du Colombier
1298ccd4a63SDavid du Colombier static int
sslgen(Chan * c,char * n,Dirtab * d,int nd,int s,Dir * dp)1308ccd4a63SDavid du Colombier sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
1318ccd4a63SDavid du Colombier {
1328ccd4a63SDavid du Colombier Qid q;
1338ccd4a63SDavid du Colombier Dstate *ds;
1348ccd4a63SDavid du Colombier char name[16], *p, *nm;
1358ccd4a63SDavid du Colombier int ft;
1368ccd4a63SDavid du Colombier
1378ccd4a63SDavid du Colombier USED(n);
1388ccd4a63SDavid du Colombier USED(nd);
1398ccd4a63SDavid du Colombier USED(d);
1408ccd4a63SDavid du Colombier
1418ccd4a63SDavid du Colombier q.type = QTFILE;
1428ccd4a63SDavid du Colombier q.vers = 0;
1438ccd4a63SDavid du Colombier
1448ccd4a63SDavid du Colombier ft = TYPE(c->qid);
1458ccd4a63SDavid du Colombier switch(ft) {
1468ccd4a63SDavid du Colombier case Qtopdir:
1478ccd4a63SDavid du Colombier if(s == DEVDOTDOT){
1488ccd4a63SDavid du Colombier q.path = QID(0, Qtopdir);
1498ccd4a63SDavid du Colombier q.type = QTDIR;
1508ccd4a63SDavid du Colombier devdir(c, q, "#D", 0, eve, 0555, dp);
1518ccd4a63SDavid du Colombier return 1;
1528ccd4a63SDavid du Colombier }
1538ccd4a63SDavid du Colombier if(s > 0)
1548ccd4a63SDavid du Colombier return -1;
1558ccd4a63SDavid du Colombier q.path = QID(0, Qprotodir);
1568ccd4a63SDavid du Colombier q.type = QTDIR;
1578ccd4a63SDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1588ccd4a63SDavid du Colombier return 1;
1598ccd4a63SDavid du Colombier case Qprotodir:
1608ccd4a63SDavid du Colombier if(s == DEVDOTDOT){
1618ccd4a63SDavid du Colombier q.path = QID(0, Qtopdir);
1628ccd4a63SDavid du Colombier q.type = QTDIR;
1638ccd4a63SDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp);
1648ccd4a63SDavid du Colombier return 1;
1658ccd4a63SDavid du Colombier }
1668ccd4a63SDavid du Colombier if(s < dshiwat) {
1678ccd4a63SDavid du Colombier q.path = QID(s, Qconvdir);
1688ccd4a63SDavid du Colombier q.type = QTDIR;
1698ccd4a63SDavid du Colombier ds = dstate[s];
1708ccd4a63SDavid du Colombier if(ds != 0)
1718ccd4a63SDavid du Colombier nm = ds->user;
1728ccd4a63SDavid du Colombier else
1738ccd4a63SDavid du Colombier nm = eve;
1748ccd4a63SDavid du Colombier if(dsname[s] == nil){
1758ccd4a63SDavid du Colombier sprint(name, "%d", s);
1768ccd4a63SDavid du Colombier kstrdup(&dsname[s], name);
1778ccd4a63SDavid du Colombier }
1788ccd4a63SDavid du Colombier devdir(c, q, dsname[s], 0, nm, 0555, dp);
1798ccd4a63SDavid du Colombier return 1;
1808ccd4a63SDavid du Colombier }
1818ccd4a63SDavid du Colombier if(s > dshiwat)
1828ccd4a63SDavid du Colombier return -1;
1838ccd4a63SDavid du Colombier q.path = QID(0, Qclonus);
1848ccd4a63SDavid du Colombier devdir(c, q, "clone", 0, eve, 0555, dp);
1858ccd4a63SDavid du Colombier return 1;
1868ccd4a63SDavid du Colombier case Qconvdir:
1878ccd4a63SDavid du Colombier if(s == DEVDOTDOT){
1888ccd4a63SDavid du Colombier q.path = QID(0, Qprotodir);
1898ccd4a63SDavid du Colombier q.type = QTDIR;
1908ccd4a63SDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1918ccd4a63SDavid du Colombier return 1;
1928ccd4a63SDavid du Colombier }
1938ccd4a63SDavid du Colombier ds = dstate[CONV(c->qid)];
1948ccd4a63SDavid du Colombier if(ds != 0)
1958ccd4a63SDavid du Colombier nm = ds->user;
1968ccd4a63SDavid du Colombier else
1978ccd4a63SDavid du Colombier nm = eve;
1988ccd4a63SDavid du Colombier switch(s) {
1998ccd4a63SDavid du Colombier default:
2008ccd4a63SDavid du Colombier return -1;
2018ccd4a63SDavid du Colombier case 0:
2028ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qctl);
2038ccd4a63SDavid du Colombier p = "ctl";
2048ccd4a63SDavid du Colombier break;
2058ccd4a63SDavid du Colombier case 1:
2068ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qdata);
2078ccd4a63SDavid du Colombier p = "data";
2088ccd4a63SDavid du Colombier break;
2098ccd4a63SDavid du Colombier case 2:
2108ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qsecretin);
2118ccd4a63SDavid du Colombier p = "secretin";
2128ccd4a63SDavid du Colombier break;
2138ccd4a63SDavid du Colombier case 3:
2148ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qsecretout);
2158ccd4a63SDavid du Colombier p = "secretout";
2168ccd4a63SDavid du Colombier break;
2178ccd4a63SDavid du Colombier case 4:
2188ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qencalgs);
2198ccd4a63SDavid du Colombier p = "encalgs";
2208ccd4a63SDavid du Colombier break;
2218ccd4a63SDavid du Colombier case 5:
2228ccd4a63SDavid du Colombier q.path = QID(CONV(c->qid), Qhashalgs);
2238ccd4a63SDavid du Colombier p = "hashalgs";
2248ccd4a63SDavid du Colombier break;
2258ccd4a63SDavid du Colombier }
2268ccd4a63SDavid du Colombier devdir(c, q, p, 0, nm, 0660, dp);
2278ccd4a63SDavid du Colombier return 1;
2288ccd4a63SDavid du Colombier case Qclonus:
2298ccd4a63SDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
2308ccd4a63SDavid du Colombier return 1;
2318ccd4a63SDavid du Colombier default:
2328ccd4a63SDavid du Colombier ds = dstate[CONV(c->qid)];
2338ccd4a63SDavid du Colombier if(ds != 0)
2348ccd4a63SDavid du Colombier nm = ds->user;
2358ccd4a63SDavid du Colombier else
2368ccd4a63SDavid du Colombier nm = eve;
2378ccd4a63SDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
2388ccd4a63SDavid du Colombier return 1;
2398ccd4a63SDavid du Colombier }
2408ccd4a63SDavid du Colombier return -1;
2418ccd4a63SDavid du Colombier }
2428ccd4a63SDavid du Colombier
2438ccd4a63SDavid du Colombier static Chan*
sslattach(char * spec)2448ccd4a63SDavid du Colombier sslattach(char *spec)
2458ccd4a63SDavid du Colombier {
2468ccd4a63SDavid du Colombier Chan *c;
2478ccd4a63SDavid du Colombier
2488ccd4a63SDavid du Colombier c = devattach('D', spec);
2498ccd4a63SDavid du Colombier c->qid.path = QID(0, Qtopdir);
2508ccd4a63SDavid du Colombier c->qid.vers = 0;
2518ccd4a63SDavid du Colombier c->qid.type = QTDIR;
2528ccd4a63SDavid du Colombier return c;
2538ccd4a63SDavid du Colombier }
2548ccd4a63SDavid du Colombier
2558ccd4a63SDavid du Colombier static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)2568ccd4a63SDavid du Colombier sslwalk(Chan *c, Chan *nc, char **name, int nname)
2578ccd4a63SDavid du Colombier {
2588ccd4a63SDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, sslgen);
2598ccd4a63SDavid du Colombier }
2608ccd4a63SDavid du Colombier
2618ccd4a63SDavid du Colombier static int
sslstat(Chan * c,uchar * db,int n)2628ccd4a63SDavid du Colombier sslstat(Chan *c, uchar *db, int n)
2638ccd4a63SDavid du Colombier {
2648ccd4a63SDavid du Colombier return devstat(c, db, n, nil, 0, sslgen);
2658ccd4a63SDavid du Colombier }
2668ccd4a63SDavid du Colombier
2678ccd4a63SDavid du Colombier static Chan*
sslopen(Chan * c,int omode)2688ccd4a63SDavid du Colombier sslopen(Chan *c, int omode)
2698ccd4a63SDavid du Colombier {
2708ccd4a63SDavid du Colombier Dstate *s, **pp;
2718ccd4a63SDavid du Colombier int perm;
2728ccd4a63SDavid du Colombier int ft;
2738ccd4a63SDavid du Colombier
2748ccd4a63SDavid du Colombier perm = 0;
2758ccd4a63SDavid du Colombier omode &= 3;
2768ccd4a63SDavid du Colombier switch(omode) {
2778ccd4a63SDavid du Colombier case OREAD:
2788ccd4a63SDavid du Colombier perm = 4;
2798ccd4a63SDavid du Colombier break;
2808ccd4a63SDavid du Colombier case OWRITE:
2818ccd4a63SDavid du Colombier perm = 2;
2828ccd4a63SDavid du Colombier break;
2838ccd4a63SDavid du Colombier case ORDWR:
2848ccd4a63SDavid du Colombier perm = 6;
2858ccd4a63SDavid du Colombier break;
2868ccd4a63SDavid du Colombier }
2878ccd4a63SDavid du Colombier
2888ccd4a63SDavid du Colombier ft = TYPE(c->qid);
2898ccd4a63SDavid du Colombier switch(ft) {
2908ccd4a63SDavid du Colombier default:
2918ccd4a63SDavid du Colombier panic("sslopen");
2928ccd4a63SDavid du Colombier case Qtopdir:
2938ccd4a63SDavid du Colombier case Qprotodir:
2948ccd4a63SDavid du Colombier case Qconvdir:
2958ccd4a63SDavid du Colombier if(omode != OREAD)
2968ccd4a63SDavid du Colombier error(Eperm);
2978ccd4a63SDavid du Colombier break;
2988ccd4a63SDavid du Colombier case Qclonus:
2998ccd4a63SDavid du Colombier s = dsclone(c);
3008ccd4a63SDavid du Colombier if(s == 0)
3018ccd4a63SDavid du Colombier error(Enodev);
3028ccd4a63SDavid du Colombier break;
3038ccd4a63SDavid du Colombier case Qctl:
3048ccd4a63SDavid du Colombier case Qdata:
3058ccd4a63SDavid du Colombier case Qsecretin:
3068ccd4a63SDavid du Colombier case Qsecretout:
3078ccd4a63SDavid du Colombier if(waserror()) {
3088ccd4a63SDavid du Colombier unlock(&dslock);
3098ccd4a63SDavid du Colombier nexterror();
3108ccd4a63SDavid du Colombier }
3118ccd4a63SDavid du Colombier lock(&dslock);
3128ccd4a63SDavid du Colombier pp = &dstate[CONV(c->qid)];
3138ccd4a63SDavid du Colombier s = *pp;
3148ccd4a63SDavid du Colombier if(s == 0)
3158ccd4a63SDavid du Colombier dsnew(c, pp);
3168ccd4a63SDavid du Colombier else {
3178ccd4a63SDavid du Colombier if((perm & (s->perm>>6)) != perm
3188ccd4a63SDavid du Colombier && (strcmp(up->user, s->user) != 0
3198ccd4a63SDavid du Colombier || (perm & s->perm) != perm))
3208ccd4a63SDavid du Colombier error(Eperm);
3218ccd4a63SDavid du Colombier
3228ccd4a63SDavid du Colombier s->ref++;
3238ccd4a63SDavid du Colombier }
3248ccd4a63SDavid du Colombier unlock(&dslock);
3258ccd4a63SDavid du Colombier poperror();
3268ccd4a63SDavid du Colombier break;
3278ccd4a63SDavid du Colombier case Qencalgs:
3288ccd4a63SDavid du Colombier case Qhashalgs:
3298ccd4a63SDavid du Colombier if(omode != OREAD)
3308ccd4a63SDavid du Colombier error(Eperm);
3318ccd4a63SDavid du Colombier break;
3328ccd4a63SDavid du Colombier }
3338ccd4a63SDavid du Colombier c->mode = openmode(omode);
3348ccd4a63SDavid du Colombier c->flag |= COPEN;
3358ccd4a63SDavid du Colombier c->offset = 0;
3368ccd4a63SDavid du Colombier return c;
3378ccd4a63SDavid du Colombier }
3388ccd4a63SDavid du Colombier
3398ccd4a63SDavid du Colombier static int
sslwstat(Chan * c,uchar * db,int n)3408ccd4a63SDavid du Colombier sslwstat(Chan *c, uchar *db, int n)
3418ccd4a63SDavid du Colombier {
3428ccd4a63SDavid du Colombier Dir *dir;
3438ccd4a63SDavid du Colombier Dstate *s;
3448ccd4a63SDavid du Colombier int m;
3458ccd4a63SDavid du Colombier
3468ccd4a63SDavid du Colombier s = dstate[CONV(c->qid)];
3478ccd4a63SDavid du Colombier if(s == 0)
3488ccd4a63SDavid du Colombier error(Ebadusefd);
3498ccd4a63SDavid du Colombier if(strcmp(s->user, up->user) != 0)
3508ccd4a63SDavid du Colombier error(Eperm);
3518ccd4a63SDavid du Colombier
3528ccd4a63SDavid du Colombier dir = smalloc(sizeof(Dir)+n);
3538ccd4a63SDavid du Colombier m = convM2D(db, n, &dir[0], (char*)&dir[1]);
3548ccd4a63SDavid du Colombier if(m == 0){
3558ccd4a63SDavid du Colombier free(dir);
3568ccd4a63SDavid du Colombier error(Eshortstat);
3578ccd4a63SDavid du Colombier }
3588ccd4a63SDavid du Colombier
3598ccd4a63SDavid du Colombier if(!emptystr(dir->uid))
3608ccd4a63SDavid du Colombier kstrdup(&s->user, dir->uid);
361*ec59a3ddSDavid du Colombier if(dir->mode != ~0)
3628ccd4a63SDavid du Colombier s->perm = dir->mode;
3638ccd4a63SDavid du Colombier
3648ccd4a63SDavid du Colombier free(dir);
3658ccd4a63SDavid du Colombier return m;
3668ccd4a63SDavid du Colombier }
3678ccd4a63SDavid du Colombier
3688ccd4a63SDavid du Colombier static void
sslclose(Chan * c)3698ccd4a63SDavid du Colombier sslclose(Chan *c)
3708ccd4a63SDavid du Colombier {
3718ccd4a63SDavid du Colombier Dstate *s;
3728ccd4a63SDavid du Colombier int ft;
3738ccd4a63SDavid du Colombier
3748ccd4a63SDavid du Colombier ft = TYPE(c->qid);
3758ccd4a63SDavid du Colombier switch(ft) {
3768ccd4a63SDavid du Colombier case Qctl:
3778ccd4a63SDavid du Colombier case Qdata:
3788ccd4a63SDavid du Colombier case Qsecretin:
3798ccd4a63SDavid du Colombier case Qsecretout:
3808ccd4a63SDavid du Colombier if((c->flag & COPEN) == 0)
3818ccd4a63SDavid du Colombier break;
3828ccd4a63SDavid du Colombier
3838ccd4a63SDavid du Colombier s = dstate[CONV(c->qid)];
3848ccd4a63SDavid du Colombier if(s == 0)
3858ccd4a63SDavid du Colombier break;
3868ccd4a63SDavid du Colombier
3878ccd4a63SDavid du Colombier lock(&dslock);
3888ccd4a63SDavid du Colombier if(--s->ref > 0) {
3898ccd4a63SDavid du Colombier unlock(&dslock);
3908ccd4a63SDavid du Colombier break;
3918ccd4a63SDavid du Colombier }
3928ccd4a63SDavid du Colombier dstate[CONV(c->qid)] = 0;
3938ccd4a63SDavid du Colombier unlock(&dslock);
3948ccd4a63SDavid du Colombier
3958ccd4a63SDavid du Colombier if(s->user != nil)
3968ccd4a63SDavid du Colombier free(s->user);
3978ccd4a63SDavid du Colombier sslhangup(s);
3988ccd4a63SDavid du Colombier if(s->c)
3998ccd4a63SDavid du Colombier cclose(s->c);
4008ccd4a63SDavid du Colombier if(s->in.secret)
4018ccd4a63SDavid du Colombier free(s->in.secret);
4028ccd4a63SDavid du Colombier if(s->out.secret)
4038ccd4a63SDavid du Colombier free(s->out.secret);
4048ccd4a63SDavid du Colombier if(s->in.state)
4058ccd4a63SDavid du Colombier free(s->in.state);
4068ccd4a63SDavid du Colombier if(s->out.state)
4078ccd4a63SDavid du Colombier free(s->out.state);
4088ccd4a63SDavid du Colombier free(s);
4098ccd4a63SDavid du Colombier
4108ccd4a63SDavid du Colombier }
4118ccd4a63SDavid du Colombier }
4128ccd4a63SDavid du Colombier
4138ccd4a63SDavid du Colombier /*
4148ccd4a63SDavid du Colombier * make sure we have at least 'n' bytes in list 'l'
4158ccd4a63SDavid du Colombier */
4168ccd4a63SDavid du Colombier static void
ensure(Dstate * s,Block ** l,int n)4178ccd4a63SDavid du Colombier ensure(Dstate *s, Block **l, int n)
4188ccd4a63SDavid du Colombier {
4198ccd4a63SDavid du Colombier int sofar, i;
4208ccd4a63SDavid du Colombier Block *b, *bl;
4218ccd4a63SDavid du Colombier
4228ccd4a63SDavid du Colombier sofar = 0;
4238ccd4a63SDavid du Colombier for(b = *l; b; b = b->next){
4248ccd4a63SDavid du Colombier sofar += BLEN(b);
4258ccd4a63SDavid du Colombier if(sofar >= n)
4268ccd4a63SDavid du Colombier return;
4278ccd4a63SDavid du Colombier l = &b->next;
4288ccd4a63SDavid du Colombier }
4298ccd4a63SDavid du Colombier
4308ccd4a63SDavid du Colombier while(sofar < n){
4318ccd4a63SDavid du Colombier bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
4328ccd4a63SDavid du Colombier if(bl == 0)
4338ccd4a63SDavid du Colombier nexterror();
4348ccd4a63SDavid du Colombier *l = bl;
4358ccd4a63SDavid du Colombier i = 0;
4368ccd4a63SDavid du Colombier for(b = bl; b; b = b->next){
4378ccd4a63SDavid du Colombier i += BLEN(b);
4388ccd4a63SDavid du Colombier l = &b->next;
4398ccd4a63SDavid du Colombier }
4408ccd4a63SDavid du Colombier if(i == 0)
4418ccd4a63SDavid du Colombier error(Ehungup);
4428ccd4a63SDavid du Colombier sofar += i;
4438ccd4a63SDavid du Colombier }
4448ccd4a63SDavid du Colombier }
4458ccd4a63SDavid du Colombier
4468ccd4a63SDavid du Colombier /*
4478ccd4a63SDavid du Colombier * copy 'n' bytes from 'l' into 'p' and free
4488ccd4a63SDavid du Colombier * the bytes in 'l'
4498ccd4a63SDavid du Colombier */
4508ccd4a63SDavid du Colombier static void
consume(Block ** l,uchar * p,int n)4518ccd4a63SDavid du Colombier consume(Block **l, uchar *p, int n)
4528ccd4a63SDavid du Colombier {
4538ccd4a63SDavid du Colombier Block *b;
4548ccd4a63SDavid du Colombier int i;
4558ccd4a63SDavid du Colombier
4568ccd4a63SDavid du Colombier for(; *l && n > 0; n -= i){
4578ccd4a63SDavid du Colombier b = *l;
4588ccd4a63SDavid du Colombier i = BLEN(b);
4598ccd4a63SDavid du Colombier if(i > n)
4608ccd4a63SDavid du Colombier i = n;
4618ccd4a63SDavid du Colombier memmove(p, b->rp, i);
4628ccd4a63SDavid du Colombier b->rp += i;
4638ccd4a63SDavid du Colombier p += i;
4648ccd4a63SDavid du Colombier if(BLEN(b) < 0)
4658ccd4a63SDavid du Colombier panic("consume");
4668ccd4a63SDavid du Colombier if(BLEN(b))
4678ccd4a63SDavid du Colombier break;
4688ccd4a63SDavid du Colombier *l = b->next;
4698ccd4a63SDavid du Colombier freeb(b);
4708ccd4a63SDavid du Colombier }
4718ccd4a63SDavid du Colombier }
4728ccd4a63SDavid du Colombier
4738ccd4a63SDavid du Colombier /*
4748ccd4a63SDavid du Colombier * give back n bytes
4758ccd4a63SDavid du Colombier static void
4768ccd4a63SDavid du Colombier regurgitate(Dstate *s, uchar *p, int n)
4778ccd4a63SDavid du Colombier {
4788ccd4a63SDavid du Colombier Block *b;
4798ccd4a63SDavid du Colombier
4808ccd4a63SDavid du Colombier if(n <= 0)
4818ccd4a63SDavid du Colombier return;
4828ccd4a63SDavid du Colombier b = s->unprocessed;
4838ccd4a63SDavid du Colombier if(s->unprocessed == nil || b->rp - b->base < n) {
4848ccd4a63SDavid du Colombier b = allocb(n);
4858ccd4a63SDavid du Colombier memmove(b->wp, p, n);
4868ccd4a63SDavid du Colombier b->wp += n;
4878ccd4a63SDavid du Colombier b->next = s->unprocessed;
4888ccd4a63SDavid du Colombier s->unprocessed = b;
4898ccd4a63SDavid du Colombier } else {
4908ccd4a63SDavid du Colombier b->rp -= n;
4918ccd4a63SDavid du Colombier memmove(b->rp, p, n);
4928ccd4a63SDavid du Colombier }
4938ccd4a63SDavid du Colombier }
4948ccd4a63SDavid du Colombier */
4958ccd4a63SDavid du Colombier
4968ccd4a63SDavid du Colombier /*
4978ccd4a63SDavid du Colombier * remove at most n bytes from the queue, if discard is set
4988ccd4a63SDavid du Colombier * dump the remainder
4998ccd4a63SDavid du Colombier */
5008ccd4a63SDavid du Colombier static Block*
qtake(Block ** l,int n,int discard)5018ccd4a63SDavid du Colombier qtake(Block **l, int n, int discard)
5028ccd4a63SDavid du Colombier {
5038ccd4a63SDavid du Colombier Block *nb, *b, *first;
5048ccd4a63SDavid du Colombier int i;
5058ccd4a63SDavid du Colombier
5068ccd4a63SDavid du Colombier first = *l;
5078ccd4a63SDavid du Colombier for(b = first; b; b = b->next){
5088ccd4a63SDavid du Colombier i = BLEN(b);
5098ccd4a63SDavid du Colombier if(i == n){
5108ccd4a63SDavid du Colombier if(discard){
5118ccd4a63SDavid du Colombier freeblist(b->next);
5128ccd4a63SDavid du Colombier *l = 0;
5138ccd4a63SDavid du Colombier } else
5148ccd4a63SDavid du Colombier *l = b->next;
5158ccd4a63SDavid du Colombier b->next = 0;
5168ccd4a63SDavid du Colombier return first;
5178ccd4a63SDavid du Colombier } else if(i > n){
5188ccd4a63SDavid du Colombier i -= n;
5198ccd4a63SDavid du Colombier if(discard){
5208ccd4a63SDavid du Colombier freeblist(b->next);
5218ccd4a63SDavid du Colombier b->wp -= i;
5228ccd4a63SDavid du Colombier *l = 0;
5238ccd4a63SDavid du Colombier } else {
5248ccd4a63SDavid du Colombier nb = allocb(i);
5258ccd4a63SDavid du Colombier memmove(nb->wp, b->rp+n, i);
5268ccd4a63SDavid du Colombier nb->wp += i;
5278ccd4a63SDavid du Colombier b->wp -= i;
5288ccd4a63SDavid du Colombier nb->next = b->next;
5298ccd4a63SDavid du Colombier *l = nb;
5308ccd4a63SDavid du Colombier }
5318ccd4a63SDavid du Colombier b->next = 0;
5328ccd4a63SDavid du Colombier if(BLEN(b) < 0)
5338ccd4a63SDavid du Colombier panic("qtake");
5348ccd4a63SDavid du Colombier return first;
5358ccd4a63SDavid du Colombier } else
5368ccd4a63SDavid du Colombier n -= i;
5378ccd4a63SDavid du Colombier if(BLEN(b) < 0)
5388ccd4a63SDavid du Colombier panic("qtake");
5398ccd4a63SDavid du Colombier }
5408ccd4a63SDavid du Colombier *l = 0;
5418ccd4a63SDavid du Colombier return first;
5428ccd4a63SDavid du Colombier }
5438ccd4a63SDavid du Colombier
5448ccd4a63SDavid du Colombier /*
5458ccd4a63SDavid du Colombier * We can't let Eintr's lose data since the program
5468ccd4a63SDavid du Colombier * doing the read may be able to handle it. The only
5478ccd4a63SDavid du Colombier * places Eintr is possible is during the read's in consume.
5488ccd4a63SDavid du Colombier * Therefore, we make sure we can always put back the bytes
5498ccd4a63SDavid du Colombier * consumed before the last ensure.
5508ccd4a63SDavid du Colombier */
5518ccd4a63SDavid du Colombier static Block*
sslbread(Chan * c,long n,ulong o)5528ccd4a63SDavid du Colombier sslbread(Chan *c, long n, ulong o)
5538ccd4a63SDavid du Colombier {
5548ccd4a63SDavid du Colombier Dstate * volatile s;
5558ccd4a63SDavid du Colombier Block *b;
5568ccd4a63SDavid du Colombier uchar consumed[3], *p;
5578ccd4a63SDavid du Colombier int toconsume;
5588ccd4a63SDavid du Colombier int len, pad;
5598ccd4a63SDavid du Colombier
5608ccd4a63SDavid du Colombier USED(o);
5618ccd4a63SDavid du Colombier s = dstate[CONV(c->qid)];
5628ccd4a63SDavid du Colombier if(s == 0)
5638ccd4a63SDavid du Colombier panic("sslbread");
5648ccd4a63SDavid du Colombier if(s->state == Sincomplete)
5658ccd4a63SDavid du Colombier error(Ebadusefd);
5668ccd4a63SDavid du Colombier
5678ccd4a63SDavid du Colombier qlock(&s->in.q);
5688ccd4a63SDavid du Colombier if(waserror()){
5698ccd4a63SDavid du Colombier qunlock(&s->in.q);
5708ccd4a63SDavid du Colombier nexterror();
5718ccd4a63SDavid du Colombier }
5728ccd4a63SDavid du Colombier
5738ccd4a63SDavid du Colombier if(s->processed == 0){
5748ccd4a63SDavid du Colombier /*
5758ccd4a63SDavid du Colombier * Read in the whole message. Until we've got it all,
5768ccd4a63SDavid du Colombier * it stays on s->unprocessed, so that if we get Eintr,
5778ccd4a63SDavid du Colombier * we'll pick up where we left off.
5788ccd4a63SDavid du Colombier */
5798ccd4a63SDavid du Colombier ensure(s, &s->unprocessed, 3);
5808ccd4a63SDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 2);
5818ccd4a63SDavid du Colombier p = s->unprocessed->rp;
5828ccd4a63SDavid du Colombier if(p[0] & 0x80){
5838ccd4a63SDavid du Colombier len = ((p[0] & 0x7f)<<8) | p[1];
5848ccd4a63SDavid du Colombier ensure(s, &s->unprocessed, len);
5858ccd4a63SDavid du Colombier pad = 0;
5868ccd4a63SDavid du Colombier toconsume = 2;
5878ccd4a63SDavid du Colombier } else {
5888ccd4a63SDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 3);
5898ccd4a63SDavid du Colombier len = ((p[0] & 0x3f)<<8) | p[1];
5908ccd4a63SDavid du Colombier pad = p[2];
5918ccd4a63SDavid du Colombier if(pad > len){
5928ccd4a63SDavid du Colombier print("pad %d buf len %d\n", pad, len);
5938ccd4a63SDavid du Colombier error("bad pad in ssl message");
5948ccd4a63SDavid du Colombier }
5958ccd4a63SDavid du Colombier toconsume = 3;
5968ccd4a63SDavid du Colombier }
5978ccd4a63SDavid du Colombier ensure(s, &s->unprocessed, toconsume+len);
5988ccd4a63SDavid du Colombier
5998ccd4a63SDavid du Colombier /* skip header */
6008ccd4a63SDavid du Colombier consume(&s->unprocessed, consumed, toconsume);
6018ccd4a63SDavid du Colombier
6028ccd4a63SDavid du Colombier /* grab the next message and decode/decrypt it */
6038ccd4a63SDavid du Colombier b = qtake(&s->unprocessed, len, 0);
6048ccd4a63SDavid du Colombier
6058ccd4a63SDavid du Colombier if(blocklen(b) != len)
6068ccd4a63SDavid du Colombier print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
6078ccd4a63SDavid du Colombier
6088ccd4a63SDavid du Colombier if(waserror()){
6098ccd4a63SDavid du Colombier qunlock(&s->in.ctlq);
6108ccd4a63SDavid du Colombier if(b != nil)
6118ccd4a63SDavid du Colombier freeb(b);
6128ccd4a63SDavid du Colombier nexterror();
6138ccd4a63SDavid du Colombier }
6148ccd4a63SDavid du Colombier qlock(&s->in.ctlq);
6158ccd4a63SDavid du Colombier switch(s->state){
6168ccd4a63SDavid du Colombier case Sencrypting:
6178ccd4a63SDavid du Colombier if(b == nil)
6188ccd4a63SDavid du Colombier error("ssl message too short (encrypting)");
6198ccd4a63SDavid du Colombier b = decryptb(s, b);
6208ccd4a63SDavid du Colombier break;
6218ccd4a63SDavid du Colombier case Sdigesting:
6228ccd4a63SDavid du Colombier b = pullupblock(b, s->diglen);
6238ccd4a63SDavid du Colombier if(b == nil)
6248ccd4a63SDavid du Colombier error("ssl message too short (digesting)");
6258ccd4a63SDavid du Colombier checkdigestb(s, b);
6268ccd4a63SDavid du Colombier pullblock(&b, s->diglen);
6278ccd4a63SDavid du Colombier len -= s->diglen;
6288ccd4a63SDavid du Colombier break;
6298ccd4a63SDavid du Colombier case Sdigenc:
6308ccd4a63SDavid du Colombier b = decryptb(s, b);
6318ccd4a63SDavid du Colombier b = pullupblock(b, s->diglen);
6328ccd4a63SDavid du Colombier if(b == nil)
6338ccd4a63SDavid du Colombier error("ssl message too short (dig+enc)");
6348ccd4a63SDavid du Colombier checkdigestb(s, b);
6358ccd4a63SDavid du Colombier pullblock(&b, s->diglen);
6368ccd4a63SDavid du Colombier len -= s->diglen;
6378ccd4a63SDavid du Colombier break;
6388ccd4a63SDavid du Colombier }
6398ccd4a63SDavid du Colombier
6408ccd4a63SDavid du Colombier /* remove pad */
6418ccd4a63SDavid du Colombier if(pad)
6428ccd4a63SDavid du Colombier s->processed = qtake(&b, len - pad, 1);
6438ccd4a63SDavid du Colombier else
6448ccd4a63SDavid du Colombier s->processed = b;
6458ccd4a63SDavid du Colombier b = nil;
6468ccd4a63SDavid du Colombier s->in.mid++;
6478ccd4a63SDavid du Colombier qunlock(&s->in.ctlq);
6488ccd4a63SDavid du Colombier poperror();
6498ccd4a63SDavid du Colombier }
6508ccd4a63SDavid du Colombier
6518ccd4a63SDavid du Colombier /* return at most what was asked for */
6528ccd4a63SDavid du Colombier b = qtake(&s->processed, n, 0);
6538ccd4a63SDavid du Colombier
6548ccd4a63SDavid du Colombier qunlock(&s->in.q);
6558ccd4a63SDavid du Colombier poperror();
6568ccd4a63SDavid du Colombier
6578ccd4a63SDavid du Colombier return b;
6588ccd4a63SDavid du Colombier }
6598ccd4a63SDavid du Colombier
6608ccd4a63SDavid du Colombier static long
sslread(Chan * c,void * a,long n,vlong off)6618ccd4a63SDavid du Colombier sslread(Chan *c, void *a, long n, vlong off)
6628ccd4a63SDavid du Colombier {
6638ccd4a63SDavid du Colombier Block * volatile b;
6648ccd4a63SDavid du Colombier Block *nb;
6658ccd4a63SDavid du Colombier uchar *va;
6668ccd4a63SDavid du Colombier int i;
6678ccd4a63SDavid du Colombier char buf[128];
6688ccd4a63SDavid du Colombier ulong offset = off;
6698ccd4a63SDavid du Colombier int ft;
6708ccd4a63SDavid du Colombier
6718ccd4a63SDavid du Colombier if(c->qid.type & QTDIR)
6728ccd4a63SDavid du Colombier return devdirread(c, a, n, 0, 0, sslgen);
6738ccd4a63SDavid du Colombier
6748ccd4a63SDavid du Colombier ft = TYPE(c->qid);
6758ccd4a63SDavid du Colombier switch(ft) {
6768ccd4a63SDavid du Colombier default:
6778ccd4a63SDavid du Colombier error(Ebadusefd);
6788ccd4a63SDavid du Colombier case Qctl:
6798ccd4a63SDavid du Colombier ft = CONV(c->qid);
6808ccd4a63SDavid du Colombier sprint(buf, "%d", ft);
6818ccd4a63SDavid du Colombier return readstr(offset, a, n, buf);
6828ccd4a63SDavid du Colombier case Qdata:
6838ccd4a63SDavid du Colombier b = sslbread(c, n, offset);
6848ccd4a63SDavid du Colombier break;
6858ccd4a63SDavid du Colombier case Qencalgs:
6868ccd4a63SDavid du Colombier return readstr(offset, a, n, encalgs);
6878ccd4a63SDavid du Colombier break;
6888ccd4a63SDavid du Colombier case Qhashalgs:
6898ccd4a63SDavid du Colombier return readstr(offset, a, n, hashalgs);
6908ccd4a63SDavid du Colombier break;
6918ccd4a63SDavid du Colombier }
6928ccd4a63SDavid du Colombier
6938ccd4a63SDavid du Colombier if(waserror()){
6948ccd4a63SDavid du Colombier freeblist(b);
6958ccd4a63SDavid du Colombier nexterror();
6968ccd4a63SDavid du Colombier }
6978ccd4a63SDavid du Colombier
6988ccd4a63SDavid du Colombier n = 0;
6998ccd4a63SDavid du Colombier va = a;
7008ccd4a63SDavid du Colombier for(nb = b; nb; nb = nb->next){
7018ccd4a63SDavid du Colombier i = BLEN(nb);
7028ccd4a63SDavid du Colombier memmove(va+n, nb->rp, i);
7038ccd4a63SDavid du Colombier n += i;
7048ccd4a63SDavid du Colombier }
7058ccd4a63SDavid du Colombier
7068ccd4a63SDavid du Colombier freeblist(b);
7078ccd4a63SDavid du Colombier poperror();
7088ccd4a63SDavid du Colombier
7098ccd4a63SDavid du Colombier return n;
7108ccd4a63SDavid du Colombier }
7118ccd4a63SDavid du Colombier
7128ccd4a63SDavid du Colombier /*
7138ccd4a63SDavid du Colombier * this algorithm doesn't have to be great since we're just
7148ccd4a63SDavid du Colombier * trying to obscure the block fill
7158ccd4a63SDavid du Colombier */
7168ccd4a63SDavid du Colombier static void
randfill(uchar * buf,int len)7178ccd4a63SDavid du Colombier randfill(uchar *buf, int len)
7188ccd4a63SDavid du Colombier {
7198ccd4a63SDavid du Colombier while(len-- > 0)
7208ccd4a63SDavid du Colombier *buf++ = fastrand();
7218ccd4a63SDavid du Colombier }
7228ccd4a63SDavid du Colombier
7238ccd4a63SDavid du Colombier static long
sslbwrite(Chan * c,Block * b,ulong o)7248ccd4a63SDavid du Colombier sslbwrite(Chan *c, Block *b, ulong o)
7258ccd4a63SDavid du Colombier {
7268ccd4a63SDavid du Colombier Dstate * volatile s;
7278ccd4a63SDavid du Colombier long rv;
7288ccd4a63SDavid du Colombier
7298ccd4a63SDavid du Colombier USED(o);
7308ccd4a63SDavid du Colombier s = dstate[CONV(c->qid)];
7318ccd4a63SDavid du Colombier if(s == nil)
7328ccd4a63SDavid du Colombier panic("sslbwrite");
7338ccd4a63SDavid du Colombier
7348ccd4a63SDavid du Colombier if(s->state == Sincomplete){
7358ccd4a63SDavid du Colombier freeb(b);
7368ccd4a63SDavid du Colombier error(Ebadusefd);
7378ccd4a63SDavid du Colombier }
7388ccd4a63SDavid du Colombier
7398ccd4a63SDavid du Colombier /* lock so split writes won't interleave */
7408ccd4a63SDavid du Colombier if(waserror()){
7418ccd4a63SDavid du Colombier qunlock(&s->out.q);
7428ccd4a63SDavid du Colombier nexterror();
7438ccd4a63SDavid du Colombier }
7448ccd4a63SDavid du Colombier qlock(&s->out.q);
7458ccd4a63SDavid du Colombier
7468ccd4a63SDavid du Colombier rv = sslput(s, b);
7478ccd4a63SDavid du Colombier
7488ccd4a63SDavid du Colombier poperror();
7498ccd4a63SDavid du Colombier qunlock(&s->out.q);
7508ccd4a63SDavid du Colombier
7518ccd4a63SDavid du Colombier return rv;
7528ccd4a63SDavid du Colombier }
7538ccd4a63SDavid du Colombier
7548ccd4a63SDavid du Colombier /*
7558ccd4a63SDavid du Colombier * use SSL record format, add in count, digest and/or encrypt.
7568ccd4a63SDavid du Colombier * the write is interruptable. if it is interrupted, we'll
7578ccd4a63SDavid du Colombier * get out of sync with the far side. not much we can do about
7588ccd4a63SDavid du Colombier * it since we don't know if any bytes have been written.
7598ccd4a63SDavid du Colombier */
7608ccd4a63SDavid du Colombier static long
sslput(Dstate * s,Block * volatile b)7618ccd4a63SDavid du Colombier sslput(Dstate *s, Block * volatile b)
7628ccd4a63SDavid du Colombier {
7638ccd4a63SDavid du Colombier Block *nb;
7648ccd4a63SDavid du Colombier int h, n, m, pad, rv;
7658ccd4a63SDavid du Colombier uchar *p;
7668ccd4a63SDavid du Colombier int offset;
7678ccd4a63SDavid du Colombier
7688ccd4a63SDavid du Colombier if(waserror()){
7698ccd4a63SDavid du Colombier iprint("error: %s\n", up->errstr);
7708ccd4a63SDavid du Colombier if(b != nil)
7718ccd4a63SDavid du Colombier free(b);
7728ccd4a63SDavid du Colombier nexterror();
7738ccd4a63SDavid du Colombier }
7748ccd4a63SDavid du Colombier
7758ccd4a63SDavid du Colombier rv = 0;
7768ccd4a63SDavid du Colombier while(b != nil){
7778ccd4a63SDavid du Colombier m = n = BLEN(b);
7788ccd4a63SDavid du Colombier h = s->diglen + 2;
7798ccd4a63SDavid du Colombier
7808ccd4a63SDavid du Colombier /* trim to maximum block size */
7818ccd4a63SDavid du Colombier pad = 0;
7828ccd4a63SDavid du Colombier if(m > s->max){
7838ccd4a63SDavid du Colombier m = s->max;
7848ccd4a63SDavid du Colombier } else if(s->blocklen != 1){
7858ccd4a63SDavid du Colombier pad = (m + s->diglen)%s->blocklen;
7868ccd4a63SDavid du Colombier if(pad){
7878ccd4a63SDavid du Colombier if(m > s->maxpad){
7888ccd4a63SDavid du Colombier pad = 0;
7898ccd4a63SDavid du Colombier m = s->maxpad;
7908ccd4a63SDavid du Colombier } else {
7918ccd4a63SDavid du Colombier pad = s->blocklen - pad;
7928ccd4a63SDavid du Colombier h++;
7938ccd4a63SDavid du Colombier }
7948ccd4a63SDavid du Colombier }
7958ccd4a63SDavid du Colombier }
7968ccd4a63SDavid du Colombier
7978ccd4a63SDavid du Colombier rv += m;
7988ccd4a63SDavid du Colombier if(m != n){
7998ccd4a63SDavid du Colombier nb = allocb(m + h + pad);
8008ccd4a63SDavid du Colombier memmove(nb->wp + h, b->rp, m);
8018ccd4a63SDavid du Colombier nb->wp += m + h;
8028ccd4a63SDavid du Colombier b->rp += m;
8038ccd4a63SDavid du Colombier } else {
8048ccd4a63SDavid du Colombier /* add header space */
8058ccd4a63SDavid du Colombier nb = padblock(b, h);
8068ccd4a63SDavid du Colombier b = 0;
8078ccd4a63SDavid du Colombier }
8088ccd4a63SDavid du Colombier m += s->diglen;
8098ccd4a63SDavid du Colombier
8108ccd4a63SDavid du Colombier /* SSL style count */
8118ccd4a63SDavid du Colombier if(pad){
8128ccd4a63SDavid du Colombier nb = padblock(nb, -pad);
8138ccd4a63SDavid du Colombier randfill(nb->wp, pad);
8148ccd4a63SDavid du Colombier nb->wp += pad;
8158ccd4a63SDavid du Colombier m += pad;
8168ccd4a63SDavid du Colombier
8178ccd4a63SDavid du Colombier p = nb->rp;
8188ccd4a63SDavid du Colombier p[0] = (m>>8);
8198ccd4a63SDavid du Colombier p[1] = m;
8208ccd4a63SDavid du Colombier p[2] = pad;
8218ccd4a63SDavid du Colombier offset = 3;
8228ccd4a63SDavid du Colombier } else {
8238ccd4a63SDavid du Colombier p = nb->rp;
8248ccd4a63SDavid du Colombier p[0] = (m>>8) | 0x80;
8258ccd4a63SDavid du Colombier p[1] = m;
8268ccd4a63SDavid du Colombier offset = 2;
8278ccd4a63SDavid du Colombier }
8288ccd4a63SDavid du Colombier
8298ccd4a63SDavid du Colombier switch(s->state){
8308ccd4a63SDavid du Colombier case Sencrypting:
8318ccd4a63SDavid du Colombier nb = encryptb(s, nb, offset);
8328ccd4a63SDavid du Colombier break;
8338ccd4a63SDavid du Colombier case Sdigesting:
8348ccd4a63SDavid du Colombier nb = digestb(s, nb, offset);
8358ccd4a63SDavid du Colombier break;
8368ccd4a63SDavid du Colombier case Sdigenc:
8378ccd4a63SDavid du Colombier nb = digestb(s, nb, offset);
8388ccd4a63SDavid du Colombier nb = encryptb(s, nb, offset);
8398ccd4a63SDavid du Colombier break;
8408ccd4a63SDavid du Colombier }
8418ccd4a63SDavid du Colombier
8428ccd4a63SDavid du Colombier s->out.mid++;
8438ccd4a63SDavid du Colombier
8448ccd4a63SDavid du Colombier m = BLEN(nb);
8458ccd4a63SDavid du Colombier devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
8468ccd4a63SDavid du Colombier s->c->offset += m;
8478ccd4a63SDavid du Colombier }
8488ccd4a63SDavid du Colombier
8498ccd4a63SDavid du Colombier poperror();
8508ccd4a63SDavid du Colombier return rv;
8518ccd4a63SDavid du Colombier }
8528ccd4a63SDavid du Colombier
8538ccd4a63SDavid du Colombier static void
setsecret(OneWay * w,uchar * secret,int n)8548ccd4a63SDavid du Colombier setsecret(OneWay *w, uchar *secret, int n)
8558ccd4a63SDavid du Colombier {
8568ccd4a63SDavid du Colombier if(w->secret)
8578ccd4a63SDavid du Colombier free(w->secret);
8588ccd4a63SDavid du Colombier
8598ccd4a63SDavid du Colombier w->secret = smalloc(n);
8608ccd4a63SDavid du Colombier memmove(w->secret, secret, n);
8618ccd4a63SDavid du Colombier w->slen = n;
8628ccd4a63SDavid du Colombier }
8638ccd4a63SDavid du Colombier
8648ccd4a63SDavid du Colombier static void
initDESkey(OneWay * w)8658ccd4a63SDavid du Colombier initDESkey(OneWay *w)
8668ccd4a63SDavid du Colombier {
8678ccd4a63SDavid du Colombier if(w->state){
8688ccd4a63SDavid du Colombier free(w->state);
8698ccd4a63SDavid du Colombier w->state = 0;
8708ccd4a63SDavid du Colombier }
8718ccd4a63SDavid du Colombier
8728ccd4a63SDavid du Colombier w->state = smalloc(sizeof(DESstate));
8738ccd4a63SDavid du Colombier if(w->slen >= 16)
8748ccd4a63SDavid du Colombier setupDESstate(w->state, w->secret, w->secret+8);
8758ccd4a63SDavid du Colombier else if(w->slen >= 8)
8768ccd4a63SDavid du Colombier setupDESstate(w->state, w->secret, 0);
8778ccd4a63SDavid du Colombier else
8788ccd4a63SDavid du Colombier error("secret too short");
8798ccd4a63SDavid du Colombier }
8808ccd4a63SDavid du Colombier
8818ccd4a63SDavid du Colombier /*
8828ccd4a63SDavid du Colombier * 40 bit DES is the same as 56 bit DES. However,
8838ccd4a63SDavid du Colombier * 16 bits of the key are masked to zero.
8848ccd4a63SDavid du Colombier */
8858ccd4a63SDavid du Colombier static void
initDESkey_40(OneWay * w)8868ccd4a63SDavid du Colombier initDESkey_40(OneWay *w)
8878ccd4a63SDavid du Colombier {
8888ccd4a63SDavid du Colombier uchar key[8];
8898ccd4a63SDavid du Colombier
8908ccd4a63SDavid du Colombier if(w->state){
8918ccd4a63SDavid du Colombier free(w->state);
8928ccd4a63SDavid du Colombier w->state = 0;
8938ccd4a63SDavid du Colombier }
8948ccd4a63SDavid du Colombier
8958ccd4a63SDavid du Colombier if(w->slen >= 8){
8968ccd4a63SDavid du Colombier memmove(key, w->secret, 8);
8978ccd4a63SDavid du Colombier key[0] &= 0x0f;
8988ccd4a63SDavid du Colombier key[2] &= 0x0f;
8998ccd4a63SDavid du Colombier key[4] &= 0x0f;
9008ccd4a63SDavid du Colombier key[6] &= 0x0f;
9018ccd4a63SDavid du Colombier }
9028ccd4a63SDavid du Colombier
9038ccd4a63SDavid du Colombier w->state = malloc(sizeof(DESstate));
9048ccd4a63SDavid du Colombier if(w->slen >= 16)
9058ccd4a63SDavid du Colombier setupDESstate(w->state, key, w->secret+8);
9068ccd4a63SDavid du Colombier else if(w->slen >= 8)
9078ccd4a63SDavid du Colombier setupDESstate(w->state, key, 0);
9088ccd4a63SDavid du Colombier else
9098ccd4a63SDavid du Colombier error("secret too short");
9108ccd4a63SDavid du Colombier }
9118ccd4a63SDavid du Colombier
9128ccd4a63SDavid du Colombier static void
initRC4key(OneWay * w)9138ccd4a63SDavid du Colombier initRC4key(OneWay *w)
9148ccd4a63SDavid du Colombier {
9158ccd4a63SDavid du Colombier if(w->state){
9168ccd4a63SDavid du Colombier free(w->state);
9178ccd4a63SDavid du Colombier w->state = 0;
9188ccd4a63SDavid du Colombier }
9198ccd4a63SDavid du Colombier
9208ccd4a63SDavid du Colombier w->state = smalloc(sizeof(RC4state));
9218ccd4a63SDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9228ccd4a63SDavid du Colombier }
9238ccd4a63SDavid du Colombier
9248ccd4a63SDavid du Colombier /*
9258ccd4a63SDavid du Colombier * 40 bit RC4 is the same as n-bit RC4. However,
9268ccd4a63SDavid du Colombier * we ignore all but the first 40 bits of the key.
9278ccd4a63SDavid du Colombier */
9288ccd4a63SDavid du Colombier static void
initRC4key_40(OneWay * w)9298ccd4a63SDavid du Colombier initRC4key_40(OneWay *w)
9308ccd4a63SDavid du Colombier {
9318ccd4a63SDavid du Colombier if(w->state){
9328ccd4a63SDavid du Colombier free(w->state);
9338ccd4a63SDavid du Colombier w->state = 0;
9348ccd4a63SDavid du Colombier }
9358ccd4a63SDavid du Colombier
9368ccd4a63SDavid du Colombier if(w->slen > 5)
9378ccd4a63SDavid du Colombier w->slen = 5;
9388ccd4a63SDavid du Colombier
9398ccd4a63SDavid du Colombier w->state = malloc(sizeof(RC4state));
9408ccd4a63SDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9418ccd4a63SDavid du Colombier }
9428ccd4a63SDavid du Colombier
9438ccd4a63SDavid du Colombier /*
9448ccd4a63SDavid du Colombier * 128 bit RC4 is the same as n-bit RC4. However,
9458ccd4a63SDavid du Colombier * we ignore all but the first 128 bits of the key.
9468ccd4a63SDavid du Colombier */
9478ccd4a63SDavid du Colombier static void
initRC4key_128(OneWay * w)9488ccd4a63SDavid du Colombier initRC4key_128(OneWay *w)
9498ccd4a63SDavid du Colombier {
9508ccd4a63SDavid du Colombier if(w->state){
9518ccd4a63SDavid du Colombier free(w->state);
9528ccd4a63SDavid du Colombier w->state = 0;
9538ccd4a63SDavid du Colombier }
9548ccd4a63SDavid du Colombier
9558ccd4a63SDavid du Colombier if(w->slen > 16)
9568ccd4a63SDavid du Colombier w->slen = 16;
9578ccd4a63SDavid du Colombier
9588ccd4a63SDavid du Colombier w->state = malloc(sizeof(RC4state));
9598ccd4a63SDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9608ccd4a63SDavid du Colombier }
9618ccd4a63SDavid du Colombier
9628ccd4a63SDavid du Colombier
9638ccd4a63SDavid du Colombier typedef struct Hashalg Hashalg;
9648ccd4a63SDavid du Colombier struct Hashalg
9658ccd4a63SDavid du Colombier {
9668ccd4a63SDavid du Colombier char *name;
9678ccd4a63SDavid du Colombier int diglen;
9688ccd4a63SDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
9698ccd4a63SDavid du Colombier };
9708ccd4a63SDavid du Colombier
9718ccd4a63SDavid du Colombier Hashalg hashtab[] =
9728ccd4a63SDavid du Colombier {
9738ccd4a63SDavid du Colombier { "md4", MD4dlen, md4, },
9748ccd4a63SDavid du Colombier { "md5", MD5dlen, md5, },
9758ccd4a63SDavid du Colombier { "sha1", SHA1dlen, sha1, },
9768ccd4a63SDavid du Colombier { "sha", SHA1dlen, sha1, },
9778ccd4a63SDavid du Colombier { 0 }
9788ccd4a63SDavid du Colombier };
9798ccd4a63SDavid du Colombier
9808ccd4a63SDavid du Colombier static int
parsehashalg(char * p,Dstate * s)9818ccd4a63SDavid du Colombier parsehashalg(char *p, Dstate *s)
9828ccd4a63SDavid du Colombier {
9838ccd4a63SDavid du Colombier Hashalg *ha;
9848ccd4a63SDavid du Colombier
9858ccd4a63SDavid du Colombier for(ha = hashtab; ha->name; ha++){
9868ccd4a63SDavid du Colombier if(strcmp(p, ha->name) == 0){
9878ccd4a63SDavid du Colombier s->hf = ha->hf;
9888ccd4a63SDavid du Colombier s->diglen = ha->diglen;
9898ccd4a63SDavid du Colombier s->state &= ~Sclear;
9908ccd4a63SDavid du Colombier s->state |= Sdigesting;
9918ccd4a63SDavid du Colombier return 0;
9928ccd4a63SDavid du Colombier }
9938ccd4a63SDavid du Colombier }
9948ccd4a63SDavid du Colombier return -1;
9958ccd4a63SDavid du Colombier }
9968ccd4a63SDavid du Colombier
9978ccd4a63SDavid du Colombier typedef struct Encalg Encalg;
9988ccd4a63SDavid du Colombier struct Encalg
9998ccd4a63SDavid du Colombier {
10008ccd4a63SDavid du Colombier char *name;
10018ccd4a63SDavid du Colombier int blocklen;
10028ccd4a63SDavid du Colombier int alg;
10038ccd4a63SDavid du Colombier void (*keyinit)(OneWay*);
10048ccd4a63SDavid du Colombier };
10058ccd4a63SDavid du Colombier
10068ccd4a63SDavid du Colombier #ifdef NOSPOOKS
10078ccd4a63SDavid du Colombier Encalg encrypttab[] =
10088ccd4a63SDavid du Colombier {
10098ccd4a63SDavid du Colombier { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */
10108ccd4a63SDavid du Colombier { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */
10118ccd4a63SDavid du Colombier { "des_56_cbc", 8, DESCBC, initDESkey, },
10128ccd4a63SDavid du Colombier { "des_56_ecb", 8, DESECB, initDESkey, },
10138ccd4a63SDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10148ccd4a63SDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10158ccd4a63SDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10168ccd4a63SDavid du Colombier { "rc4_256", 1, RC4, initRC4key, },
10178ccd4a63SDavid du Colombier { "rc4_128", 1, RC4, initRC4key_128, },
10188ccd4a63SDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10198ccd4a63SDavid du Colombier { 0 }
10208ccd4a63SDavid du Colombier };
10218ccd4a63SDavid du Colombier #else
10228ccd4a63SDavid du Colombier Encalg encrypttab[] =
10238ccd4a63SDavid du Colombier {
10248ccd4a63SDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10258ccd4a63SDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10268ccd4a63SDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10278ccd4a63SDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10288ccd4a63SDavid du Colombier { 0 }
10298ccd4a63SDavid du Colombier };
10308ccd4a63SDavid du Colombier #endif /* NOSPOOKS */
10318ccd4a63SDavid du Colombier
10328ccd4a63SDavid du Colombier static int
parseencryptalg(char * p,Dstate * s)10338ccd4a63SDavid du Colombier parseencryptalg(char *p, Dstate *s)
10348ccd4a63SDavid du Colombier {
10358ccd4a63SDavid du Colombier Encalg *ea;
10368ccd4a63SDavid du Colombier
10378ccd4a63SDavid du Colombier for(ea = encrypttab; ea->name; ea++){
10388ccd4a63SDavid du Colombier if(strcmp(p, ea->name) == 0){
10398ccd4a63SDavid du Colombier s->encryptalg = ea->alg;
10408ccd4a63SDavid du Colombier s->blocklen = ea->blocklen;
10418ccd4a63SDavid du Colombier (*ea->keyinit)(&s->in);
10428ccd4a63SDavid du Colombier (*ea->keyinit)(&s->out);
10438ccd4a63SDavid du Colombier s->state &= ~Sclear;
10448ccd4a63SDavid du Colombier s->state |= Sencrypting;
10458ccd4a63SDavid du Colombier return 0;
10468ccd4a63SDavid du Colombier }
10478ccd4a63SDavid du Colombier }
10488ccd4a63SDavid du Colombier return -1;
10498ccd4a63SDavid du Colombier }
10508ccd4a63SDavid du Colombier
10518ccd4a63SDavid du Colombier static long
sslwrite(Chan * c,void * a,long n,vlong o)10528ccd4a63SDavid du Colombier sslwrite(Chan *c, void *a, long n, vlong o)
10538ccd4a63SDavid du Colombier {
10548ccd4a63SDavid du Colombier Dstate * volatile s;
10558ccd4a63SDavid du Colombier Block * volatile b;
10568ccd4a63SDavid du Colombier int m, t;
10578ccd4a63SDavid du Colombier char *p, *np, *e, buf[128];
10588ccd4a63SDavid du Colombier uchar *x;
10598ccd4a63SDavid du Colombier
10608ccd4a63SDavid du Colombier USED(o);
10618ccd4a63SDavid du Colombier s = dstate[CONV(c->qid)];
10628ccd4a63SDavid du Colombier if(s == 0)
10638ccd4a63SDavid du Colombier panic("sslwrite");
10648ccd4a63SDavid du Colombier
10658ccd4a63SDavid du Colombier t = TYPE(c->qid);
10668ccd4a63SDavid du Colombier if(t == Qdata){
10678ccd4a63SDavid du Colombier if(s->state == Sincomplete)
10688ccd4a63SDavid du Colombier error(Ebadusefd);
10698ccd4a63SDavid du Colombier
10708ccd4a63SDavid du Colombier /* lock should a write gets split over multiple records */
10718ccd4a63SDavid du Colombier if(waserror()){
10728ccd4a63SDavid du Colombier qunlock(&s->out.q);
10738ccd4a63SDavid du Colombier nexterror();
10748ccd4a63SDavid du Colombier }
10758ccd4a63SDavid du Colombier qlock(&s->out.q);
10768ccd4a63SDavid du Colombier p = a;
10778ccd4a63SDavid du Colombier if(0) iprint("write %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
10788ccd4a63SDavid du Colombier n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
10798ccd4a63SDavid du Colombier e = p + n;
10808ccd4a63SDavid du Colombier do {
10818ccd4a63SDavid du Colombier m = e - p;
10828ccd4a63SDavid du Colombier if(m > s->max)
10838ccd4a63SDavid du Colombier m = s->max;
10848ccd4a63SDavid du Colombier
10858ccd4a63SDavid du Colombier b = allocb(m);
10868ccd4a63SDavid du Colombier if(waserror()){
10878ccd4a63SDavid du Colombier freeb(b);
10888ccd4a63SDavid du Colombier nexterror();
10898ccd4a63SDavid du Colombier }
10908ccd4a63SDavid du Colombier memmove(b->wp, p, m);
10918ccd4a63SDavid du Colombier poperror();
10928ccd4a63SDavid du Colombier b->wp += m;
10938ccd4a63SDavid du Colombier
10948ccd4a63SDavid du Colombier sslput(s, b);
10958ccd4a63SDavid du Colombier
10968ccd4a63SDavid du Colombier p += m;
10978ccd4a63SDavid du Colombier } while(p < e);
10988ccd4a63SDavid du Colombier p = a;
10998ccd4a63SDavid du Colombier if(0) iprint("wrote %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
11008ccd4a63SDavid du Colombier n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
11018ccd4a63SDavid du Colombier poperror();
11028ccd4a63SDavid du Colombier qunlock(&s->out.q);
11038ccd4a63SDavid du Colombier return n;
11048ccd4a63SDavid du Colombier }
11058ccd4a63SDavid du Colombier
11068ccd4a63SDavid du Colombier /* mutex with operations using what we're about to change */
11078ccd4a63SDavid du Colombier if(waserror()){
11088ccd4a63SDavid du Colombier qunlock(&s->in.ctlq);
11098ccd4a63SDavid du Colombier qunlock(&s->out.q);
11108ccd4a63SDavid du Colombier nexterror();
11118ccd4a63SDavid du Colombier }
11128ccd4a63SDavid du Colombier qlock(&s->in.ctlq);
11138ccd4a63SDavid du Colombier qlock(&s->out.q);
11148ccd4a63SDavid du Colombier
11158ccd4a63SDavid du Colombier switch(t){
11168ccd4a63SDavid du Colombier default:
11178ccd4a63SDavid du Colombier panic("sslwrite");
11188ccd4a63SDavid du Colombier case Qsecretin:
11198ccd4a63SDavid du Colombier setsecret(&s->in, a, n);
11208ccd4a63SDavid du Colombier goto out;
11218ccd4a63SDavid du Colombier case Qsecretout:
11228ccd4a63SDavid du Colombier setsecret(&s->out, a, n);
11238ccd4a63SDavid du Colombier goto out;
11248ccd4a63SDavid du Colombier case Qctl:
11258ccd4a63SDavid du Colombier break;
11268ccd4a63SDavid du Colombier }
11278ccd4a63SDavid du Colombier
11288ccd4a63SDavid du Colombier if(n >= sizeof(buf))
11298ccd4a63SDavid du Colombier error("arg too long");
11308ccd4a63SDavid du Colombier strncpy(buf, a, n);
11318ccd4a63SDavid du Colombier buf[n] = 0;
11328ccd4a63SDavid du Colombier p = strchr(buf, '\n');
11338ccd4a63SDavid du Colombier if(p)
11348ccd4a63SDavid du Colombier *p = 0;
11358ccd4a63SDavid du Colombier p = strchr(buf, ' ');
11368ccd4a63SDavid du Colombier if(p)
11378ccd4a63SDavid du Colombier *p++ = 0;
11388ccd4a63SDavid du Colombier
11398ccd4a63SDavid du Colombier if(strcmp(buf, "fd") == 0){
11408ccd4a63SDavid du Colombier s->c = buftochan(p);
11418ccd4a63SDavid du Colombier
11428ccd4a63SDavid du Colombier /* default is clear (msg delimiters only) */
11438ccd4a63SDavid du Colombier s->state = Sclear;
11448ccd4a63SDavid du Colombier s->blocklen = 1;
11458ccd4a63SDavid du Colombier s->diglen = 0;
11468ccd4a63SDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11478ccd4a63SDavid du Colombier s->in.mid = 0;
11488ccd4a63SDavid du Colombier s->out.mid = 0;
11498ccd4a63SDavid du Colombier } else if(strcmp(buf, "alg") == 0 && p != 0){
11508ccd4a63SDavid du Colombier s->blocklen = 1;
11518ccd4a63SDavid du Colombier s->diglen = 0;
11528ccd4a63SDavid du Colombier
11538ccd4a63SDavid du Colombier if(s->c == 0)
11548ccd4a63SDavid du Colombier error("must set fd before algorithm");
11558ccd4a63SDavid du Colombier
11568ccd4a63SDavid du Colombier s->state = Sclear;
11578ccd4a63SDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11588ccd4a63SDavid du Colombier if(strcmp(p, "clear") == 0){
11598ccd4a63SDavid du Colombier goto out;
11608ccd4a63SDavid du Colombier }
11618ccd4a63SDavid du Colombier
11628ccd4a63SDavid du Colombier if(s->in.secret && s->out.secret == 0)
11638ccd4a63SDavid du Colombier setsecret(&s->out, s->in.secret, s->in.slen);
11648ccd4a63SDavid du Colombier if(s->out.secret && s->in.secret == 0)
11658ccd4a63SDavid du Colombier setsecret(&s->in, s->out.secret, s->out.slen);
11668ccd4a63SDavid du Colombier if(s->in.secret == 0 || s->out.secret == 0)
11678ccd4a63SDavid du Colombier error("algorithm but no secret");
11688ccd4a63SDavid du Colombier
11698ccd4a63SDavid du Colombier s->hf = 0;
11708ccd4a63SDavid du Colombier s->encryptalg = Noencryption;
11718ccd4a63SDavid du Colombier s->blocklen = 1;
11728ccd4a63SDavid du Colombier
11738ccd4a63SDavid du Colombier for(;;){
11748ccd4a63SDavid du Colombier np = strchr(p, ' ');
11758ccd4a63SDavid du Colombier if(np)
11768ccd4a63SDavid du Colombier *np++ = 0;
11778ccd4a63SDavid du Colombier
11788ccd4a63SDavid du Colombier if(parsehashalg(p, s) < 0)
11798ccd4a63SDavid du Colombier if(parseencryptalg(p, s) < 0)
11808ccd4a63SDavid du Colombier error("bad algorithm");
11818ccd4a63SDavid du Colombier
11828ccd4a63SDavid du Colombier if(np == 0)
11838ccd4a63SDavid du Colombier break;
11848ccd4a63SDavid du Colombier p = np;
11858ccd4a63SDavid du Colombier }
11868ccd4a63SDavid du Colombier
11878ccd4a63SDavid du Colombier if(s->hf == 0 && s->encryptalg == Noencryption)
11888ccd4a63SDavid du Colombier error("bad algorithm");
11898ccd4a63SDavid du Colombier
11908ccd4a63SDavid du Colombier if(s->blocklen != 1){
11918ccd4a63SDavid du Colombier s->max = (1<<15) - s->diglen - 1;
11928ccd4a63SDavid du Colombier s->max -= s->max % s->blocklen;
11938ccd4a63SDavid du Colombier s->maxpad = (1<<14) - s->diglen - 1;
11948ccd4a63SDavid du Colombier s->maxpad -= s->maxpad % s->blocklen;
11958ccd4a63SDavid du Colombier } else
11968ccd4a63SDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11978ccd4a63SDavid du Colombier } else if(strcmp(buf, "secretin") == 0 && p != 0) {
11988ccd4a63SDavid du Colombier m = (strlen(p)*3)/2;
11998ccd4a63SDavid du Colombier x = smalloc(m);
12008ccd4a63SDavid du Colombier t = dec64(x, m, p, strlen(p));
12018ccd4a63SDavid du Colombier setsecret(&s->in, x, t);
12028ccd4a63SDavid du Colombier free(x);
12038ccd4a63SDavid du Colombier } else if(strcmp(buf, "secretout") == 0 && p != 0) {
12048ccd4a63SDavid du Colombier m = (strlen(p)*3)/2 + 1;
12058ccd4a63SDavid du Colombier x = smalloc(m);
12068ccd4a63SDavid du Colombier t = dec64(x, m, p, strlen(p));
12078ccd4a63SDavid du Colombier setsecret(&s->out, x, t);
12088ccd4a63SDavid du Colombier free(x);
12098ccd4a63SDavid du Colombier } else
12108ccd4a63SDavid du Colombier error(Ebadarg);
12118ccd4a63SDavid du Colombier
12128ccd4a63SDavid du Colombier out:
12138ccd4a63SDavid du Colombier qunlock(&s->in.ctlq);
12148ccd4a63SDavid du Colombier qunlock(&s->out.q);
12158ccd4a63SDavid du Colombier poperror();
12168ccd4a63SDavid du Colombier return n;
12178ccd4a63SDavid du Colombier }
12188ccd4a63SDavid du Colombier
12198ccd4a63SDavid du Colombier static void
sslinit(void)12208ccd4a63SDavid du Colombier sslinit(void)
12218ccd4a63SDavid du Colombier {
12228ccd4a63SDavid du Colombier struct Encalg *e;
12238ccd4a63SDavid du Colombier struct Hashalg *h;
12248ccd4a63SDavid du Colombier int n;
12258ccd4a63SDavid du Colombier char *cp;
12268ccd4a63SDavid du Colombier
12278ccd4a63SDavid du Colombier n = 1;
12288ccd4a63SDavid du Colombier for(e = encrypttab; e->name != nil; e++)
12298ccd4a63SDavid du Colombier n += strlen(e->name) + 1;
12308ccd4a63SDavid du Colombier cp = encalgs = smalloc(n);
12318ccd4a63SDavid du Colombier for(e = encrypttab;;){
12328ccd4a63SDavid du Colombier strcpy(cp, e->name);
12338ccd4a63SDavid du Colombier cp += strlen(e->name);
12348ccd4a63SDavid du Colombier e++;
12358ccd4a63SDavid du Colombier if(e->name == nil)
12368ccd4a63SDavid du Colombier break;
12378ccd4a63SDavid du Colombier *cp++ = ' ';
12388ccd4a63SDavid du Colombier }
12398ccd4a63SDavid du Colombier *cp = 0;
12408ccd4a63SDavid du Colombier
12418ccd4a63SDavid du Colombier n = 1;
12428ccd4a63SDavid du Colombier for(h = hashtab; h->name != nil; h++)
12438ccd4a63SDavid du Colombier n += strlen(h->name) + 1;
12448ccd4a63SDavid du Colombier cp = hashalgs = smalloc(n);
12458ccd4a63SDavid du Colombier for(h = hashtab;;){
12468ccd4a63SDavid du Colombier strcpy(cp, h->name);
12478ccd4a63SDavid du Colombier cp += strlen(h->name);
12488ccd4a63SDavid du Colombier h++;
12498ccd4a63SDavid du Colombier if(h->name == nil)
12508ccd4a63SDavid du Colombier break;
12518ccd4a63SDavid du Colombier *cp++ = ' ';
12528ccd4a63SDavid du Colombier }
12538ccd4a63SDavid du Colombier *cp = 0;
12548ccd4a63SDavid du Colombier }
12558ccd4a63SDavid du Colombier
12568ccd4a63SDavid du Colombier Dev ssldevtab = {
12578ccd4a63SDavid du Colombier 'D',
12588ccd4a63SDavid du Colombier "ssl",
12598ccd4a63SDavid du Colombier
12608ccd4a63SDavid du Colombier devreset,
12618ccd4a63SDavid du Colombier sslinit,
12628ccd4a63SDavid du Colombier devshutdown,
12638ccd4a63SDavid du Colombier sslattach,
12648ccd4a63SDavid du Colombier sslwalk,
12658ccd4a63SDavid du Colombier sslstat,
12668ccd4a63SDavid du Colombier sslopen,
12678ccd4a63SDavid du Colombier devcreate,
12688ccd4a63SDavid du Colombier sslclose,
12698ccd4a63SDavid du Colombier sslread,
12708ccd4a63SDavid du Colombier sslbread,
12718ccd4a63SDavid du Colombier sslwrite,
12728ccd4a63SDavid du Colombier sslbwrite,
12738ccd4a63SDavid du Colombier devremove,
12748ccd4a63SDavid du Colombier sslwstat,
12758ccd4a63SDavid du Colombier };
12768ccd4a63SDavid du Colombier
12778ccd4a63SDavid du Colombier static Block*
encryptb(Dstate * s,Block * b,int offset)12788ccd4a63SDavid du Colombier encryptb(Dstate *s, Block *b, int offset)
12798ccd4a63SDavid du Colombier {
12808ccd4a63SDavid du Colombier uchar *p, *ep, *p2, *ip, *eip;
12818ccd4a63SDavid du Colombier DESstate *ds;
12828ccd4a63SDavid du Colombier
12838ccd4a63SDavid du Colombier switch(s->encryptalg){
12848ccd4a63SDavid du Colombier case DESECB:
12858ccd4a63SDavid du Colombier ds = s->out.state;
12868ccd4a63SDavid du Colombier ep = b->rp + BLEN(b);
12878ccd4a63SDavid du Colombier for(p = b->rp + offset; p < ep; p += 8)
12888ccd4a63SDavid du Colombier block_cipher(ds->expanded, p, 0);
12898ccd4a63SDavid du Colombier break;
12908ccd4a63SDavid du Colombier case DESCBC:
12918ccd4a63SDavid du Colombier ds = s->out.state;
12928ccd4a63SDavid du Colombier ep = b->rp + BLEN(b);
12938ccd4a63SDavid du Colombier for(p = b->rp + offset; p < ep; p += 8){
12948ccd4a63SDavid du Colombier p2 = p;
12958ccd4a63SDavid du Colombier ip = ds->ivec;
12968ccd4a63SDavid du Colombier for(eip = ip+8; ip < eip; )
12978ccd4a63SDavid du Colombier *p2++ ^= *ip++;
12988ccd4a63SDavid du Colombier block_cipher(ds->expanded, p, 0);
12998ccd4a63SDavid du Colombier memmove(ds->ivec, p, 8);
13008ccd4a63SDavid du Colombier }
13018ccd4a63SDavid du Colombier break;
13028ccd4a63SDavid du Colombier case RC4:
13038ccd4a63SDavid du Colombier rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
13048ccd4a63SDavid du Colombier break;
13058ccd4a63SDavid du Colombier }
13068ccd4a63SDavid du Colombier return b;
13078ccd4a63SDavid du Colombier }
13088ccd4a63SDavid du Colombier
13098ccd4a63SDavid du Colombier static Block*
decryptb(Dstate * s,Block * bin)13108ccd4a63SDavid du Colombier decryptb(Dstate *s, Block *bin)
13118ccd4a63SDavid du Colombier {
13128ccd4a63SDavid du Colombier Block *b, **l;
13138ccd4a63SDavid du Colombier uchar *p, *ep, *tp, *ip, *eip;
13148ccd4a63SDavid du Colombier DESstate *ds;
13158ccd4a63SDavid du Colombier uchar tmp[8];
13168ccd4a63SDavid du Colombier int i;
13178ccd4a63SDavid du Colombier
13188ccd4a63SDavid du Colombier l = &bin;
13198ccd4a63SDavid du Colombier for(b = bin; b; b = b->next){
13208ccd4a63SDavid du Colombier /* make sure we have a multiple of s->blocklen */
13218ccd4a63SDavid du Colombier if(s->blocklen > 1){
13228ccd4a63SDavid du Colombier i = BLEN(b);
13238ccd4a63SDavid du Colombier if(i % s->blocklen){
13248ccd4a63SDavid du Colombier *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
13258ccd4a63SDavid du Colombier if(b == 0)
13268ccd4a63SDavid du Colombier error("ssl encrypted message too short");
13278ccd4a63SDavid du Colombier }
13288ccd4a63SDavid du Colombier }
13298ccd4a63SDavid du Colombier l = &b->next;
13308ccd4a63SDavid du Colombier
13318ccd4a63SDavid du Colombier /* decrypt */
13328ccd4a63SDavid du Colombier switch(s->encryptalg){
13338ccd4a63SDavid du Colombier case DESECB:
13348ccd4a63SDavid du Colombier ds = s->in.state;
13358ccd4a63SDavid du Colombier ep = b->rp + BLEN(b);
13368ccd4a63SDavid du Colombier for(p = b->rp; p < ep; p += 8)
13378ccd4a63SDavid du Colombier block_cipher(ds->expanded, p, 1);
13388ccd4a63SDavid du Colombier break;
13398ccd4a63SDavid du Colombier case DESCBC:
13408ccd4a63SDavid du Colombier ds = s->in.state;
13418ccd4a63SDavid du Colombier ep = b->rp + BLEN(b);
13428ccd4a63SDavid du Colombier for(p = b->rp; p < ep;){
13438ccd4a63SDavid du Colombier memmove(tmp, p, 8);
13448ccd4a63SDavid du Colombier block_cipher(ds->expanded, p, 1);
13458ccd4a63SDavid du Colombier tp = tmp;
13468ccd4a63SDavid du Colombier ip = ds->ivec;
13478ccd4a63SDavid du Colombier for(eip = ip+8; ip < eip; ){
13488ccd4a63SDavid du Colombier *p++ ^= *ip;
13498ccd4a63SDavid du Colombier *ip++ = *tp++;
13508ccd4a63SDavid du Colombier }
13518ccd4a63SDavid du Colombier }
13528ccd4a63SDavid du Colombier break;
13538ccd4a63SDavid du Colombier case RC4:
13548ccd4a63SDavid du Colombier rc4(s->in.state, b->rp, BLEN(b));
13558ccd4a63SDavid du Colombier break;
13568ccd4a63SDavid du Colombier }
13578ccd4a63SDavid du Colombier }
13588ccd4a63SDavid du Colombier return bin;
13598ccd4a63SDavid du Colombier }
13608ccd4a63SDavid du Colombier
13618ccd4a63SDavid du Colombier static Block*
digestb(Dstate * s,Block * b,int offset)13628ccd4a63SDavid du Colombier digestb(Dstate *s, Block *b, int offset)
13638ccd4a63SDavid du Colombier {
13648ccd4a63SDavid du Colombier uchar *p;
13658ccd4a63SDavid du Colombier DigestState ss;
13668ccd4a63SDavid du Colombier uchar msgid[4];
13678ccd4a63SDavid du Colombier ulong n, h;
13688ccd4a63SDavid du Colombier OneWay *w;
13698ccd4a63SDavid du Colombier
13708ccd4a63SDavid du Colombier w = &s->out;
13718ccd4a63SDavid du Colombier
13728ccd4a63SDavid du Colombier memset(&ss, 0, sizeof(ss));
13738ccd4a63SDavid du Colombier h = s->diglen + offset;
13748ccd4a63SDavid du Colombier n = BLEN(b) - h;
13758ccd4a63SDavid du Colombier
13768ccd4a63SDavid du Colombier /* hash secret + message */
13778ccd4a63SDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
13788ccd4a63SDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
13798ccd4a63SDavid du Colombier
13808ccd4a63SDavid du Colombier /* hash message id */
13818ccd4a63SDavid du Colombier p = msgid;
13828ccd4a63SDavid du Colombier n = w->mid;
13838ccd4a63SDavid du Colombier *p++ = n>>24;
13848ccd4a63SDavid du Colombier *p++ = n>>16;
13858ccd4a63SDavid du Colombier *p++ = n>>8;
13868ccd4a63SDavid du Colombier *p = n;
13878ccd4a63SDavid du Colombier (*s->hf)(msgid, 4, b->rp + offset, &ss);
13888ccd4a63SDavid du Colombier
13898ccd4a63SDavid du Colombier return b;
13908ccd4a63SDavid du Colombier }
13918ccd4a63SDavid du Colombier
13928ccd4a63SDavid du Colombier static void
checkdigestb(Dstate * s,Block * bin)13938ccd4a63SDavid du Colombier checkdigestb(Dstate *s, Block *bin)
13948ccd4a63SDavid du Colombier {
13958ccd4a63SDavid du Colombier uchar *p;
13968ccd4a63SDavid du Colombier DigestState ss;
13978ccd4a63SDavid du Colombier uchar msgid[4];
13988ccd4a63SDavid du Colombier int n, h;
13998ccd4a63SDavid du Colombier OneWay *w;
14008ccd4a63SDavid du Colombier uchar digest[128];
14018ccd4a63SDavid du Colombier Block *b;
14028ccd4a63SDavid du Colombier
14038ccd4a63SDavid du Colombier w = &s->in;
14048ccd4a63SDavid du Colombier
14058ccd4a63SDavid du Colombier memset(&ss, 0, sizeof(ss));
14068ccd4a63SDavid du Colombier
14078ccd4a63SDavid du Colombier /* hash secret */
14088ccd4a63SDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
14098ccd4a63SDavid du Colombier
14108ccd4a63SDavid du Colombier /* hash message */
14118ccd4a63SDavid du Colombier h = s->diglen;
14128ccd4a63SDavid du Colombier for(b = bin; b; b = b->next){
14138ccd4a63SDavid du Colombier n = BLEN(b) - h;
14148ccd4a63SDavid du Colombier if(n < 0)
14158ccd4a63SDavid du Colombier panic("checkdigestb");
14168ccd4a63SDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
14178ccd4a63SDavid du Colombier h = 0;
14188ccd4a63SDavid du Colombier }
14198ccd4a63SDavid du Colombier
14208ccd4a63SDavid du Colombier /* hash message id */
14218ccd4a63SDavid du Colombier p = msgid;
14228ccd4a63SDavid du Colombier n = w->mid;
14238ccd4a63SDavid du Colombier *p++ = n>>24;
14248ccd4a63SDavid du Colombier *p++ = n>>16;
14258ccd4a63SDavid du Colombier *p++ = n>>8;
14268ccd4a63SDavid du Colombier *p = n;
14278ccd4a63SDavid du Colombier (*s->hf)(msgid, 4, digest, &ss);
14288ccd4a63SDavid du Colombier
14298ccd4a63SDavid du Colombier if(memcmp(digest, bin->rp, s->diglen) != 0)
14308ccd4a63SDavid du Colombier error("bad digest");
14318ccd4a63SDavid du Colombier }
14328ccd4a63SDavid du Colombier
14338ccd4a63SDavid du Colombier /* get channel associated with an fd */
14348ccd4a63SDavid du Colombier static Chan*
buftochan(char * p)14358ccd4a63SDavid du Colombier buftochan(char *p)
14368ccd4a63SDavid du Colombier {
14378ccd4a63SDavid du Colombier Chan *c;
14388ccd4a63SDavid du Colombier int fd;
14398ccd4a63SDavid du Colombier
14408ccd4a63SDavid du Colombier if(p == 0)
14418ccd4a63SDavid du Colombier error(Ebadarg);
14428ccd4a63SDavid du Colombier fd = strtoul(p, 0, 0);
14438ccd4a63SDavid du Colombier if(fd < 0)
14448ccd4a63SDavid du Colombier error(Ebadarg);
14458ccd4a63SDavid du Colombier c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
14468ccd4a63SDavid du Colombier if(devtab[c->type] == &ssldevtab){
14478ccd4a63SDavid du Colombier cclose(c);
14488ccd4a63SDavid du Colombier error("cannot ssl encrypt devssl files");
14498ccd4a63SDavid du Colombier }
14508ccd4a63SDavid du Colombier return c;
14518ccd4a63SDavid du Colombier }
14528ccd4a63SDavid du Colombier
14538ccd4a63SDavid du Colombier /* hand up a digest connection */
14548ccd4a63SDavid du Colombier static void
sslhangup(Dstate * s)14558ccd4a63SDavid du Colombier sslhangup(Dstate *s)
14568ccd4a63SDavid du Colombier {
14578ccd4a63SDavid du Colombier Block *b;
14588ccd4a63SDavid du Colombier
14598ccd4a63SDavid du Colombier qlock(&s->in.q);
14608ccd4a63SDavid du Colombier for(b = s->processed; b; b = s->processed){
14618ccd4a63SDavid du Colombier s->processed = b->next;
14628ccd4a63SDavid du Colombier freeb(b);
14638ccd4a63SDavid du Colombier }
14648ccd4a63SDavid du Colombier if(s->unprocessed){
14658ccd4a63SDavid du Colombier freeb(s->unprocessed);
14668ccd4a63SDavid du Colombier s->unprocessed = 0;
14678ccd4a63SDavid du Colombier }
14688ccd4a63SDavid du Colombier s->state = Sincomplete;
14698ccd4a63SDavid du Colombier qunlock(&s->in.q);
14708ccd4a63SDavid du Colombier }
14718ccd4a63SDavid du Colombier
14728ccd4a63SDavid du Colombier static Dstate*
dsclone(Chan * ch)14738ccd4a63SDavid du Colombier dsclone(Chan *ch)
14748ccd4a63SDavid du Colombier {
14758ccd4a63SDavid du Colombier int i;
14768ccd4a63SDavid du Colombier Dstate *ret;
14778ccd4a63SDavid du Colombier
14788ccd4a63SDavid du Colombier if(waserror()) {
14798ccd4a63SDavid du Colombier unlock(&dslock);
14808ccd4a63SDavid du Colombier nexterror();
14818ccd4a63SDavid du Colombier }
14828ccd4a63SDavid du Colombier lock(&dslock);
14838ccd4a63SDavid du Colombier ret = nil;
14848ccd4a63SDavid du Colombier for(i=0; i<Maxdstate; i++){
14858ccd4a63SDavid du Colombier if(dstate[i] == nil){
14868ccd4a63SDavid du Colombier dsnew(ch, &dstate[i]);
14878ccd4a63SDavid du Colombier ret = dstate[i];
14888ccd4a63SDavid du Colombier break;
14898ccd4a63SDavid du Colombier }
14908ccd4a63SDavid du Colombier }
14918ccd4a63SDavid du Colombier unlock(&dslock);
14928ccd4a63SDavid du Colombier poperror();
14938ccd4a63SDavid du Colombier return ret;
14948ccd4a63SDavid du Colombier }
14958ccd4a63SDavid du Colombier
14968ccd4a63SDavid du Colombier static void
dsnew(Chan * ch,Dstate ** pp)14978ccd4a63SDavid du Colombier dsnew(Chan *ch, Dstate **pp)
14988ccd4a63SDavid du Colombier {
14998ccd4a63SDavid du Colombier Dstate *s;
15008ccd4a63SDavid du Colombier int t;
15018ccd4a63SDavid du Colombier
15028ccd4a63SDavid du Colombier *pp = s = malloc(sizeof(*s));
15038ccd4a63SDavid du Colombier if(!s)
15048ccd4a63SDavid du Colombier error(Enomem);
15058ccd4a63SDavid du Colombier if(pp - dstate >= dshiwat)
15068ccd4a63SDavid du Colombier dshiwat++;
15078ccd4a63SDavid du Colombier memset(s, 0, sizeof(*s));
15088ccd4a63SDavid du Colombier s->state = Sincomplete;
15098ccd4a63SDavid du Colombier s->ref = 1;
15108ccd4a63SDavid du Colombier kstrdup(&s->user, up->user);
15118ccd4a63SDavid du Colombier s->perm = 0660;
15128ccd4a63SDavid du Colombier t = TYPE(ch->qid);
15138ccd4a63SDavid du Colombier if(t == Qclonus)
15148ccd4a63SDavid du Colombier t = Qctl;
15158ccd4a63SDavid du Colombier ch->qid.path = QID(pp - dstate, t);
15168ccd4a63SDavid du Colombier ch->qid.vers = 0;
15178ccd4a63SDavid du Colombier }
1518