17dd7cddfSDavid du Colombier /*
29a747e4fSDavid du Colombier * devssl - secure sockets layer
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
97dd7cddfSDavid du Colombier #include "../port/error.h"
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier #include <libsec.h>
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier #define NOSPOOKS 1
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier typedef struct OneWay OneWay;
167dd7cddfSDavid du Colombier struct OneWay
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier QLock q;
197dd7cddfSDavid du Colombier QLock ctlq;
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier void *state; /* encryption state */
227dd7cddfSDavid du Colombier int slen; /* hash data length */
237dd7cddfSDavid du Colombier uchar *secret; /* secret */
247dd7cddfSDavid du Colombier ulong mid; /* message id */
257dd7cddfSDavid du Colombier };
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier enum
287dd7cddfSDavid du Colombier {
297dd7cddfSDavid du Colombier /* connection states */
307dd7cddfSDavid du Colombier Sincomplete= 0,
317dd7cddfSDavid du Colombier Sclear= 1,
327dd7cddfSDavid du Colombier Sencrypting= 2,
337dd7cddfSDavid du Colombier Sdigesting= 4,
347dd7cddfSDavid du Colombier Sdigenc= Sencrypting|Sdigesting,
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier /* encryption algorithms */
377dd7cddfSDavid du Colombier Noencryption= 0,
387dd7cddfSDavid du Colombier DESCBC= 1,
397dd7cddfSDavid du Colombier DESECB= 2,
407dd7cddfSDavid du Colombier RC4= 3
417dd7cddfSDavid du Colombier };
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier typedef struct Dstate Dstate;
447dd7cddfSDavid du Colombier struct Dstate
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier Chan *c; /* io channel */
477dd7cddfSDavid du Colombier uchar state; /* state of connection */
487dd7cddfSDavid du Colombier int ref; /* serialized by dslock for atomic destroy */
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier uchar encryptalg; /* encryption algorithm */
517dd7cddfSDavid du Colombier ushort blocklen; /* blocking length */
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier ushort diglen; /* length of digest */
547dd7cddfSDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier /* for SSL format */
577dd7cddfSDavid du Colombier int max; /* maximum unpadded data per msg */
587dd7cddfSDavid du Colombier int maxpad; /* maximum padded data per msg */
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier /* input side */
617dd7cddfSDavid du Colombier OneWay in;
627dd7cddfSDavid du Colombier Block *processed;
637dd7cddfSDavid du Colombier Block *unprocessed;
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier /* output side */
667dd7cddfSDavid du Colombier OneWay out;
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier /* protections */
699a747e4fSDavid du Colombier char *user;
707dd7cddfSDavid du Colombier int perm;
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier enum
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier Maxdmsg= 1<<16,
76e9b54818SDavid du Colombier Maxdstate= 512, /* max. open ssl conn's; must be a power of 2 */
777dd7cddfSDavid du Colombier };
787dd7cddfSDavid du Colombier
79e9b54818SDavid du Colombier static Lock dslock;
80e9b54818SDavid du Colombier static int dshiwat;
81e9b54818SDavid du Colombier static char *dsname[Maxdstate];
82e9b54818SDavid du Colombier static Dstate *dstate[Maxdstate];
83e9b54818SDavid du Colombier static char *encalgs;
84e9b54818SDavid du Colombier static char *hashalgs;
859a747e4fSDavid du Colombier
867dd7cddfSDavid du Colombier enum{
877dd7cddfSDavid du Colombier Qtopdir = 1, /* top level directory */
887dd7cddfSDavid du Colombier Qprotodir,
897dd7cddfSDavid du Colombier Qclonus,
907dd7cddfSDavid du Colombier Qconvdir, /* directory for a conversation */
917dd7cddfSDavid du Colombier Qdata,
927dd7cddfSDavid du Colombier Qctl,
937dd7cddfSDavid du Colombier Qsecretin,
947dd7cddfSDavid du Colombier Qsecretout,
957dd7cddfSDavid du Colombier Qencalgs,
967dd7cddfSDavid du Colombier Qhashalgs,
977dd7cddfSDavid du Colombier };
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier #define TYPE(x) ((x).path & 0xf)
1007dd7cddfSDavid du Colombier #define CONV(x) (((x).path >> 5)&(Maxdstate-1))
1017dd7cddfSDavid du Colombier #define QID(c, y) (((c)<<5) | (y))
1027dd7cddfSDavid du Colombier
1037dd7cddfSDavid du Colombier static void ensure(Dstate*, Block**, int);
1047dd7cddfSDavid du Colombier static void consume(Block**, uchar*, int);
1057dd7cddfSDavid du Colombier static void setsecret(OneWay*, uchar*, int);
1067dd7cddfSDavid du Colombier static Block* encryptb(Dstate*, Block*, int);
1077dd7cddfSDavid du Colombier static Block* decryptb(Dstate*, Block*);
1087dd7cddfSDavid du Colombier static Block* digestb(Dstate*, Block*, int);
1097dd7cddfSDavid du Colombier static void checkdigestb(Dstate*, Block*);
1107dd7cddfSDavid du Colombier static Chan* buftochan(char*);
1117dd7cddfSDavid du Colombier static void sslhangup(Dstate*);
1127dd7cddfSDavid du Colombier static Dstate* dsclone(Chan *c);
1137dd7cddfSDavid du Colombier static void dsnew(Chan *c, Dstate **);
1149a747e4fSDavid du Colombier static long sslput(Dstate *s, Block * volatile b);
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier char *sslnames[] = {
1177dd7cddfSDavid du Colombier [Qclonus] "clone",
1187dd7cddfSDavid du Colombier [Qdata] "data",
1197dd7cddfSDavid du Colombier [Qctl] "ctl",
1207dd7cddfSDavid du Colombier [Qsecretin] "secretin",
1217dd7cddfSDavid du Colombier [Qsecretout] "secretout",
1227dd7cddfSDavid du Colombier [Qencalgs] "encalgs",
1237dd7cddfSDavid du Colombier [Qhashalgs] "hashalgs",
1247dd7cddfSDavid du Colombier };
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier static int
sslgen(Chan * c,char *,Dirtab * d,int nd,int s,Dir * dp)1279a747e4fSDavid du Colombier sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier Qid q;
1307dd7cddfSDavid du Colombier Dstate *ds;
1317dd7cddfSDavid du Colombier char name[16], *p, *nm;
1329a747e4fSDavid du Colombier int ft;
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier USED(nd);
1357dd7cddfSDavid du Colombier USED(d);
1369a747e4fSDavid du Colombier
1379a747e4fSDavid du Colombier q.type = QTFILE;
1387dd7cddfSDavid du Colombier q.vers = 0;
1399a747e4fSDavid du Colombier
1409a747e4fSDavid du Colombier ft = TYPE(c->qid);
1419a747e4fSDavid du Colombier switch(ft) {
1427dd7cddfSDavid du Colombier case Qtopdir:
1437dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
1449a747e4fSDavid du Colombier q.path = QID(0, Qtopdir);
1459a747e4fSDavid du Colombier q.type = QTDIR;
1469a747e4fSDavid du Colombier devdir(c, q, "#D", 0, eve, 0555, dp);
1477dd7cddfSDavid du Colombier return 1;
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier if(s > 0)
1507dd7cddfSDavid du Colombier return -1;
1519a747e4fSDavid du Colombier q.path = QID(0, Qprotodir);
1529a747e4fSDavid du Colombier q.type = QTDIR;
1539a747e4fSDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1547dd7cddfSDavid du Colombier return 1;
1557dd7cddfSDavid du Colombier case Qprotodir:
1567dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
1579a747e4fSDavid du Colombier q.path = QID(0, Qtopdir);
1589a747e4fSDavid du Colombier q.type = QTDIR;
1599a747e4fSDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp);
1607dd7cddfSDavid du Colombier return 1;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier if(s < dshiwat) {
1639a747e4fSDavid du Colombier q.path = QID(s, Qconvdir);
1649a747e4fSDavid du Colombier q.type = QTDIR;
1657dd7cddfSDavid du Colombier ds = dstate[s];
1667dd7cddfSDavid du Colombier if(ds != 0)
1677dd7cddfSDavid du Colombier nm = ds->user;
1687dd7cddfSDavid du Colombier else
1697dd7cddfSDavid du Colombier nm = eve;
1709a747e4fSDavid du Colombier if(dsname[s] == nil){
171*4e3613abSDavid du Colombier snprint(name, sizeof name, "%d", s);
1729a747e4fSDavid du Colombier kstrdup(&dsname[s], name);
1739a747e4fSDavid du Colombier }
1749a747e4fSDavid du Colombier devdir(c, q, dsname[s], 0, nm, 0555, dp);
1757dd7cddfSDavid du Colombier return 1;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier if(s > dshiwat)
1787dd7cddfSDavid du Colombier return -1;
1797dd7cddfSDavid du Colombier q.path = QID(0, Qclonus);
1807dd7cddfSDavid du Colombier devdir(c, q, "clone", 0, eve, 0555, dp);
1817dd7cddfSDavid du Colombier return 1;
1827dd7cddfSDavid du Colombier case Qconvdir:
1837dd7cddfSDavid du Colombier if(s == DEVDOTDOT){
1849a747e4fSDavid du Colombier q.path = QID(0, Qprotodir);
1859a747e4fSDavid du Colombier q.type = QTDIR;
1869a747e4fSDavid du Colombier devdir(c, q, "ssl", 0, eve, 0555, dp);
1877dd7cddfSDavid du Colombier return 1;
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier ds = dstate[CONV(c->qid)];
1907dd7cddfSDavid du Colombier if(ds != 0)
1917dd7cddfSDavid du Colombier nm = ds->user;
1927dd7cddfSDavid du Colombier else
1937dd7cddfSDavid du Colombier nm = eve;
1947dd7cddfSDavid du Colombier switch(s) {
1957dd7cddfSDavid du Colombier default:
1967dd7cddfSDavid du Colombier return -1;
1977dd7cddfSDavid du Colombier case 0:
1987dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qctl);
1997dd7cddfSDavid du Colombier p = "ctl";
2007dd7cddfSDavid du Colombier break;
2017dd7cddfSDavid du Colombier case 1:
2027dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qdata);
2037dd7cddfSDavid du Colombier p = "data";
2047dd7cddfSDavid du Colombier break;
2057dd7cddfSDavid du Colombier case 2:
2067dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qsecretin);
2077dd7cddfSDavid du Colombier p = "secretin";
2087dd7cddfSDavid du Colombier break;
2097dd7cddfSDavid du Colombier case 3:
2107dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qsecretout);
2117dd7cddfSDavid du Colombier p = "secretout";
2127dd7cddfSDavid du Colombier break;
2137dd7cddfSDavid du Colombier case 4:
2147dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qencalgs);
2157dd7cddfSDavid du Colombier p = "encalgs";
2167dd7cddfSDavid du Colombier break;
2177dd7cddfSDavid du Colombier case 5:
2187dd7cddfSDavid du Colombier q.path = QID(CONV(c->qid), Qhashalgs);
2197dd7cddfSDavid du Colombier p = "hashalgs";
2207dd7cddfSDavid du Colombier break;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier devdir(c, q, p, 0, nm, 0660, dp);
2237dd7cddfSDavid du Colombier return 1;
2247dd7cddfSDavid du Colombier case Qclonus:
2257dd7cddfSDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
2267dd7cddfSDavid du Colombier return 1;
2277dd7cddfSDavid du Colombier default:
2287dd7cddfSDavid du Colombier ds = dstate[CONV(c->qid)];
2293ff48bf5SDavid du Colombier if(ds != 0)
2303ff48bf5SDavid du Colombier nm = ds->user;
2313ff48bf5SDavid du Colombier else
2323ff48bf5SDavid du Colombier nm = eve;
2333ff48bf5SDavid du Colombier devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
2347dd7cddfSDavid du Colombier return 1;
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier static Chan*
sslattach(char * spec)2397dd7cddfSDavid du Colombier sslattach(char *spec)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier Chan *c;
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier c = devattach('D', spec);
2449a747e4fSDavid du Colombier c->qid.path = QID(0, Qtopdir);
2457dd7cddfSDavid du Colombier c->qid.vers = 0;
2469a747e4fSDavid du Colombier c->qid.type = QTDIR;
2477dd7cddfSDavid du Colombier return c;
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier
2509a747e4fSDavid du Colombier static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)2519a747e4fSDavid du Colombier sslwalk(Chan *c, Chan *nc, char **name, int nname)
2527dd7cddfSDavid du Colombier {
2539a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, sslgen);
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier
2569a747e4fSDavid du Colombier static int
sslstat(Chan * c,uchar * db,int n)2579a747e4fSDavid du Colombier sslstat(Chan *c, uchar *db, int n)
2587dd7cddfSDavid du Colombier {
2599a747e4fSDavid du Colombier return devstat(c, db, n, nil, 0, sslgen);
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier
2627dd7cddfSDavid du Colombier static Chan*
sslopen(Chan * c,int omode)2637dd7cddfSDavid du Colombier sslopen(Chan *c, int omode)
2647dd7cddfSDavid du Colombier {
2657dd7cddfSDavid du Colombier Dstate *s, **pp;
2667dd7cddfSDavid du Colombier int perm;
2679a747e4fSDavid du Colombier int ft;
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier perm = 0;
2707dd7cddfSDavid du Colombier omode &= 3;
2717dd7cddfSDavid du Colombier switch(omode) {
2727dd7cddfSDavid du Colombier case OREAD:
2737dd7cddfSDavid du Colombier perm = 4;
2747dd7cddfSDavid du Colombier break;
2757dd7cddfSDavid du Colombier case OWRITE:
2767dd7cddfSDavid du Colombier perm = 2;
2777dd7cddfSDavid du Colombier break;
2787dd7cddfSDavid du Colombier case ORDWR:
2797dd7cddfSDavid du Colombier perm = 6;
2807dd7cddfSDavid du Colombier break;
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier
2839a747e4fSDavid du Colombier ft = TYPE(c->qid);
2849a747e4fSDavid du Colombier switch(ft) {
2857dd7cddfSDavid du Colombier default:
2867dd7cddfSDavid du Colombier panic("sslopen");
2877dd7cddfSDavid du Colombier case Qtopdir:
2887dd7cddfSDavid du Colombier case Qprotodir:
2897dd7cddfSDavid du Colombier case Qconvdir:
2907dd7cddfSDavid du Colombier if(omode != OREAD)
2917dd7cddfSDavid du Colombier error(Eperm);
2927dd7cddfSDavid du Colombier break;
2937dd7cddfSDavid du Colombier case Qclonus:
2947dd7cddfSDavid du Colombier s = dsclone(c);
2957dd7cddfSDavid du Colombier if(s == 0)
2967dd7cddfSDavid du Colombier error(Enodev);
2977dd7cddfSDavid du Colombier break;
2987dd7cddfSDavid du Colombier case Qctl:
2997dd7cddfSDavid du Colombier case Qdata:
3007dd7cddfSDavid du Colombier case Qsecretin:
3017dd7cddfSDavid du Colombier case Qsecretout:
3027dd7cddfSDavid du Colombier if(waserror()) {
3037dd7cddfSDavid du Colombier unlock(&dslock);
3047dd7cddfSDavid du Colombier nexterror();
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier lock(&dslock);
3077dd7cddfSDavid du Colombier pp = &dstate[CONV(c->qid)];
3087dd7cddfSDavid du Colombier s = *pp;
3097dd7cddfSDavid du Colombier if(s == 0)
3107dd7cddfSDavid du Colombier dsnew(c, pp);
3117dd7cddfSDavid du Colombier else {
3127dd7cddfSDavid du Colombier if((perm & (s->perm>>6)) != perm
3137dd7cddfSDavid du Colombier && (strcmp(up->user, s->user) != 0
3147dd7cddfSDavid du Colombier || (perm & s->perm) != perm))
3157dd7cddfSDavid du Colombier error(Eperm);
3167dd7cddfSDavid du Colombier
3177dd7cddfSDavid du Colombier s->ref++;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier unlock(&dslock);
3207dd7cddfSDavid du Colombier poperror();
3217dd7cddfSDavid du Colombier break;
3227dd7cddfSDavid du Colombier case Qencalgs:
3237dd7cddfSDavid du Colombier case Qhashalgs:
3247dd7cddfSDavid du Colombier if(omode != OREAD)
3257dd7cddfSDavid du Colombier error(Eperm);
3267dd7cddfSDavid du Colombier break;
3277dd7cddfSDavid du Colombier }
3287dd7cddfSDavid du Colombier c->mode = openmode(omode);
3297dd7cddfSDavid du Colombier c->flag |= COPEN;
3307dd7cddfSDavid du Colombier c->offset = 0;
3317dd7cddfSDavid du Colombier return c;
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier
3349a747e4fSDavid du Colombier static int
sslwstat(Chan * c,uchar * db,int n)3359a747e4fSDavid du Colombier sslwstat(Chan *c, uchar *db, int n)
3367dd7cddfSDavid du Colombier {
3379a747e4fSDavid du Colombier Dir *dir;
3387dd7cddfSDavid du Colombier Dstate *s;
3399a747e4fSDavid du Colombier int m;
3407dd7cddfSDavid du Colombier
3417dd7cddfSDavid du Colombier s = dstate[CONV(c->qid)];
3427dd7cddfSDavid du Colombier if(s == 0)
3437dd7cddfSDavid du Colombier error(Ebadusefd);
3447dd7cddfSDavid du Colombier if(strcmp(s->user, up->user) != 0)
3457dd7cddfSDavid du Colombier error(Eperm);
3467dd7cddfSDavid du Colombier
3479a747e4fSDavid du Colombier dir = smalloc(sizeof(Dir)+n);
3489a747e4fSDavid du Colombier m = convM2D(db, n, &dir[0], (char*)&dir[1]);
3499a747e4fSDavid du Colombier if(m == 0){
3509a747e4fSDavid du Colombier free(dir);
3519a747e4fSDavid du Colombier error(Eshortstat);
3529a747e4fSDavid du Colombier }
3539a747e4fSDavid du Colombier
3549a747e4fSDavid du Colombier if(!emptystr(dir->uid))
3559a747e4fSDavid du Colombier kstrdup(&s->user, dir->uid);
3569a747e4fSDavid du Colombier if(dir->mode != ~0UL)
3579a747e4fSDavid du Colombier s->perm = dir->mode;
3589a747e4fSDavid du Colombier
3599a747e4fSDavid du Colombier free(dir);
3609a747e4fSDavid du Colombier return m;
3617dd7cddfSDavid du Colombier }
3627dd7cddfSDavid du Colombier
3637dd7cddfSDavid du Colombier static void
sslclose(Chan * c)3647dd7cddfSDavid du Colombier sslclose(Chan *c)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier Dstate *s;
3679a747e4fSDavid du Colombier int ft;
3687dd7cddfSDavid du Colombier
3699a747e4fSDavid du Colombier ft = TYPE(c->qid);
3709a747e4fSDavid du Colombier switch(ft) {
3717dd7cddfSDavid du Colombier case Qctl:
3727dd7cddfSDavid du Colombier case Qdata:
3737dd7cddfSDavid du Colombier case Qsecretin:
3747dd7cddfSDavid du Colombier case Qsecretout:
3757dd7cddfSDavid du Colombier if((c->flag & COPEN) == 0)
3767dd7cddfSDavid du Colombier break;
3777dd7cddfSDavid du Colombier
3787dd7cddfSDavid du Colombier s = dstate[CONV(c->qid)];
3797dd7cddfSDavid du Colombier if(s == 0)
3807dd7cddfSDavid du Colombier break;
3817dd7cddfSDavid du Colombier
3827dd7cddfSDavid du Colombier lock(&dslock);
3837dd7cddfSDavid du Colombier if(--s->ref > 0) {
3847dd7cddfSDavid du Colombier unlock(&dslock);
3857dd7cddfSDavid du Colombier break;
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier dstate[CONV(c->qid)] = 0;
3887dd7cddfSDavid du Colombier unlock(&dslock);
3897dd7cddfSDavid du Colombier
3909a747e4fSDavid du Colombier if(s->user != nil)
3919a747e4fSDavid du Colombier free(s->user);
3927dd7cddfSDavid du Colombier sslhangup(s);
3937dd7cddfSDavid du Colombier if(s->c)
3947dd7cddfSDavid du Colombier cclose(s->c);
3957dd7cddfSDavid du Colombier if(s->in.secret)
3967dd7cddfSDavid du Colombier free(s->in.secret);
3977dd7cddfSDavid du Colombier if(s->out.secret)
3987dd7cddfSDavid du Colombier free(s->out.secret);
3997dd7cddfSDavid du Colombier if(s->in.state)
4007dd7cddfSDavid du Colombier free(s->in.state);
4017dd7cddfSDavid du Colombier if(s->out.state)
4027dd7cddfSDavid du Colombier free(s->out.state);
4037dd7cddfSDavid du Colombier free(s);
4047dd7cddfSDavid du Colombier
4057dd7cddfSDavid du Colombier }
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier
4087dd7cddfSDavid du Colombier /*
4097dd7cddfSDavid du Colombier * make sure we have at least 'n' bytes in list 'l'
4107dd7cddfSDavid du Colombier */
4117dd7cddfSDavid du Colombier static void
ensure(Dstate * s,Block ** l,int n)4127dd7cddfSDavid du Colombier ensure(Dstate *s, Block **l, int n)
4137dd7cddfSDavid du Colombier {
4147dd7cddfSDavid du Colombier int sofar, i;
4157dd7cddfSDavid du Colombier Block *b, *bl;
4167dd7cddfSDavid du Colombier
4177dd7cddfSDavid du Colombier sofar = 0;
4187dd7cddfSDavid du Colombier for(b = *l; b; b = b->next){
4197dd7cddfSDavid du Colombier sofar += BLEN(b);
4207dd7cddfSDavid du Colombier if(sofar >= n)
4217dd7cddfSDavid du Colombier return;
4227dd7cddfSDavid du Colombier l = &b->next;
4237dd7cddfSDavid du Colombier }
4247dd7cddfSDavid du Colombier
4257dd7cddfSDavid du Colombier while(sofar < n){
4267dd7cddfSDavid du Colombier bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
4277dd7cddfSDavid du Colombier if(bl == 0)
4289a747e4fSDavid du Colombier nexterror();
4297dd7cddfSDavid du Colombier *l = bl;
4307dd7cddfSDavid du Colombier i = 0;
4317dd7cddfSDavid du Colombier for(b = bl; b; b = b->next){
4327dd7cddfSDavid du Colombier i += BLEN(b);
4337dd7cddfSDavid du Colombier l = &b->next;
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier if(i == 0)
4367dd7cddfSDavid du Colombier error(Ehungup);
4377dd7cddfSDavid du Colombier sofar += i;
4387dd7cddfSDavid du Colombier }
4397dd7cddfSDavid du Colombier }
4407dd7cddfSDavid du Colombier
4417dd7cddfSDavid du Colombier /*
4427dd7cddfSDavid du Colombier * copy 'n' bytes from 'l' into 'p' and free
4437dd7cddfSDavid du Colombier * the bytes in 'l'
4447dd7cddfSDavid du Colombier */
4457dd7cddfSDavid du Colombier static void
consume(Block ** l,uchar * p,int n)4467dd7cddfSDavid du Colombier consume(Block **l, uchar *p, int n)
4477dd7cddfSDavid du Colombier {
4487dd7cddfSDavid du Colombier Block *b;
4497dd7cddfSDavid du Colombier int i;
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier for(; *l && n > 0; n -= i){
4527dd7cddfSDavid du Colombier b = *l;
4537dd7cddfSDavid du Colombier i = BLEN(b);
4547dd7cddfSDavid du Colombier if(i > n)
4557dd7cddfSDavid du Colombier i = n;
4567dd7cddfSDavid du Colombier memmove(p, b->rp, i);
4577dd7cddfSDavid du Colombier b->rp += i;
4587dd7cddfSDavid du Colombier p += i;
4597dd7cddfSDavid du Colombier if(BLEN(b) < 0)
4607dd7cddfSDavid du Colombier panic("consume");
4617dd7cddfSDavid du Colombier if(BLEN(b))
4627dd7cddfSDavid du Colombier break;
4637dd7cddfSDavid du Colombier *l = b->next;
4647dd7cddfSDavid du Colombier freeb(b);
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier
4687dd7cddfSDavid du Colombier /*
46959cc4ca5SDavid du Colombier * give back n bytes
47059cc4ca5SDavid du Colombier static void
47159cc4ca5SDavid du Colombier regurgitate(Dstate *s, uchar *p, int n)
47259cc4ca5SDavid du Colombier {
47359cc4ca5SDavid du Colombier Block *b;
47459cc4ca5SDavid du Colombier
47559cc4ca5SDavid du Colombier if(n <= 0)
47659cc4ca5SDavid du Colombier return;
47759cc4ca5SDavid du Colombier b = s->unprocessed;
47859cc4ca5SDavid du Colombier if(s->unprocessed == nil || b->rp - b->base < n) {
47959cc4ca5SDavid du Colombier b = allocb(n);
48059cc4ca5SDavid du Colombier memmove(b->wp, p, n);
48159cc4ca5SDavid du Colombier b->wp += n;
48259cc4ca5SDavid du Colombier b->next = s->unprocessed;
48359cc4ca5SDavid du Colombier s->unprocessed = b;
48459cc4ca5SDavid du Colombier } else {
48559cc4ca5SDavid du Colombier b->rp -= n;
48659cc4ca5SDavid du Colombier memmove(b->rp, p, n);
48759cc4ca5SDavid du Colombier }
48859cc4ca5SDavid du Colombier }
4899a747e4fSDavid du Colombier */
49059cc4ca5SDavid du Colombier
49159cc4ca5SDavid du Colombier /*
4927dd7cddfSDavid du Colombier * remove at most n bytes from the queue, if discard is set
4937dd7cddfSDavid du Colombier * dump the remainder
4947dd7cddfSDavid du Colombier */
4957dd7cddfSDavid du Colombier static Block*
qtake(Block ** l,int n,int discard)4969a747e4fSDavid du Colombier qtake(Block **l, int n, int discard)
4977dd7cddfSDavid du Colombier {
4987dd7cddfSDavid du Colombier Block *nb, *b, *first;
4997dd7cddfSDavid du Colombier int i;
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier first = *l;
5027dd7cddfSDavid du Colombier for(b = first; b; b = b->next){
5037dd7cddfSDavid du Colombier i = BLEN(b);
5047dd7cddfSDavid du Colombier if(i == n){
5057dd7cddfSDavid du Colombier if(discard){
5067dd7cddfSDavid du Colombier freeblist(b->next);
5077dd7cddfSDavid du Colombier *l = 0;
5087dd7cddfSDavid du Colombier } else
5097dd7cddfSDavid du Colombier *l = b->next;
5107dd7cddfSDavid du Colombier b->next = 0;
5117dd7cddfSDavid du Colombier return first;
5127dd7cddfSDavid du Colombier } else if(i > n){
5137dd7cddfSDavid du Colombier i -= n;
5147dd7cddfSDavid du Colombier if(discard){
5157dd7cddfSDavid du Colombier freeblist(b->next);
5167dd7cddfSDavid du Colombier b->wp -= i;
5177dd7cddfSDavid du Colombier *l = 0;
5187dd7cddfSDavid du Colombier } else {
5197dd7cddfSDavid du Colombier nb = allocb(i);
5207dd7cddfSDavid du Colombier memmove(nb->wp, b->rp+n, i);
5217dd7cddfSDavid du Colombier nb->wp += i;
5227dd7cddfSDavid du Colombier b->wp -= i;
5237dd7cddfSDavid du Colombier nb->next = b->next;
5247dd7cddfSDavid du Colombier *l = nb;
5257dd7cddfSDavid du Colombier }
5267dd7cddfSDavid du Colombier b->next = 0;
5277dd7cddfSDavid du Colombier if(BLEN(b) < 0)
5289a747e4fSDavid du Colombier panic("qtake");
5297dd7cddfSDavid du Colombier return first;
5307dd7cddfSDavid du Colombier } else
5317dd7cddfSDavid du Colombier n -= i;
5327dd7cddfSDavid du Colombier if(BLEN(b) < 0)
5339a747e4fSDavid du Colombier panic("qtake");
5347dd7cddfSDavid du Colombier }
5357dd7cddfSDavid du Colombier *l = 0;
5367dd7cddfSDavid du Colombier return first;
5377dd7cddfSDavid du Colombier }
5387dd7cddfSDavid du Colombier
53959cc4ca5SDavid du Colombier /*
54059cc4ca5SDavid du Colombier * We can't let Eintr's lose data since the program
54159cc4ca5SDavid du Colombier * doing the read may be able to handle it. The only
54259cc4ca5SDavid du Colombier * places Eintr is possible is during the read's in consume.
54359cc4ca5SDavid du Colombier * Therefore, we make sure we can always put back the bytes
54459cc4ca5SDavid du Colombier * consumed before the last ensure.
54559cc4ca5SDavid du Colombier */
5467dd7cddfSDavid du Colombier static Block*
sslbread(Chan * c,long n,ulong)5477dd7cddfSDavid du Colombier sslbread(Chan *c, long n, ulong)
5487dd7cddfSDavid du Colombier {
5499a747e4fSDavid du Colombier Dstate * volatile s;
5507dd7cddfSDavid du Colombier Block *b;
5519a747e4fSDavid du Colombier uchar consumed[3], *p;
5529a747e4fSDavid du Colombier int toconsume;
5537dd7cddfSDavid du Colombier int len, pad;
5547dd7cddfSDavid du Colombier
5559a747e4fSDavid du Colombier s = dstate[CONV(c->qid)];
5569a747e4fSDavid du Colombier if(s == 0)
5577dd7cddfSDavid du Colombier panic("sslbread");
5589a747e4fSDavid du Colombier if(s->state == Sincomplete)
5597dd7cddfSDavid du Colombier error(Ebadusefd);
5607dd7cddfSDavid du Colombier
5619a747e4fSDavid du Colombier qlock(&s->in.q);
5627dd7cddfSDavid du Colombier if(waserror()){
5639a747e4fSDavid du Colombier qunlock(&s->in.q);
5647dd7cddfSDavid du Colombier nexterror();
5657dd7cddfSDavid du Colombier }
5667dd7cddfSDavid du Colombier
5679a747e4fSDavid du Colombier if(s->processed == 0){
5689a747e4fSDavid du Colombier /*
5699a747e4fSDavid du Colombier * Read in the whole message. Until we've got it all,
5709a747e4fSDavid du Colombier * it stays on s->unprocessed, so that if we get Eintr,
5719a747e4fSDavid du Colombier * we'll pick up where we left off.
5729a747e4fSDavid du Colombier */
5739a747e4fSDavid du Colombier ensure(s, &s->unprocessed, 3);
5749a747e4fSDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 2);
5759a747e4fSDavid du Colombier p = s->unprocessed->rp;
5769a747e4fSDavid du Colombier if(p[0] & 0x80){
5779a747e4fSDavid du Colombier len = ((p[0] & 0x7f)<<8) | p[1];
5789a747e4fSDavid du Colombier ensure(s, &s->unprocessed, len);
5797dd7cddfSDavid du Colombier pad = 0;
5809a747e4fSDavid du Colombier toconsume = 2;
5817dd7cddfSDavid du Colombier } else {
5829a747e4fSDavid du Colombier s->unprocessed = pullupblock(s->unprocessed, 3);
5839a747e4fSDavid du Colombier len = ((p[0] & 0x3f)<<8) | p[1];
5849a747e4fSDavid du Colombier pad = p[2];
5857dd7cddfSDavid du Colombier if(pad > len){
5867dd7cddfSDavid du Colombier print("pad %d buf len %d\n", pad, len);
5877dd7cddfSDavid du Colombier error("bad pad in ssl message");
5887dd7cddfSDavid du Colombier }
5899a747e4fSDavid du Colombier toconsume = 3;
5907dd7cddfSDavid du Colombier }
5919a747e4fSDavid du Colombier ensure(s, &s->unprocessed, toconsume+len);
5927dd7cddfSDavid du Colombier
5939a747e4fSDavid du Colombier /* skip header */
5949a747e4fSDavid du Colombier consume(&s->unprocessed, consumed, toconsume);
5959a747e4fSDavid du Colombier
59659cc4ca5SDavid du Colombier /* grab the next message and decode/decrypt it */
5979a747e4fSDavid du Colombier b = qtake(&s->unprocessed, len, 0);
5989a747e4fSDavid du Colombier
5999a747e4fSDavid du Colombier if(blocklen(b) != len)
6009a747e4fSDavid du Colombier print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
6017dd7cddfSDavid du Colombier
6027dd7cddfSDavid du Colombier if(waserror()){
6039a747e4fSDavid du Colombier qunlock(&s->in.ctlq);
60459cc4ca5SDavid du Colombier if(b != nil)
60559cc4ca5SDavid du Colombier freeb(b);
6067dd7cddfSDavid du Colombier nexterror();
6077dd7cddfSDavid du Colombier }
6089a747e4fSDavid du Colombier qlock(&s->in.ctlq);
6099a747e4fSDavid du Colombier switch(s->state){
6107dd7cddfSDavid du Colombier case Sencrypting:
6119a747e4fSDavid du Colombier if(b == nil)
6129a747e4fSDavid du Colombier error("ssl message too short (encrypting)");
6139a747e4fSDavid du Colombier b = decryptb(s, b);
6147dd7cddfSDavid du Colombier break;
6157dd7cddfSDavid du Colombier case Sdigesting:
6169a747e4fSDavid du Colombier b = pullupblock(b, s->diglen);
61759cc4ca5SDavid du Colombier if(b == nil)
6189a747e4fSDavid du Colombier error("ssl message too short (digesting)");
6199a747e4fSDavid du Colombier checkdigestb(s, b);
62018027f8cSDavid du Colombier pullblock(&b, s->diglen);
62118027f8cSDavid du Colombier len -= s->diglen;
6227dd7cddfSDavid du Colombier break;
6237dd7cddfSDavid du Colombier case Sdigenc:
6249a747e4fSDavid du Colombier b = decryptb(s, b);
6259a747e4fSDavid du Colombier b = pullupblock(b, s->diglen);
62659cc4ca5SDavid du Colombier if(b == nil)
6279a747e4fSDavid du Colombier error("ssl message too short (dig+enc)");
6289a747e4fSDavid du Colombier checkdigestb(s, b);
62918027f8cSDavid du Colombier pullblock(&b, s->diglen);
6309a747e4fSDavid du Colombier len -= s->diglen;
6317dd7cddfSDavid du Colombier break;
6327dd7cddfSDavid du Colombier }
6337dd7cddfSDavid du Colombier
6347dd7cddfSDavid du Colombier /* remove pad */
6357dd7cddfSDavid du Colombier if(pad)
6369a747e4fSDavid du Colombier s->processed = qtake(&b, len - pad, 1);
63759cc4ca5SDavid du Colombier else
6389a747e4fSDavid du Colombier s->processed = b;
63959cc4ca5SDavid du Colombier b = nil;
6409a747e4fSDavid du Colombier s->in.mid++;
6419a747e4fSDavid du Colombier qunlock(&s->in.ctlq);
64259cc4ca5SDavid du Colombier poperror();
6437dd7cddfSDavid du Colombier }
6447dd7cddfSDavid du Colombier
6457dd7cddfSDavid du Colombier /* return at most what was asked for */
6469a747e4fSDavid du Colombier b = qtake(&s->processed, n, 0);
6477dd7cddfSDavid du Colombier
6489a747e4fSDavid du Colombier qunlock(&s->in.q);
6497dd7cddfSDavid du Colombier poperror();
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier return b;
6527dd7cddfSDavid du Colombier }
6537dd7cddfSDavid du Colombier
6547dd7cddfSDavid du Colombier static long
sslread(Chan * c,void * a,long n,vlong off)6557dd7cddfSDavid du Colombier sslread(Chan *c, void *a, long n, vlong off)
6567dd7cddfSDavid du Colombier {
6579a747e4fSDavid du Colombier Block * volatile b;
6587dd7cddfSDavid du Colombier Block *nb;
6597dd7cddfSDavid du Colombier uchar *va;
6607dd7cddfSDavid du Colombier int i;
6617dd7cddfSDavid du Colombier char buf[128];
6627dd7cddfSDavid du Colombier ulong offset = off;
6639a747e4fSDavid du Colombier int ft;
6647dd7cddfSDavid du Colombier
6659a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
6667dd7cddfSDavid du Colombier return devdirread(c, a, n, 0, 0, sslgen);
6677dd7cddfSDavid du Colombier
6689a747e4fSDavid du Colombier ft = TYPE(c->qid);
6699a747e4fSDavid du Colombier switch(ft) {
6707dd7cddfSDavid du Colombier default:
6717dd7cddfSDavid du Colombier error(Ebadusefd);
6727dd7cddfSDavid du Colombier case Qctl:
6739a747e4fSDavid du Colombier ft = CONV(c->qid);
674*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "%d", ft);
6757dd7cddfSDavid du Colombier return readstr(offset, a, n, buf);
6767dd7cddfSDavid du Colombier case Qdata:
6779a747e4fSDavid du Colombier b = sslbread(c, n, offset);
6787dd7cddfSDavid du Colombier break;
6797dd7cddfSDavid du Colombier case Qencalgs:
6807dd7cddfSDavid du Colombier return readstr(offset, a, n, encalgs);
6817dd7cddfSDavid du Colombier break;
6827dd7cddfSDavid du Colombier case Qhashalgs:
6837dd7cddfSDavid du Colombier return readstr(offset, a, n, hashalgs);
6847dd7cddfSDavid du Colombier break;
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier
6877dd7cddfSDavid du Colombier if(waserror()){
6889a747e4fSDavid du Colombier freeblist(b);
6897dd7cddfSDavid du Colombier nexterror();
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier
6927dd7cddfSDavid du Colombier n = 0;
6937dd7cddfSDavid du Colombier va = a;
6949a747e4fSDavid du Colombier for(nb = b; nb; nb = nb->next){
6957dd7cddfSDavid du Colombier i = BLEN(nb);
6967dd7cddfSDavid du Colombier memmove(va+n, nb->rp, i);
6977dd7cddfSDavid du Colombier n += i;
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier
7009a747e4fSDavid du Colombier freeblist(b);
7017dd7cddfSDavid du Colombier poperror();
7027dd7cddfSDavid du Colombier
7037dd7cddfSDavid du Colombier return n;
7047dd7cddfSDavid du Colombier }
7057dd7cddfSDavid du Colombier
7067dd7cddfSDavid du Colombier /*
7077dd7cddfSDavid du Colombier * this algorithm doesn't have to be great since we're just
7087dd7cddfSDavid du Colombier * trying to obscure the block fill
7097dd7cddfSDavid du Colombier */
7107dd7cddfSDavid du Colombier static void
randfill(uchar * buf,int len)7117dd7cddfSDavid du Colombier randfill(uchar *buf, int len)
7127dd7cddfSDavid du Colombier {
7137dd7cddfSDavid du Colombier while(len-- > 0)
7147dd7cddfSDavid du Colombier *buf++ = nrand(256);
7157dd7cddfSDavid du Colombier }
7167dd7cddfSDavid du Colombier
7179a747e4fSDavid du Colombier static long
sslbwrite(Chan * c,Block * b,ulong)7189a747e4fSDavid du Colombier sslbwrite(Chan *c, Block *b, ulong)
7199a747e4fSDavid du Colombier {
7209a747e4fSDavid du Colombier Dstate * volatile s;
7219a747e4fSDavid du Colombier long rv;
7229a747e4fSDavid du Colombier
7239a747e4fSDavid du Colombier s = dstate[CONV(c->qid)];
7249a747e4fSDavid du Colombier if(s == nil)
7259a747e4fSDavid du Colombier panic("sslbwrite");
7269a747e4fSDavid du Colombier
7279a747e4fSDavid du Colombier if(s->state == Sincomplete){
7289a747e4fSDavid du Colombier freeb(b);
7299a747e4fSDavid du Colombier error(Ebadusefd);
7309a747e4fSDavid du Colombier }
7319a747e4fSDavid du Colombier
7329a747e4fSDavid du Colombier /* lock so split writes won't interleave */
7339a747e4fSDavid du Colombier if(waserror()){
7349a747e4fSDavid du Colombier qunlock(&s->out.q);
7359a747e4fSDavid du Colombier nexterror();
7369a747e4fSDavid du Colombier }
7379a747e4fSDavid du Colombier qlock(&s->out.q);
7389a747e4fSDavid du Colombier
7399a747e4fSDavid du Colombier rv = sslput(s, b);
7409a747e4fSDavid du Colombier
7419a747e4fSDavid du Colombier poperror();
7429a747e4fSDavid du Colombier qunlock(&s->out.q);
7439a747e4fSDavid du Colombier
7449a747e4fSDavid du Colombier return rv;
7459a747e4fSDavid du Colombier }
7469a747e4fSDavid du Colombier
7477dd7cddfSDavid du Colombier /*
74859cc4ca5SDavid du Colombier * use SSL record format, add in count, digest and/or encrypt.
74959cc4ca5SDavid du Colombier * the write is interruptable. if it is interrupted, we'll
75059cc4ca5SDavid du Colombier * get out of sync with the far side. not much we can do about
75159cc4ca5SDavid du Colombier * it since we don't know if any bytes have been written.
7527dd7cddfSDavid du Colombier */
7537dd7cddfSDavid du Colombier static long
sslput(Dstate * s,Block * volatile b)7549a747e4fSDavid du Colombier sslput(Dstate *s, Block * volatile b)
7557dd7cddfSDavid du Colombier {
7567dd7cddfSDavid du Colombier Block *nb;
7577dd7cddfSDavid du Colombier int h, n, m, pad, rv;
7587dd7cddfSDavid du Colombier uchar *p;
7599a747e4fSDavid du Colombier int offset;
7607dd7cddfSDavid du Colombier
7617dd7cddfSDavid du Colombier if(waserror()){
7629a747e4fSDavid du Colombier if(b != nil)
763e360d427SDavid du Colombier freeb(b);
7647dd7cddfSDavid du Colombier nexterror();
7657dd7cddfSDavid du Colombier }
7667dd7cddfSDavid du Colombier
7677dd7cddfSDavid du Colombier rv = 0;
7689a747e4fSDavid du Colombier while(b != nil){
7699a747e4fSDavid du Colombier m = n = BLEN(b);
7709a747e4fSDavid du Colombier h = s->diglen + 2;
7717dd7cddfSDavid du Colombier
7727dd7cddfSDavid du Colombier /* trim to maximum block size */
7737dd7cddfSDavid du Colombier pad = 0;
7749a747e4fSDavid du Colombier if(m > s->max){
7759a747e4fSDavid du Colombier m = s->max;
7769a747e4fSDavid du Colombier } else if(s->blocklen != 1){
7779a747e4fSDavid du Colombier pad = (m + s->diglen)%s->blocklen;
7787dd7cddfSDavid du Colombier if(pad){
7799a747e4fSDavid du Colombier if(m > s->maxpad){
7807dd7cddfSDavid du Colombier pad = 0;
7819a747e4fSDavid du Colombier m = s->maxpad;
7827dd7cddfSDavid du Colombier } else {
7839a747e4fSDavid du Colombier pad = s->blocklen - pad;
7847dd7cddfSDavid du Colombier h++;
7857dd7cddfSDavid du Colombier }
7867dd7cddfSDavid du Colombier }
7877dd7cddfSDavid du Colombier }
7887dd7cddfSDavid du Colombier
7897dd7cddfSDavid du Colombier rv += m;
7907dd7cddfSDavid du Colombier if(m != n){
7917dd7cddfSDavid du Colombier nb = allocb(m + h + pad);
7929a747e4fSDavid du Colombier memmove(nb->wp + h, b->rp, m);
7937dd7cddfSDavid du Colombier nb->wp += m + h;
7949a747e4fSDavid du Colombier b->rp += m;
7957dd7cddfSDavid du Colombier } else {
7967dd7cddfSDavid du Colombier /* add header space */
7979a747e4fSDavid du Colombier nb = padblock(b, h);
7989a747e4fSDavid du Colombier b = 0;
7997dd7cddfSDavid du Colombier }
8009a747e4fSDavid du Colombier m += s->diglen;
8017dd7cddfSDavid du Colombier
8027dd7cddfSDavid du Colombier /* SSL style count */
8037dd7cddfSDavid du Colombier if(pad){
8047dd7cddfSDavid du Colombier nb = padblock(nb, -pad);
8057dd7cddfSDavid du Colombier randfill(nb->wp, pad);
8067dd7cddfSDavid du Colombier nb->wp += pad;
8077dd7cddfSDavid du Colombier m += pad;
8087dd7cddfSDavid du Colombier
8097dd7cddfSDavid du Colombier p = nb->rp;
8107dd7cddfSDavid du Colombier p[0] = (m>>8);
8117dd7cddfSDavid du Colombier p[1] = m;
8127dd7cddfSDavid du Colombier p[2] = pad;
8137dd7cddfSDavid du Colombier offset = 3;
8147dd7cddfSDavid du Colombier } else {
8157dd7cddfSDavid du Colombier p = nb->rp;
8167dd7cddfSDavid du Colombier p[0] = (m>>8) | 0x80;
8177dd7cddfSDavid du Colombier p[1] = m;
8187dd7cddfSDavid du Colombier offset = 2;
8197dd7cddfSDavid du Colombier }
8207dd7cddfSDavid du Colombier
8219a747e4fSDavid du Colombier switch(s->state){
8227dd7cddfSDavid du Colombier case Sencrypting:
8239a747e4fSDavid du Colombier nb = encryptb(s, nb, offset);
8247dd7cddfSDavid du Colombier break;
8257dd7cddfSDavid du Colombier case Sdigesting:
8269a747e4fSDavid du Colombier nb = digestb(s, nb, offset);
8277dd7cddfSDavid du Colombier break;
8287dd7cddfSDavid du Colombier case Sdigenc:
8299a747e4fSDavid du Colombier nb = digestb(s, nb, offset);
8309a747e4fSDavid du Colombier nb = encryptb(s, nb, offset);
8317dd7cddfSDavid du Colombier break;
8327dd7cddfSDavid du Colombier }
8337dd7cddfSDavid du Colombier
8349a747e4fSDavid du Colombier s->out.mid++;
8357dd7cddfSDavid du Colombier
8367dd7cddfSDavid du Colombier m = BLEN(nb);
8379a747e4fSDavid du Colombier devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
8389a747e4fSDavid du Colombier s->c->offset += m;
8397dd7cddfSDavid du Colombier }
8407dd7cddfSDavid du Colombier
8419a747e4fSDavid du Colombier poperror();
8427dd7cddfSDavid du Colombier return rv;
8437dd7cddfSDavid du Colombier }
8447dd7cddfSDavid du Colombier
8457dd7cddfSDavid du Colombier static void
setsecret(OneWay * w,uchar * secret,int n)8467dd7cddfSDavid du Colombier setsecret(OneWay *w, uchar *secret, int n)
8477dd7cddfSDavid du Colombier {
8487dd7cddfSDavid du Colombier if(w->secret)
8497dd7cddfSDavid du Colombier free(w->secret);
8507dd7cddfSDavid du Colombier
8517dd7cddfSDavid du Colombier w->secret = smalloc(n);
8527dd7cddfSDavid du Colombier memmove(w->secret, secret, n);
8537dd7cddfSDavid du Colombier w->slen = n;
8547dd7cddfSDavid du Colombier }
8557dd7cddfSDavid du Colombier
8567dd7cddfSDavid du Colombier static void
initDESkey(OneWay * w)8577dd7cddfSDavid du Colombier initDESkey(OneWay *w)
8587dd7cddfSDavid du Colombier {
8597dd7cddfSDavid du Colombier if(w->state){
8607dd7cddfSDavid du Colombier free(w->state);
8617dd7cddfSDavid du Colombier w->state = 0;
8627dd7cddfSDavid du Colombier }
8637dd7cddfSDavid du Colombier
8647dd7cddfSDavid du Colombier w->state = smalloc(sizeof(DESstate));
8657dd7cddfSDavid du Colombier if(w->slen >= 16)
8667dd7cddfSDavid du Colombier setupDESstate(w->state, w->secret, w->secret+8);
8677dd7cddfSDavid du Colombier else if(w->slen >= 8)
8687dd7cddfSDavid du Colombier setupDESstate(w->state, w->secret, 0);
8697dd7cddfSDavid du Colombier else
8707dd7cddfSDavid du Colombier error("secret too short");
8717dd7cddfSDavid du Colombier }
8727dd7cddfSDavid du Colombier
8737dd7cddfSDavid du Colombier /*
8747dd7cddfSDavid du Colombier * 40 bit DES is the same as 56 bit DES. However,
8757dd7cddfSDavid du Colombier * 16 bits of the key are masked to zero.
8767dd7cddfSDavid du Colombier */
8777dd7cddfSDavid du Colombier static void
initDESkey_40(OneWay * w)8787dd7cddfSDavid du Colombier initDESkey_40(OneWay *w)
8797dd7cddfSDavid du Colombier {
8807dd7cddfSDavid du Colombier uchar key[8];
8817dd7cddfSDavid du Colombier
8827dd7cddfSDavid du Colombier if(w->state){
8837dd7cddfSDavid du Colombier free(w->state);
8847dd7cddfSDavid du Colombier w->state = 0;
8857dd7cddfSDavid du Colombier }
8867dd7cddfSDavid du Colombier
8877dd7cddfSDavid du Colombier if(w->slen >= 8){
8887dd7cddfSDavid du Colombier memmove(key, w->secret, 8);
8897dd7cddfSDavid du Colombier key[0] &= 0x0f;
8907dd7cddfSDavid du Colombier key[2] &= 0x0f;
8917dd7cddfSDavid du Colombier key[4] &= 0x0f;
8927dd7cddfSDavid du Colombier key[6] &= 0x0f;
8937dd7cddfSDavid du Colombier }
8947dd7cddfSDavid du Colombier
8957dd7cddfSDavid du Colombier w->state = malloc(sizeof(DESstate));
896aa72973aSDavid du Colombier if(w->state == nil)
897aa72973aSDavid du Colombier error(Enomem);
8987dd7cddfSDavid du Colombier if(w->slen >= 16)
8997dd7cddfSDavid du Colombier setupDESstate(w->state, key, w->secret+8);
9007dd7cddfSDavid du Colombier else if(w->slen >= 8)
9017dd7cddfSDavid du Colombier setupDESstate(w->state, key, 0);
9027dd7cddfSDavid du Colombier else
9037dd7cddfSDavid du Colombier error("secret too short");
9047dd7cddfSDavid du Colombier }
9057dd7cddfSDavid du Colombier
9067dd7cddfSDavid du Colombier static void
initRC4key(OneWay * w)9077dd7cddfSDavid du Colombier initRC4key(OneWay *w)
9087dd7cddfSDavid du Colombier {
9097dd7cddfSDavid du Colombier if(w->state){
9107dd7cddfSDavid du Colombier free(w->state);
9117dd7cddfSDavid du Colombier w->state = 0;
9127dd7cddfSDavid du Colombier }
9137dd7cddfSDavid du Colombier
9147dd7cddfSDavid du Colombier w->state = smalloc(sizeof(RC4state));
9157dd7cddfSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9167dd7cddfSDavid du Colombier }
9177dd7cddfSDavid du Colombier
9187dd7cddfSDavid du Colombier /*
9197dd7cddfSDavid du Colombier * 40 bit RC4 is the same as n-bit RC4. However,
9207dd7cddfSDavid du Colombier * we ignore all but the first 40 bits of the key.
9217dd7cddfSDavid du Colombier */
9227dd7cddfSDavid du Colombier static void
initRC4key_40(OneWay * w)9237dd7cddfSDavid du Colombier initRC4key_40(OneWay *w)
9247dd7cddfSDavid du Colombier {
9257dd7cddfSDavid du Colombier if(w->state){
9267dd7cddfSDavid du Colombier free(w->state);
9277dd7cddfSDavid du Colombier w->state = 0;
9287dd7cddfSDavid du Colombier }
9297dd7cddfSDavid du Colombier
9307dd7cddfSDavid du Colombier if(w->slen > 5)
9317dd7cddfSDavid du Colombier w->slen = 5;
9327dd7cddfSDavid du Colombier
9337dd7cddfSDavid du Colombier w->state = malloc(sizeof(RC4state));
934aa72973aSDavid du Colombier if(w->state == nil)
935aa72973aSDavid du Colombier error(Enomem);
9367dd7cddfSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier
9397dd7cddfSDavid du Colombier /*
9407dd7cddfSDavid du Colombier * 128 bit RC4 is the same as n-bit RC4. However,
9417dd7cddfSDavid du Colombier * we ignore all but the first 128 bits of the key.
9427dd7cddfSDavid du Colombier */
9437dd7cddfSDavid du Colombier static void
initRC4key_128(OneWay * w)9447dd7cddfSDavid du Colombier initRC4key_128(OneWay *w)
9457dd7cddfSDavid du Colombier {
9467dd7cddfSDavid du Colombier if(w->state){
9477dd7cddfSDavid du Colombier free(w->state);
9487dd7cddfSDavid du Colombier w->state = 0;
9497dd7cddfSDavid du Colombier }
9507dd7cddfSDavid du Colombier
9517dd7cddfSDavid du Colombier if(w->slen > 16)
9527dd7cddfSDavid du Colombier w->slen = 16;
9537dd7cddfSDavid du Colombier
9547dd7cddfSDavid du Colombier w->state = malloc(sizeof(RC4state));
955aa72973aSDavid du Colombier if(w->state == nil)
956aa72973aSDavid du Colombier error(Enomem);
9577dd7cddfSDavid du Colombier setupRC4state(w->state, w->secret, w->slen);
9587dd7cddfSDavid du Colombier }
9597dd7cddfSDavid du Colombier
9607dd7cddfSDavid du Colombier
9617dd7cddfSDavid du Colombier typedef struct Hashalg Hashalg;
9627dd7cddfSDavid du Colombier struct Hashalg
9637dd7cddfSDavid du Colombier {
9647dd7cddfSDavid du Colombier char *name;
9657dd7cddfSDavid du Colombier int diglen;
9667dd7cddfSDavid du Colombier DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
9677dd7cddfSDavid du Colombier };
9687dd7cddfSDavid du Colombier
9697dd7cddfSDavid du Colombier Hashalg hashtab[] =
9707dd7cddfSDavid du Colombier {
9717dd7cddfSDavid du Colombier { "md4", MD4dlen, md4, },
9727dd7cddfSDavid du Colombier { "md5", MD5dlen, md5, },
9737dd7cddfSDavid du Colombier { "sha1", SHA1dlen, sha1, },
9747dd7cddfSDavid du Colombier { "sha", SHA1dlen, sha1, },
9757dd7cddfSDavid du Colombier { 0 }
9767dd7cddfSDavid du Colombier };
9777dd7cddfSDavid du Colombier
9787dd7cddfSDavid du Colombier static int
parsehashalg(char * p,Dstate * s)9797dd7cddfSDavid du Colombier parsehashalg(char *p, Dstate *s)
9807dd7cddfSDavid du Colombier {
9817dd7cddfSDavid du Colombier Hashalg *ha;
9827dd7cddfSDavid du Colombier
9837dd7cddfSDavid du Colombier for(ha = hashtab; ha->name; ha++){
9847dd7cddfSDavid du Colombier if(strcmp(p, ha->name) == 0){
9857dd7cddfSDavid du Colombier s->hf = ha->hf;
9867dd7cddfSDavid du Colombier s->diglen = ha->diglen;
9877dd7cddfSDavid du Colombier s->state &= ~Sclear;
9887dd7cddfSDavid du Colombier s->state |= Sdigesting;
9897dd7cddfSDavid du Colombier return 0;
9907dd7cddfSDavid du Colombier }
9917dd7cddfSDavid du Colombier }
9927dd7cddfSDavid du Colombier return -1;
9937dd7cddfSDavid du Colombier }
9947dd7cddfSDavid du Colombier
9957dd7cddfSDavid du Colombier typedef struct Encalg Encalg;
9967dd7cddfSDavid du Colombier struct Encalg
9977dd7cddfSDavid du Colombier {
9987dd7cddfSDavid du Colombier char *name;
9997dd7cddfSDavid du Colombier int blocklen;
10007dd7cddfSDavid du Colombier int alg;
10017dd7cddfSDavid du Colombier void (*keyinit)(OneWay*);
10027dd7cddfSDavid du Colombier };
10037dd7cddfSDavid du Colombier
10047dd7cddfSDavid du Colombier #ifdef NOSPOOKS
10057dd7cddfSDavid du Colombier Encalg encrypttab[] =
10067dd7cddfSDavid du Colombier {
10077dd7cddfSDavid du Colombier { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */
10087dd7cddfSDavid du Colombier { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */
10097dd7cddfSDavid du Colombier { "des_56_cbc", 8, DESCBC, initDESkey, },
10107dd7cddfSDavid du Colombier { "des_56_ecb", 8, DESECB, initDESkey, },
10117dd7cddfSDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10127dd7cddfSDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10137dd7cddfSDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10147dd7cddfSDavid du Colombier { "rc4_256", 1, RC4, initRC4key, },
10157dd7cddfSDavid du Colombier { "rc4_128", 1, RC4, initRC4key_128, },
10167dd7cddfSDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10177dd7cddfSDavid du Colombier { 0 }
10187dd7cddfSDavid du Colombier };
10197dd7cddfSDavid du Colombier #else
10207dd7cddfSDavid du Colombier Encalg encrypttab[] =
10217dd7cddfSDavid du Colombier {
10227dd7cddfSDavid du Colombier { "des_40_cbc", 8, DESCBC, initDESkey_40, },
10237dd7cddfSDavid du Colombier { "des_40_ecb", 8, DESECB, initDESkey_40, },
10247dd7cddfSDavid du Colombier { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */
10257dd7cddfSDavid du Colombier { "rc4_40", 1, RC4, initRC4key_40, },
10267dd7cddfSDavid du Colombier { 0 }
10277dd7cddfSDavid du Colombier };
10287dd7cddfSDavid du Colombier #endif NOSPOOKS
10297dd7cddfSDavid du Colombier
10307dd7cddfSDavid du Colombier static int
parseencryptalg(char * p,Dstate * s)10317dd7cddfSDavid du Colombier parseencryptalg(char *p, Dstate *s)
10327dd7cddfSDavid du Colombier {
10337dd7cddfSDavid du Colombier Encalg *ea;
10347dd7cddfSDavid du Colombier
10357dd7cddfSDavid du Colombier for(ea = encrypttab; ea->name; ea++){
10367dd7cddfSDavid du Colombier if(strcmp(p, ea->name) == 0){
10377dd7cddfSDavid du Colombier s->encryptalg = ea->alg;
10387dd7cddfSDavid du Colombier s->blocklen = ea->blocklen;
10397dd7cddfSDavid du Colombier (*ea->keyinit)(&s->in);
10407dd7cddfSDavid du Colombier (*ea->keyinit)(&s->out);
10417dd7cddfSDavid du Colombier s->state &= ~Sclear;
10427dd7cddfSDavid du Colombier s->state |= Sencrypting;
10437dd7cddfSDavid du Colombier return 0;
10447dd7cddfSDavid du Colombier }
10457dd7cddfSDavid du Colombier }
10467dd7cddfSDavid du Colombier return -1;
10477dd7cddfSDavid du Colombier }
10487dd7cddfSDavid du Colombier
10497dd7cddfSDavid du Colombier static long
sslwrite(Chan * c,void * a,long n,vlong)10509a747e4fSDavid du Colombier sslwrite(Chan *c, void *a, long n, vlong)
10517dd7cddfSDavid du Colombier {
10529a747e4fSDavid du Colombier Dstate * volatile s;
10539a747e4fSDavid du Colombier Block * volatile b;
10547dd7cddfSDavid du Colombier int m, t;
10557dd7cddfSDavid du Colombier char *p, *np, *e, buf[128];
10567dd7cddfSDavid du Colombier uchar *x;
10577dd7cddfSDavid du Colombier
1058f7db6155SDavid du Colombier x = nil;
10599a747e4fSDavid du Colombier s = dstate[CONV(c->qid)];
10609a747e4fSDavid du Colombier if(s == 0)
10617dd7cddfSDavid du Colombier panic("sslwrite");
10627dd7cddfSDavid du Colombier
10637dd7cddfSDavid du Colombier t = TYPE(c->qid);
10647dd7cddfSDavid du Colombier if(t == Qdata){
10659a747e4fSDavid du Colombier if(s->state == Sincomplete)
10667dd7cddfSDavid du Colombier error(Ebadusefd);
10677dd7cddfSDavid du Colombier
10689a747e4fSDavid du Colombier /* lock should a write gets split over multiple records */
10699a747e4fSDavid du Colombier if(waserror()){
10709a747e4fSDavid du Colombier qunlock(&s->out.q);
10719a747e4fSDavid du Colombier nexterror();
10729a747e4fSDavid du Colombier }
10739a747e4fSDavid du Colombier qlock(&s->out.q);
10749a747e4fSDavid du Colombier
10757dd7cddfSDavid du Colombier p = a;
10767dd7cddfSDavid du Colombier e = p + n;
10777dd7cddfSDavid du Colombier do {
10787dd7cddfSDavid du Colombier m = e - p;
10799a747e4fSDavid du Colombier if(m > s->max)
10809a747e4fSDavid du Colombier m = s->max;
10817dd7cddfSDavid du Colombier
10829a747e4fSDavid du Colombier b = allocb(m);
10837dd7cddfSDavid du Colombier if(waserror()){
10849a747e4fSDavid du Colombier freeb(b);
10857dd7cddfSDavid du Colombier nexterror();
10867dd7cddfSDavid du Colombier }
10879a747e4fSDavid du Colombier memmove(b->wp, p, m);
10887dd7cddfSDavid du Colombier poperror();
10899a747e4fSDavid du Colombier b->wp += m;
10907dd7cddfSDavid du Colombier
10919a747e4fSDavid du Colombier sslput(s, b);
10927dd7cddfSDavid du Colombier
10937dd7cddfSDavid du Colombier p += m;
10947dd7cddfSDavid du Colombier } while(p < e);
10959a747e4fSDavid du Colombier
10969a747e4fSDavid du Colombier poperror();
10979a747e4fSDavid du Colombier qunlock(&s->out.q);
10987dd7cddfSDavid du Colombier return n;
10997dd7cddfSDavid du Colombier }
11007dd7cddfSDavid du Colombier
11017dd7cddfSDavid du Colombier /* mutex with operations using what we're about to change */
11027dd7cddfSDavid du Colombier if(waserror()){
11039a747e4fSDavid du Colombier qunlock(&s->in.ctlq);
11049a747e4fSDavid du Colombier qunlock(&s->out.q);
11057dd7cddfSDavid du Colombier nexterror();
11067dd7cddfSDavid du Colombier }
11079a747e4fSDavid du Colombier qlock(&s->in.ctlq);
11089a747e4fSDavid du Colombier qlock(&s->out.q);
11097dd7cddfSDavid du Colombier
11107dd7cddfSDavid du Colombier switch(t){
11117dd7cddfSDavid du Colombier default:
11127dd7cddfSDavid du Colombier panic("sslwrite");
11137dd7cddfSDavid du Colombier case Qsecretin:
11149a747e4fSDavid du Colombier setsecret(&s->in, a, n);
11157dd7cddfSDavid du Colombier goto out;
11167dd7cddfSDavid du Colombier case Qsecretout:
11179a747e4fSDavid du Colombier setsecret(&s->out, a, n);
11187dd7cddfSDavid du Colombier goto out;
11197dd7cddfSDavid du Colombier case Qctl:
11207dd7cddfSDavid du Colombier break;
11217dd7cddfSDavid du Colombier }
11227dd7cddfSDavid du Colombier
11237dd7cddfSDavid du Colombier if(n >= sizeof(buf))
11247dd7cddfSDavid du Colombier error("arg too long");
11257dd7cddfSDavid du Colombier strncpy(buf, a, n);
11267dd7cddfSDavid du Colombier buf[n] = 0;
11277dd7cddfSDavid du Colombier p = strchr(buf, '\n');
11287dd7cddfSDavid du Colombier if(p)
11297dd7cddfSDavid du Colombier *p = 0;
11307dd7cddfSDavid du Colombier p = strchr(buf, ' ');
11317dd7cddfSDavid du Colombier if(p)
11327dd7cddfSDavid du Colombier *p++ = 0;
11337dd7cddfSDavid du Colombier
1134f7db6155SDavid du Colombier if(waserror()){
1135f7db6155SDavid du Colombier free(x);
1136f7db6155SDavid du Colombier nexterror();
1137f7db6155SDavid du Colombier }
11387dd7cddfSDavid du Colombier if(strcmp(buf, "fd") == 0){
11399a747e4fSDavid du Colombier s->c = buftochan(p);
11407dd7cddfSDavid du Colombier
11417dd7cddfSDavid du Colombier /* default is clear (msg delimiters only) */
11429a747e4fSDavid du Colombier s->state = Sclear;
11439a747e4fSDavid du Colombier s->blocklen = 1;
11449a747e4fSDavid du Colombier s->diglen = 0;
11459a747e4fSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11469a747e4fSDavid du Colombier s->in.mid = 0;
11479a747e4fSDavid du Colombier s->out.mid = 0;
11487dd7cddfSDavid du Colombier } else if(strcmp(buf, "alg") == 0 && p != 0){
11499a747e4fSDavid du Colombier s->blocklen = 1;
11509a747e4fSDavid du Colombier s->diglen = 0;
11517dd7cddfSDavid du Colombier
11529a747e4fSDavid du Colombier if(s->c == 0)
11537dd7cddfSDavid du Colombier error("must set fd before algorithm");
11547dd7cddfSDavid du Colombier
11559a747e4fSDavid du Colombier s->state = Sclear;
11569a747e4fSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
1157f7db6155SDavid du Colombier if(strcmp(p, "clear") == 0)
1158f7db6155SDavid du Colombier goto outx;
11597dd7cddfSDavid du Colombier
11609a747e4fSDavid du Colombier if(s->in.secret && s->out.secret == 0)
11619a747e4fSDavid du Colombier setsecret(&s->out, s->in.secret, s->in.slen);
11629a747e4fSDavid du Colombier if(s->out.secret && s->in.secret == 0)
11639a747e4fSDavid du Colombier setsecret(&s->in, s->out.secret, s->out.slen);
11649a747e4fSDavid du Colombier if(s->in.secret == 0 || s->out.secret == 0)
11657dd7cddfSDavid du Colombier error("algorithm but no secret");
11667dd7cddfSDavid du Colombier
11679a747e4fSDavid du Colombier s->hf = 0;
11689a747e4fSDavid du Colombier s->encryptalg = Noencryption;
11699a747e4fSDavid du Colombier s->blocklen = 1;
11707dd7cddfSDavid du Colombier
11717dd7cddfSDavid du Colombier for(;;){
11727dd7cddfSDavid du Colombier np = strchr(p, ' ');
11737dd7cddfSDavid du Colombier if(np)
11747dd7cddfSDavid du Colombier *np++ = 0;
11757dd7cddfSDavid du Colombier
11769a747e4fSDavid du Colombier if(parsehashalg(p, s) < 0)
11779a747e4fSDavid du Colombier if(parseencryptalg(p, s) < 0)
11787dd7cddfSDavid du Colombier error("bad algorithm");
11797dd7cddfSDavid du Colombier
11807dd7cddfSDavid du Colombier if(np == 0)
11817dd7cddfSDavid du Colombier break;
11827dd7cddfSDavid du Colombier p = np;
11837dd7cddfSDavid du Colombier }
11847dd7cddfSDavid du Colombier
11859a747e4fSDavid du Colombier if(s->hf == 0 && s->encryptalg == Noencryption)
11867dd7cddfSDavid du Colombier error("bad algorithm");
11877dd7cddfSDavid du Colombier
11889a747e4fSDavid du Colombier if(s->blocklen != 1){
11899a747e4fSDavid du Colombier s->max = (1<<15) - s->diglen - 1;
11909a747e4fSDavid du Colombier s->max -= s->max % s->blocklen;
11919a747e4fSDavid du Colombier s->maxpad = (1<<14) - s->diglen - 1;
11929a747e4fSDavid du Colombier s->maxpad -= s->maxpad % s->blocklen;
11937dd7cddfSDavid du Colombier } else
11949a747e4fSDavid du Colombier s->maxpad = s->max = (1<<15) - s->diglen - 1;
11957dd7cddfSDavid du Colombier } else if(strcmp(buf, "secretin") == 0 && p != 0) {
11967dd7cddfSDavid du Colombier m = (strlen(p)*3)/2;
11977dd7cddfSDavid du Colombier x = smalloc(m);
11989a747e4fSDavid du Colombier t = dec64(x, m, p, strlen(p));
1199f7db6155SDavid du Colombier if(t <= 0)
1200f7db6155SDavid du Colombier error(Ebadarg);
12019a747e4fSDavid du Colombier setsecret(&s->in, x, t);
12027dd7cddfSDavid du Colombier } else if(strcmp(buf, "secretout") == 0 && p != 0) {
12037dd7cddfSDavid du Colombier m = (strlen(p)*3)/2 + 1;
12047dd7cddfSDavid du Colombier x = smalloc(m);
12059a747e4fSDavid du Colombier t = dec64(x, m, p, strlen(p));
1206f7db6155SDavid du Colombier if(t <= 0)
1207f7db6155SDavid du Colombier error(Ebadarg);
12089a747e4fSDavid du Colombier setsecret(&s->out, x, t);
12097dd7cddfSDavid du Colombier } else
12107dd7cddfSDavid du Colombier error(Ebadarg);
1211f7db6155SDavid du Colombier outx:
1212f7db6155SDavid du Colombier free(x);
1213f7db6155SDavid du Colombier poperror();
12147dd7cddfSDavid du Colombier out:
12159a747e4fSDavid du Colombier qunlock(&s->in.ctlq);
12169a747e4fSDavid du Colombier qunlock(&s->out.q);
12177dd7cddfSDavid du Colombier poperror();
12187dd7cddfSDavid du Colombier return n;
12197dd7cddfSDavid du Colombier }
12207dd7cddfSDavid du Colombier
12217dd7cddfSDavid du Colombier static void
sslinit(void)12227dd7cddfSDavid du Colombier sslinit(void)
12237dd7cddfSDavid du Colombier {
12247dd7cddfSDavid du Colombier struct Encalg *e;
12257dd7cddfSDavid du Colombier struct Hashalg *h;
12267dd7cddfSDavid du Colombier int n;
12277dd7cddfSDavid du Colombier char *cp;
12287dd7cddfSDavid du Colombier
12297dd7cddfSDavid du Colombier n = 1;
12307dd7cddfSDavid du Colombier for(e = encrypttab; e->name != nil; e++)
12317dd7cddfSDavid du Colombier n += strlen(e->name) + 1;
12327dd7cddfSDavid du Colombier cp = encalgs = smalloc(n);
12337dd7cddfSDavid du Colombier for(e = encrypttab;;){
12347dd7cddfSDavid du Colombier strcpy(cp, e->name);
12357dd7cddfSDavid du Colombier cp += strlen(e->name);
12367dd7cddfSDavid du Colombier e++;
12377dd7cddfSDavid du Colombier if(e->name == nil)
12387dd7cddfSDavid du Colombier break;
12397dd7cddfSDavid du Colombier *cp++ = ' ';
12407dd7cddfSDavid du Colombier }
12417dd7cddfSDavid du Colombier *cp = 0;
12427dd7cddfSDavid du Colombier
12437dd7cddfSDavid du Colombier n = 1;
12447dd7cddfSDavid du Colombier for(h = hashtab; h->name != nil; h++)
12457dd7cddfSDavid du Colombier n += strlen(h->name) + 1;
12467dd7cddfSDavid du Colombier cp = hashalgs = smalloc(n);
12477dd7cddfSDavid du Colombier for(h = hashtab;;){
12487dd7cddfSDavid du Colombier strcpy(cp, h->name);
12497dd7cddfSDavid du Colombier cp += strlen(h->name);
12507dd7cddfSDavid du Colombier h++;
12517dd7cddfSDavid du Colombier if(h->name == nil)
12527dd7cddfSDavid du Colombier break;
12537dd7cddfSDavid du Colombier *cp++ = ' ';
12547dd7cddfSDavid du Colombier }
12557dd7cddfSDavid du Colombier *cp = 0;
12567dd7cddfSDavid du Colombier }
12577dd7cddfSDavid du Colombier
12587dd7cddfSDavid du Colombier Dev ssldevtab = {
12597dd7cddfSDavid du Colombier 'D',
12607dd7cddfSDavid du Colombier "ssl",
12617dd7cddfSDavid du Colombier
12627dd7cddfSDavid du Colombier devreset,
12637dd7cddfSDavid du Colombier sslinit,
12649a747e4fSDavid du Colombier devshutdown,
12657dd7cddfSDavid du Colombier sslattach,
12667dd7cddfSDavid du Colombier sslwalk,
12677dd7cddfSDavid du Colombier sslstat,
12687dd7cddfSDavid du Colombier sslopen,
12697dd7cddfSDavid du Colombier devcreate,
12707dd7cddfSDavid du Colombier sslclose,
12717dd7cddfSDavid du Colombier sslread,
12727dd7cddfSDavid du Colombier sslbread,
12737dd7cddfSDavid du Colombier sslwrite,
12747dd7cddfSDavid du Colombier sslbwrite,
12757dd7cddfSDavid du Colombier devremove,
12767dd7cddfSDavid du Colombier sslwstat,
12777dd7cddfSDavid du Colombier };
12787dd7cddfSDavid du Colombier
12797dd7cddfSDavid du Colombier static Block*
encryptb(Dstate * s,Block * b,int offset)12807dd7cddfSDavid du Colombier encryptb(Dstate *s, Block *b, int offset)
12817dd7cddfSDavid du Colombier {
12827dd7cddfSDavid du Colombier uchar *p, *ep, *p2, *ip, *eip;
12837dd7cddfSDavid du Colombier DESstate *ds;
12847dd7cddfSDavid du Colombier
12857dd7cddfSDavid du Colombier switch(s->encryptalg){
12867dd7cddfSDavid du Colombier case DESECB:
12877dd7cddfSDavid du Colombier ds = s->out.state;
12887dd7cddfSDavid du Colombier ep = b->rp + BLEN(b);
12897dd7cddfSDavid du Colombier for(p = b->rp + offset; p < ep; p += 8)
12907dd7cddfSDavid du Colombier block_cipher(ds->expanded, p, 0);
12917dd7cddfSDavid du Colombier break;
12927dd7cddfSDavid du Colombier case DESCBC:
12937dd7cddfSDavid du Colombier ds = s->out.state;
12947dd7cddfSDavid du Colombier ep = b->rp + BLEN(b);
12957dd7cddfSDavid du Colombier for(p = b->rp + offset; p < ep; p += 8){
12967dd7cddfSDavid du Colombier p2 = p;
12977dd7cddfSDavid du Colombier ip = ds->ivec;
12987dd7cddfSDavid du Colombier for(eip = ip+8; ip < eip; )
12997dd7cddfSDavid du Colombier *p2++ ^= *ip++;
13007dd7cddfSDavid du Colombier block_cipher(ds->expanded, p, 0);
13017dd7cddfSDavid du Colombier memmove(ds->ivec, p, 8);
13027dd7cddfSDavid du Colombier }
13037dd7cddfSDavid du Colombier break;
13047dd7cddfSDavid du Colombier case RC4:
13057dd7cddfSDavid du Colombier rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
13067dd7cddfSDavid du Colombier break;
13077dd7cddfSDavid du Colombier }
13087dd7cddfSDavid du Colombier return b;
13097dd7cddfSDavid du Colombier }
13107dd7cddfSDavid du Colombier
13117dd7cddfSDavid du Colombier static Block*
decryptb(Dstate * s,Block * bin)13127dd7cddfSDavid du Colombier decryptb(Dstate *s, Block *bin)
13137dd7cddfSDavid du Colombier {
13147dd7cddfSDavid du Colombier Block *b, **l;
13157dd7cddfSDavid du Colombier uchar *p, *ep, *tp, *ip, *eip;
13167dd7cddfSDavid du Colombier DESstate *ds;
13177dd7cddfSDavid du Colombier uchar tmp[8];
13187dd7cddfSDavid du Colombier int i;
13197dd7cddfSDavid du Colombier
13207dd7cddfSDavid du Colombier l = &bin;
13217dd7cddfSDavid du Colombier for(b = bin; b; b = b->next){
13227dd7cddfSDavid du Colombier /* make sure we have a multiple of s->blocklen */
13237dd7cddfSDavid du Colombier if(s->blocklen > 1){
13247dd7cddfSDavid du Colombier i = BLEN(b);
13257dd7cddfSDavid du Colombier if(i % s->blocklen){
13267dd7cddfSDavid du Colombier *l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
13277dd7cddfSDavid du Colombier if(b == 0)
13287dd7cddfSDavid du Colombier error("ssl encrypted message too short");
13297dd7cddfSDavid du Colombier }
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier l = &b->next;
13327dd7cddfSDavid du Colombier
13337dd7cddfSDavid du Colombier /* decrypt */
13347dd7cddfSDavid du Colombier switch(s->encryptalg){
13357dd7cddfSDavid du Colombier case DESECB:
13367dd7cddfSDavid du Colombier ds = s->in.state;
13377dd7cddfSDavid du Colombier ep = b->rp + BLEN(b);
13387dd7cddfSDavid du Colombier for(p = b->rp; p < ep; p += 8)
13397dd7cddfSDavid du Colombier block_cipher(ds->expanded, p, 1);
13407dd7cddfSDavid du Colombier break;
13417dd7cddfSDavid du Colombier case DESCBC:
13427dd7cddfSDavid du Colombier ds = s->in.state;
13437dd7cddfSDavid du Colombier ep = b->rp + BLEN(b);
13447dd7cddfSDavid du Colombier for(p = b->rp; p < ep;){
13457dd7cddfSDavid du Colombier memmove(tmp, p, 8);
13467dd7cddfSDavid du Colombier block_cipher(ds->expanded, p, 1);
13477dd7cddfSDavid du Colombier tp = tmp;
13487dd7cddfSDavid du Colombier ip = ds->ivec;
13497dd7cddfSDavid du Colombier for(eip = ip+8; ip < eip; ){
13507dd7cddfSDavid du Colombier *p++ ^= *ip;
13517dd7cddfSDavid du Colombier *ip++ = *tp++;
13527dd7cddfSDavid du Colombier }
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier break;
13557dd7cddfSDavid du Colombier case RC4:
13567dd7cddfSDavid du Colombier rc4(s->in.state, b->rp, BLEN(b));
13577dd7cddfSDavid du Colombier break;
13587dd7cddfSDavid du Colombier }
13597dd7cddfSDavid du Colombier }
13607dd7cddfSDavid du Colombier return bin;
13617dd7cddfSDavid du Colombier }
13627dd7cddfSDavid du Colombier
13637dd7cddfSDavid du Colombier static Block*
digestb(Dstate * s,Block * b,int offset)13647dd7cddfSDavid du Colombier digestb(Dstate *s, Block *b, int offset)
13657dd7cddfSDavid du Colombier {
13667dd7cddfSDavid du Colombier uchar *p;
13677dd7cddfSDavid du Colombier DigestState ss;
13687dd7cddfSDavid du Colombier uchar msgid[4];
13697dd7cddfSDavid du Colombier ulong n, h;
13707dd7cddfSDavid du Colombier OneWay *w;
13717dd7cddfSDavid du Colombier
13727dd7cddfSDavid du Colombier w = &s->out;
13737dd7cddfSDavid du Colombier
13747dd7cddfSDavid du Colombier memset(&ss, 0, sizeof(ss));
13757dd7cddfSDavid du Colombier h = s->diglen + offset;
13767dd7cddfSDavid du Colombier n = BLEN(b) - h;
13777dd7cddfSDavid du Colombier
13787dd7cddfSDavid du Colombier /* hash secret + message */
13797dd7cddfSDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
13807dd7cddfSDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
13817dd7cddfSDavid du Colombier
13827dd7cddfSDavid du Colombier /* hash message id */
13837dd7cddfSDavid du Colombier p = msgid;
13847dd7cddfSDavid du Colombier n = w->mid;
13857dd7cddfSDavid du Colombier *p++ = n>>24;
13867dd7cddfSDavid du Colombier *p++ = n>>16;
13877dd7cddfSDavid du Colombier *p++ = n>>8;
13887dd7cddfSDavid du Colombier *p = n;
13897dd7cddfSDavid du Colombier (*s->hf)(msgid, 4, b->rp + offset, &ss);
13907dd7cddfSDavid du Colombier
13917dd7cddfSDavid du Colombier return b;
13927dd7cddfSDavid du Colombier }
13937dd7cddfSDavid du Colombier
13947dd7cddfSDavid du Colombier static void
checkdigestb(Dstate * s,Block * bin)13957dd7cddfSDavid du Colombier checkdigestb(Dstate *s, Block *bin)
13967dd7cddfSDavid du Colombier {
13977dd7cddfSDavid du Colombier uchar *p;
13987dd7cddfSDavid du Colombier DigestState ss;
13997dd7cddfSDavid du Colombier uchar msgid[4];
14007dd7cddfSDavid du Colombier int n, h;
14017dd7cddfSDavid du Colombier OneWay *w;
14027dd7cddfSDavid du Colombier uchar digest[128];
14037dd7cddfSDavid du Colombier Block *b;
14047dd7cddfSDavid du Colombier
14057dd7cddfSDavid du Colombier w = &s->in;
14067dd7cddfSDavid du Colombier
14077dd7cddfSDavid du Colombier memset(&ss, 0, sizeof(ss));
14087dd7cddfSDavid du Colombier
14097dd7cddfSDavid du Colombier /* hash secret */
14107dd7cddfSDavid du Colombier (*s->hf)(w->secret, w->slen, 0, &ss);
14117dd7cddfSDavid du Colombier
14127dd7cddfSDavid du Colombier /* hash message */
14137dd7cddfSDavid du Colombier h = s->diglen;
14147dd7cddfSDavid du Colombier for(b = bin; b; b = b->next){
14157dd7cddfSDavid du Colombier n = BLEN(b) - h;
14167dd7cddfSDavid du Colombier if(n < 0)
14177dd7cddfSDavid du Colombier panic("checkdigestb");
14187dd7cddfSDavid du Colombier (*s->hf)(b->rp + h, n, 0, &ss);
14197dd7cddfSDavid du Colombier h = 0;
14207dd7cddfSDavid du Colombier }
14217dd7cddfSDavid du Colombier
14227dd7cddfSDavid du Colombier /* hash message id */
14237dd7cddfSDavid du Colombier p = msgid;
14247dd7cddfSDavid du Colombier n = w->mid;
14257dd7cddfSDavid du Colombier *p++ = n>>24;
14267dd7cddfSDavid du Colombier *p++ = n>>16;
14277dd7cddfSDavid du Colombier *p++ = n>>8;
14287dd7cddfSDavid du Colombier *p = n;
14297dd7cddfSDavid du Colombier (*s->hf)(msgid, 4, digest, &ss);
14307dd7cddfSDavid du Colombier
14317dd7cddfSDavid du Colombier if(memcmp(digest, bin->rp, s->diglen) != 0)
14327dd7cddfSDavid du Colombier error("bad digest");
14337dd7cddfSDavid du Colombier }
14347dd7cddfSDavid du Colombier
14357dd7cddfSDavid du Colombier /* get channel associated with an fd */
14367dd7cddfSDavid du Colombier static Chan*
buftochan(char * p)14377dd7cddfSDavid du Colombier buftochan(char *p)
14387dd7cddfSDavid du Colombier {
14397dd7cddfSDavid du Colombier Chan *c;
14407dd7cddfSDavid du Colombier int fd;
14417dd7cddfSDavid du Colombier
14427dd7cddfSDavid du Colombier if(p == 0)
14437dd7cddfSDavid du Colombier error(Ebadarg);
14447dd7cddfSDavid du Colombier fd = strtoul(p, 0, 0);
14457dd7cddfSDavid du Colombier if(fd < 0)
14467dd7cddfSDavid du Colombier error(Ebadarg);
14477dd7cddfSDavid du Colombier c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
14489a747e4fSDavid du Colombier if(devtab[c->type] == &ssldevtab){
14499a747e4fSDavid du Colombier cclose(c);
14509a747e4fSDavid du Colombier error("cannot ssl encrypt devssl files");
14519a747e4fSDavid du Colombier }
14527dd7cddfSDavid du Colombier return c;
14537dd7cddfSDavid du Colombier }
14547dd7cddfSDavid du Colombier
14557dd7cddfSDavid du Colombier /* hand up a digest connection */
14567dd7cddfSDavid du Colombier static void
sslhangup(Dstate * s)14577dd7cddfSDavid du Colombier sslhangup(Dstate *s)
14587dd7cddfSDavid du Colombier {
14597dd7cddfSDavid du Colombier Block *b;
14607dd7cddfSDavid du Colombier
14617dd7cddfSDavid du Colombier qlock(&s->in.q);
14627dd7cddfSDavid du Colombier for(b = s->processed; b; b = s->processed){
14637dd7cddfSDavid du Colombier s->processed = b->next;
14647dd7cddfSDavid du Colombier freeb(b);
14657dd7cddfSDavid du Colombier }
14667dd7cddfSDavid du Colombier if(s->unprocessed){
14677dd7cddfSDavid du Colombier freeb(s->unprocessed);
14687dd7cddfSDavid du Colombier s->unprocessed = 0;
14697dd7cddfSDavid du Colombier }
14707dd7cddfSDavid du Colombier s->state = Sincomplete;
14717dd7cddfSDavid du Colombier qunlock(&s->in.q);
14727dd7cddfSDavid du Colombier }
14737dd7cddfSDavid du Colombier
14747dd7cddfSDavid du Colombier static Dstate*
dsclone(Chan * ch)14757dd7cddfSDavid du Colombier dsclone(Chan *ch)
14767dd7cddfSDavid du Colombier {
14779a747e4fSDavid du Colombier int i;
14789a747e4fSDavid du Colombier Dstate *ret;
14797dd7cddfSDavid du Colombier
14807dd7cddfSDavid du Colombier if(waserror()) {
14817dd7cddfSDavid du Colombier unlock(&dslock);
14827dd7cddfSDavid du Colombier nexterror();
14837dd7cddfSDavid du Colombier }
14847dd7cddfSDavid du Colombier lock(&dslock);
14859a747e4fSDavid du Colombier ret = nil;
14869a747e4fSDavid du Colombier for(i=0; i<Maxdstate; i++){
14879a747e4fSDavid du Colombier if(dstate[i] == nil){
14889a747e4fSDavid du Colombier dsnew(ch, &dstate[i]);
14899a747e4fSDavid du Colombier ret = dstate[i];
14907dd7cddfSDavid du Colombier break;
14917dd7cddfSDavid du Colombier }
14927dd7cddfSDavid du Colombier }
14937dd7cddfSDavid du Colombier unlock(&dslock);
14947dd7cddfSDavid du Colombier poperror();
14959a747e4fSDavid du Colombier return ret;
14967dd7cddfSDavid du Colombier }
14977dd7cddfSDavid du Colombier
14987dd7cddfSDavid du Colombier static void
dsnew(Chan * ch,Dstate ** pp)14997dd7cddfSDavid du Colombier dsnew(Chan *ch, Dstate **pp)
15007dd7cddfSDavid du Colombier {
15017dd7cddfSDavid du Colombier Dstate *s;
15027dd7cddfSDavid du Colombier int t;
15037dd7cddfSDavid du Colombier
15047dd7cddfSDavid du Colombier *pp = s = malloc(sizeof(*s));
15057dd7cddfSDavid du Colombier if(!s)
15067dd7cddfSDavid du Colombier error(Enomem);
15077dd7cddfSDavid du Colombier if(pp - dstate >= dshiwat)
15087dd7cddfSDavid du Colombier dshiwat++;
15097dd7cddfSDavid du Colombier memset(s, 0, sizeof(*s));
15107dd7cddfSDavid du Colombier s->state = Sincomplete;
15117dd7cddfSDavid du Colombier s->ref = 1;
15129a747e4fSDavid du Colombier kstrdup(&s->user, up->user);
15137dd7cddfSDavid du Colombier s->perm = 0660;
15147dd7cddfSDavid du Colombier t = TYPE(ch->qid);
15157dd7cddfSDavid du Colombier if(t == Qclonus)
15167dd7cddfSDavid du Colombier t = Qctl;
15177dd7cddfSDavid du Colombier ch->qid.path = QID(pp - dstate, t);
15187dd7cddfSDavid du Colombier ch->qid.vers = 0;
15197dd7cddfSDavid du Colombier }
1520