From b85405263c6cd5855e446a312c5eeddcdeea4049 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 31 Mar 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-03-31 --- bitsy/devuda1341.c | 15 +- port/devkprof.c | 4 +- port/devloopback.c | 11 +- port/devssl.c | 4 +- port/devtls.c | 810 ++++++++++++++++++++++++--------------------- port/parse.c | 9 +- port/portclock.c | 10 +- 7 files changed, 463 insertions(+), 400 deletions(-) diff --git a/bitsy/devuda1341.c b/bitsy/devuda1341.c index cde4f8822a6d03860ddc2809fd9f68f699e611b4..cd6873c773d737b523f0ffafc86e5b6b384d88fc 100644 --- a/bitsy/devuda1341.c +++ b/bitsy/devuda1341.c @@ -44,13 +44,13 @@ static int debug = 0; * L3 setup and hold times (expressed in µs) */ enum { - L3_DataSetupTime = 1, /* 190 ns */ - L3_DataHoldTime = 1, /* 30 ns */ - L3_ModeSetupTime = 1, /* 190 ns */ - L3_ModeHoldTime = 1, /* 190 ns */ - L3_ClockHighTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ - L3_ClockLowTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ - L3_HaltTime = 1, /* 190 ns */ + L3_DataSetupTime = 10, /* 190 ns */ + L3_DataHoldTime = 10, /* 30 ns */ + L3_ModeSetupTime = 10, /* 190 ns */ + L3_ModeHoldTime = 10, /* 190 ns */ + L3_ClockHighTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ + L3_ClockLowTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ + L3_HaltTime = 10, /* 190 ns */ }; /* UDA 1341 Registers */ @@ -940,6 +940,7 @@ audioread(Chan *c, void *v, long n, vlong off) ulong offset = off; char *p; IOstate *s; + uchar voldata; n0 = n; p = v; diff --git a/port/devkprof.c b/port/devkprof.c index 95d0cc31fb551df35589f832265e90222fbd8d63..5da7c64a389115e7c6ba398de35bf8964fdb1d2e 100644 --- a/port/devkprof.c +++ b/port/devkprof.c @@ -76,7 +76,7 @@ kprofattach(char *spec) error(Enomem); } kproftab[0].length = n; - return devattach('T', spec); + return devattach('K', spec); } static int @@ -171,7 +171,7 @@ kprofwrite(Chan *c, void *a, long n, vlong) } Dev kprofdevtab = { - 'T', + 'K', "kprof", devreset, diff --git a/port/devloopback.c b/port/devloopback.c index a99f92ab4355389159996d30b44ad84fb4bbc42d..c1166ba2d8bb3240fa9ff116e38bb8b74433e7ba 100644 --- a/port/devloopback.c +++ b/port/devloopback.c @@ -123,7 +123,7 @@ loopbackinit(void) static Chan* loopbackattach(char *spec) { - Loop *lb; + Loop *volatile lb; Queue *q; Chan *c; int chan; @@ -472,8 +472,8 @@ loopbackwrite(Chan *c, void *va, long n, vlong off) { Loop *lb; Link *link; - Cmdbuf *cb; - Block *bp; + Cmdbuf *volatile cb; + Block *volatile bp; vlong d0, d0ns; long dn, dnns; @@ -492,6 +492,10 @@ loopbackwrite(Chan *c, void *va, long n, vlong off) lb = c->aux; link = &lb->link[ID(c->qid.path)]; cb = parsecmd(va, n); + if(waserror()){ + free(cb); + nexterror(); + } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "delay") == 0){ @@ -545,6 +549,7 @@ loopbackwrite(Chan *c, void *va, long n, vlong off) iunlock(link); }else error("unknown control request"); + free(cb); break; default: error(Eperm); diff --git a/port/devssl.c b/port/devssl.c index 9ed4d8eb40c6f7d67502de9dd9b3d02eda8bb38f..6ccfa3ccfa9289e0e73323e64c405abf27e92223 100644 --- a/port/devssl.c +++ b/port/devssl.c @@ -525,7 +525,7 @@ sslbread(Chan *c, long n, ulong) nconsumed = 0; if(waserror()){ - if(strcmp(up->error, Eintr) != 0) + if(strcmp(up->error, Eintr) == 0) regurgitate(s.s, consumed, nconsumed); qunlock(&s.s->in.q); nexterror(); @@ -773,9 +773,7 @@ sslbwrite(Chan *c, Block *b, ulong offset) s.s->out.mid++; - m = BLEN(nb); devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset); - s.s->c->offset += m; } qunlock(&s.s->out.q); poperror(); diff --git a/port/devtls.c b/port/devtls.c index 916ae8b293610aee8bebd75fb7b4705e4c152420..0839093978255278f8db028b055ad67f8011be8a 100644 --- a/port/devtls.c +++ b/port/devtls.c @@ -1,5 +1,5 @@ /* - * devtls - transport layer security 1.0 and secure sockets layer 3.0 record layer + * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 */ #include "u.h" #include "../port/lib.h" @@ -13,25 +13,8 @@ #define NOSPOOKS 1 typedef struct OneWay OneWay; -struct OneWay -{ - QLock q; - QLock ctlq; - - void *state; /* encryption state */ - int slen; /* hash data length */ - uchar *secret; /* secret */ - ulong mid; /* message id */ -}; - enum { - /* connection states */ - Sincomplete= 0, - Sclear= 1, - Sencrypting= 2, - Sdigesting= 4, - Sdigenc= Sencrypting|Sdigesting, /* encryption algorithms */ Noencryption= 0, @@ -40,27 +23,97 @@ enum RC4= 3 }; -typedef struct Dstate Dstate; -struct Dstate +enum { + MaxRecLen = 1<<14, /* max payload length of a record layer message */ + RecHdrLen = 5, + TLSVersion = 0x0301, + SSL3Version = 0x0300, + ProtocolVersion = 0x0301, /* maximum version we speak */ + MinProtoVersion = 0x0300, /* limits on version we accept */ + MaxProtoVersion = 0x03ff, +}; + +/* connection states */ +enum { + SHandshake, // doing handshake + SOpen, // application data can be sent + SRemoteClosed, // remote side has closed down + SError, // some sort of error has occured + SClosed, // it is all over +}; + +/* record types */ +enum { + RChangeCipherSpec = 20, + RAlert, + RHandshake, + RApplication, +}; + +/* alerts */ +enum { + ECloseNotify = 0, + EUnexpectedMessage = 10, + EBadRecordMac = 20, + EDecryptionFailed = 21, + ERecordOverflow = 22, + EDecompressionFailure = 30, + EHandshakeFailure = 40, + ENoCertificate = 41, + EBadCertificate = 42, + EUnsupportedCertificate = 43, + ECertificateRevoked = 44, + ECertificateExpired = 45, + ECertificateUnknown = 46, + EIllegalParameter = 47, + EUnknownCa = 48, + EAccessDenied = 49, + EDecodeError = 50, + EDecryptError = 51, + EExportRestriction = 60, + EProtocolVersion = 70, + EInsufficientSecurity = 71, + EInternalError = 80, + EUserCanceled = 90, + ENoRenegotiation = 100, + + EMAX = 256 +}; +struct OneWay { - Chan *c; /* io channel */ - uchar state; /* state of connection */ - int ref; /* serialized by dslock for atomic destroy */ + QLock q; /* locks io access */ + QLock ctlq; /* locks one-way paramaters */ + + ulong seq; + int keyed; /* have key, waiting for cipher enable */ - uchar encryptalg; /* encryption algorithm */ - ushort blocklen; /* blocking length */ + int protected; /* cipher is enabled */ + RC4state rc4; + uchar mackey[64]; +}; + + +typedef struct TlsRec TlsRec; +struct TlsRec +{ + Chan *c; /* io channel */ + int ref; /* serialized by dslock for atomic destroy */ + int version; /* version of the protocol we are speaking */ + int verset; /* version has been set */ - ushort diglen; /* length of digest */ - DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */ + Lock statelk; + int state; /* must be set using setstate */ - /* for SSL format */ - int max; /* maximum unpadded data per msg */ - int maxpad; /* maximum padded data per msg */ + /* record layer mac functions for different protocol versions */ + void (*packMac)(TlsRec*, uchar*, uchar*, uchar*, uchar*, int, uchar*); + DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); + int maclen; - /* input side */ + /* input side -- protected by in.q */ OneWay in; - Block *processed; - Block *unprocessed; + Queue *handq; /* queue of handshake messages */ + Block *processed; /* next bunch of application data */ + Block *unprocessed; /* data read from c but not parsed into records */ /* output side */ OneWay out; @@ -73,7 +126,7 @@ struct Dstate static Lock dslock; static int dshiwat; static int maxdstate = 128; -static Dstate** dstate; +static TlsRec** dstate; static char *encalgs; static char *hashalgs; @@ -90,8 +143,7 @@ enum{ Qconvdir, /* directory for a conversation */ Qdata, Qctl, - Qsecretin, - Qsecretout, + Qhand, Qencalgs, Qhashalgs, }; @@ -100,24 +152,32 @@ enum{ #define CONV(x) (((x).path >> 5)&(Maxdstate-1)) #define QID(c, y) (((c)<<5) | (y)) -static void ensure(Dstate*, Block**, int); +static void ensure(TlsRec*, Block**, int); static void consume(Block**, uchar*, int); static void setsecret(OneWay*, uchar*, int); -static Block* encryptb(Dstate*, Block*, int); -static Block* decryptb(Dstate*, Block*); -static Block* digestb(Dstate*, Block*, int); -static void checkdigestb(Dstate*, Block*); +static Block* encryptb(TlsRec*, Block*, int); +static Block* decryptb(TlsRec*, Block*); +static Block* digestb(TlsRec*, Block*, int); +static void checkdigestb(TlsRec*, Block*); static Chan* buftochan(char*); -static void tlshangup(Dstate*); -static Dstate* dsclone(Chan *c); -static void dsnew(Chan *c, Dstate **); +static void tlshangup(TlsRec*); +static TlsRec* dsclone(Chan *c); +static void dsnew(Chan *c, TlsRec **); +static void put64(uchar *p, vlong x); +static void put32(uchar *p, u32int); +static void put24(uchar *p, int); +static void put16(uchar *p, int); +static u32int get32(uchar *p); +static int get16(uchar *p); +static void tlsAlert(TlsRec *tr, int err); +static void tlsError(TlsRec *tr, int err, char *msg, ...); +#pragma varargck argpos tlsError 3 static char *tlsnames[] = { [Qclonus] "clone", [Qdata] "data", [Qctl] "ctl", -[Qsecretin] "secretin", -[Qsecretout] "secretout", +[Qhand] "hand", [Qencalgs] "encalgs", [Qhashalgs] "hashalgs", }; @@ -126,7 +186,7 @@ static int tlsgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp) { Qid q; - Dstate *ds; + TlsRec *ds; char name[16], *p, *nm; USED(nd); @@ -189,18 +249,14 @@ tlsgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp) p = "data"; break; case 2: - q.path = QID(CONV(c->qid), Qsecretin); - p = "secretin"; + q.path = QID(CONV(c->qid), Qhand); + p = "hand"; break; case 3: - q.path = QID(CONV(c->qid), Qsecretout); - p = "secretout"; - break; - case 4: q.path = QID(CONV(c->qid), Qencalgs); p = "encalgs"; break; - case 5: + case 4: q.path = QID(CONV(c->qid), Qhashalgs); p = "hashalgs"; break; @@ -223,7 +279,7 @@ tlsattach(char *spec) { Chan *c; - c = devattach('D', spec); + c = devattach('a', spec); c->qid.path = QID(0, Qtopdir)|CHDIR; c->qid.vers = 0; return c; @@ -244,7 +300,7 @@ tlsstat(Chan *c, char *db) static Chan* tlsopen(Chan *c, int omode) { - Dstate *s, **pp; + TlsRec *s, **pp; int perm; perm = 0; @@ -277,8 +333,7 @@ tlsopen(Chan *c, int omode) break; case Qctl: case Qdata: - case Qsecretin: - case Qsecretout: + case Qhand: if(waserror()) { unlock(&dslock); nexterror(); @@ -315,7 +370,7 @@ static void tlswstat(Chan *c, char *dp) { Dir d; - Dstate *s; + TlsRec *s; convM2D(dp, &d); @@ -332,13 +387,12 @@ tlswstat(Chan *c, char *dp) static void tlsclose(Chan *c) { - Dstate *s; + TlsRec *s; switch(TYPE(c->qid)) { case Qctl: case Qdata: - case Qsecretin: - case Qsecretout: + case Qhand: if((c->flag & COPEN) == 0) break; @@ -357,10 +411,6 @@ tlsclose(Chan *c) tlshangup(s); if(s->c) cclose(s->c); - free(s->in.secret); - free(s->out.secret); - free(s->in.state); - free(s->out.state); free(s); } } @@ -369,7 +419,7 @@ tlsclose(Chan *c) * make sure we have at least 'n' bytes in list 'l' */ static void -ensure(Dstate *s, Block **l, int n) +ensure(TlsRec *s, Block **l, int n) { int sofar, i; Block *b, *bl; @@ -429,7 +479,7 @@ consume(Block **l, uchar *p, int n) * give back n bytes */ static void -regurgitate(Dstate *s, uchar *p, int n) +regurgitate(TlsRec *s, uchar *p, int n) { Block *b; @@ -496,6 +546,129 @@ qremove(Block **l, int n, int discard) return first; } +/* + * read and process one tls record layer message + * must be called with tr->in.q held + */ +static void +tlsrecread(TlsRec *tr) +{ + OneWay *volatile in; + Block *volatile b; + uchar *p, seq[8], header[RecHdrLen], hmac[MD5dlen]; + int volatile nconsumed; + int len, type, ver; + + nconsumed = 0; + if(waserror()){ + if(strcmp(up->error, Eintr) == 0) + regurgitate(tr, header, nconsumed); + nexterror(); + } + ensure(tr, &tr->unprocessed, RecHdrLen); + consume(&tr->unprocessed, header, RecHdrLen); + nconsumed = RecHdrLen; + type = header[0]; + ver = get16(header+1); + len = get16(header+3); + if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion)) + tlsError(tr, EProtocolVersion, "invalid version in record layer"); + if(len <= 0) + tlsError(tr, EIllegalParameter, "invalid length in record layer"); + if(len > MaxRecLen) + tlsError(tr, ERecordOverflow, "record message too long"); + ensure(tr, &tr->unprocessed, len); + nconsumed = 0; + + /* + * if an Eintr happens after this, we're screwed. Make + * sure nothing we call can sleep. Luckily, allocb + * won't sleep, it'll just error out. + * grab the next message and decode/decrypt it + */ + b = qremove(&tr->unprocessed, len, 0); + + in = &tr->in; + if(waserror()){ + qunlock(&in->ctlq); + if(b != nil) + freeb(b); + nexterror(); + } + qlock(&in->ctlq); + b = pullupblock(b, len); + p = b->rp; + if(in->protected) { + if(len <= tr->maclen) + tlsError(tr, EDecodeError, "record message too short for mac"); + rc4(&in->rc4, p, len); + len -= tr->maclen; + + /* update length */ + put16(header+3, len); + put64(seq, in->seq); + in->seq++; + (*tr->packMac)(tr, in->mackey, seq, header, p, len, hmac); + if(memcmp(hmac, p+len, tr->maclen) != 0) + tlsError(tr, EBadRecordMac, "record mac mismatch"); + } + qunlock(&tr->in.ctlq); + poperror(); + if(len <= 0) + tlsError(tr, EDecodeError, "runt record message"); + + switch(type) { + default: + tlsError(tr, EIllegalParameter, "invalid record message 0x%x", type); + return; + case RChangeCipherSpec: + if(len != 1 || p[0] != 1) + tlsError(tr, EHandshakeFailure, "invalid change cipher spec"); + qlock(&in->ctlq); + if(!tr->in.keyed){ + qunlock(&in->ctlq); + tlsError(tr, EUnexpectedMessage, "unexpected change cipher spec"); + } + tr->in.keyed = 0; + tr->in.protected = 1; + tr->in.seq = 0; + qunlock(&in->ctlq); + break; + case RAlert: + if(len != 2) + tlsError(tr, EDecodeError, "invalid alert"); + if(p[0] == 1) { + if(p[1] == ECloseNotify) { + tlsError(tr, ECloseNotify, "remote close"); + tlsSetState(tr, SRemoteClosed); + } + } else { + tlsSetState(tr, SError); + tlsAlert(tr, p[1]); + } + break; + case RHandshake: + /* + * don't worry about dropping the block + * qbwrite always queue it even if flow controlled and interrupted. + */ + if(tr->handq != nil){ + qbwrite(tr->handq, b); + b = nil; + } + break; + case RApplication: +//ZZZ race on state + if(tr->state != SOpen) + tlsError(tr, EUnexpectedMessage, "application message received before handshake completed"); + tr->processed = b; + b = nil; + break; + } + if(b != nil) + freeb(b); +} + /* * We can't let Eintr's lose data since the program * doing the read may be able to handle it. The only @@ -504,106 +677,48 @@ qremove(Block **l, int n, int discard) * consumed before the last ensure. */ static Block* -tlsbread(Chan *c, long n, ulong) +tlsbread(Chan *c, long n, ulong offset) { - Dstate *volatile s; + TlsRec *volatile tr; Block *b; - uchar consumed[3]; - int nconsumed; - int len, pad; - s = dstate[CONV(c->qid)]; - if(s == nil) + switch(TYPE(c->qid)) { + default: + return devbread(c, n, offset); + case Qhand: + case Qdata: + break; + } + + tr = dstate[CONV(c->qid)]; + if(tr == nil) panic("tlsbread"); - if(s->state == Sincomplete) - error(Ebadusefd); - nconsumed = 0; if(waserror()){ - if(strcmp(up->error, Eintr) != 0) - regurgitate(s, consumed, nconsumed); - qunlock(&s->in.q); + qunlock(&tr->in.q); nexterror(); } - qlock(&s->in.q); - - if(s->processed == 0){ - /* read in the whole message */ - ensure(s, &s->unprocessed, 2); - consume(&s->unprocessed, consumed, 2); - nconsumed = 2; - if(consumed[0] & 0x80){ - len = ((consumed[0] & 0x7f)<<8) | consumed[1]; - ensure(s, &s->unprocessed, len); - pad = 0; - } else { - len = ((consumed[0] & 0x3f)<<8) | consumed[1]; - ensure(s, &s->unprocessed, len+1); - consume(&s->unprocessed, &consumed[2], 1); - pad = consumed[2]; - if(pad > len){ - print("pad %d buf len %d\n", pad, len); - error("bad pad in tls message"); - } - } - USED(nconsumed); - nconsumed = 0; - - /* if an Eintr happens after this, we're screwed. Make - * sure nothing we call can sleep. Luckily, allocb - * won't sleep, it'll just error out. - */ - - /* grab the next message and decode/decrypt it */ - b = qremove(&s->unprocessed, len, 0); - - if(waserror()){ - qunlock(&s->in.ctlq); - if(b != nil) - freeb(b); - nexterror(); - } - qlock(&s->in.ctlq); - switch(s->state){ - case Sencrypting: - b = decryptb(s, b); - break; - case Sdigesting: - b = pullupblock(b, s->diglen); - if(b == nil) - error("tls message too short"); - checkdigestb(s, b); - b->rp += s->diglen; - break; - case Sdigenc: - b = decryptb(s, b); - b = pullupblock(b, s->diglen); - if(b == nil) - error("tls message too short"); - checkdigestb(s, b); - b->rp += s->diglen; - len -= s->diglen; - break; - } + qlock(&tr->in.q); + if(TYPE(c->qid) == Qdata){ +//ZZZ race setting state + if(tr->state != SOpen) + error(Ebadusefd); + while(tr->processed == nil) + tlsrecread(tr); - /* remove pad */ - if(pad) - s->processed = qremove(&b, len - pad, 1); - else - s->processed = b; - b = nil; - s->in.mid++; - qunlock(&s->in.ctlq); + /* return at most what was asked for */ + b = qremove(&tr->processed, n, 0); + qunlock(&tr->in.q); + poperror(); + }else{ +//ZZZ race setting state + while(tr->state == SHandshake && !qcanread(tr->handq)) + tlsrecread(tr); + qunlock(&tr->in.q); poperror(); - USED(nconsumed); + b = qbread(tr->handq, n); } - /* return at most what was asked for */ - b = qremove(&s->processed, n, 0); - - qunlock(&s->in.q); - poperror(); - return b; } @@ -666,204 +781,135 @@ randfill(uchar *buf, int len) } /* - * use SSL record format, add in count, digest and/or encrypt. - * the write is interruptable. if it is interrupted, we'll - * get out of sync with the far side. not much we can do about - * it since we don't know if any bytes have been written. + * write a block in tls records */ -static long -tlsbwrite(Chan *c, Block *b, ulong offset) +static void +tlsrecwrite(TlsRec *tr, int type, Block *b) { - Dstate *volatile s; Block *volatile bb; Block *nb; - int h, n, m, pad, rv; - uchar *p; + uchar *p, seq[8]; + OneWay *volatile out; + int n, maclen; + out = &tr->out; bb = b; - s = dstate[CONV(c->qid)]; - if(s == nil) - panic("tlsbwrite"); - if(s->state == Sincomplete){ - freeb(b); - error(Ebadusefd); - } - if(waserror()){ - qunlock(&s->out.q); + qunlock(&out->q); if(bb != nil) freeb(bb); nexterror(); } - qlock(&s->out.q); + qlock(&out->q); - rv = 0; - while(bb){ - m = n = BLEN(bb); - h = s->diglen + 2; - - /* trim to maximum block size */ - pad = 0; - if(m > s->max){ - m = s->max; - } else if(s->blocklen != 1){ - pad = (m + s->diglen)%s->blocklen; - if(pad){ - if(m > s->maxpad){ - pad = 0; - m = s->maxpad; - } else { - pad = s->blocklen - pad; - h++; - } - } - } + while(bb != nil){ +//ZZZ race on state + if(tr->state != SHandshake && tr->state != SOpen) + error(Ebadusefd); - rv += m; - if(m != n){ - nb = allocb(m + h + pad); - memmove(nb->wp + h, bb->rp, m); - nb->wp += m + h; - bb->rp += m; - } else { - /* add header space */ - nb = padblock(bb, h); - bb = nil; - } - m += s->diglen; - - /* SSL style count */ - if(pad){ - nb = padblock(nb, -pad); - randfill(nb->wp, pad); - nb->wp += pad; - m += pad; - - p = nb->rp; - p[0] = (m>>8); - p[1] = m; - p[2] = pad; - offset = 3; - } else { - p = nb->rp; - p[0] = (m>>8) | 0x80; - p[1] = m; - offset = 2; + /* + * get at most one maximal record's input, + * with padding on the front for header and back for mac + */ + if(waserror()){ + qunlock(&out->ctlq); + nexterror(); } - - switch(s->state){ - case Sencrypting: - nb = encryptb(s, nb, offset); - break; - case Sdigesting: - nb = digestb(s, nb, offset); - break; - case Sdigenc: - nb = digestb(s, nb, offset); - nb = encryptb(s, nb, offset); - break; + qlock(&out->ctlq); + maclen = 0; + if(out->protected) + maclen = tr->maclen; + n = BLEN(bb); + if(n > MaxRecLen){ + n = MaxRecLen; + nb = allocb(n + RecHdrLen + maclen); + memmove(nb->wp + RecHdrLen, bb->rp, n); + nb->wp += n + RecHdrLen; + bb->rp += n; + }else{ + /* + * carefully reuse bb so it will get freed if we're out of memory + */ + bb = padblock(bb, RecHdrLen); + if(maclen) + nb = padblock(bb, -maclen); + else + nb = bb; + bb = nil; } - s->out.mid++; - - m = BLEN(nb); - devtab[s->c->type]->bwrite(s->c, nb, s->c->offset); - s->c->offset += m; - } - qunlock(&s->out.q); - poperror(); + p = nb->rp; + p[0] = type; + put16(p+1, tr->version); + put16(p+3, n); - return rv; -} + if(out->protected){ + put64(seq, out->seq); + out->seq++; + (*tr->packMac)(tr, out->mackey, seq, p, p + RecHdrLen, n, nb->wp); + b->wp += maclen; + n += maclen; -static void -setsecret(OneWay *w, uchar *secret, int n) -{ - if(w->secret) - free(w->secret); + /* update length */ + put16(p+3, n); - w->secret = smalloc(n); - memmove(w->secret, secret, n); - w->slen = n; -} + /* encrypt */ + rc4(&out->rc4, p+RecHdrLen, n); + } + qunlock(&out->ctlq); + poperror(); -static void -initDESkey(OneWay *w) -{ - if(w->state){ - free(w->state); - w->state = 0; + /* + * if bwrite error's, we assume the block is queued. + * if not, we're out of sync with the receiver and will not recover. + */ + devtab[tr->c->type]->bwrite(tr->c, nb, 0); } - - w->state = smalloc(sizeof(DESstate)); - if(w->slen >= 16) - setupDESstate(w->state, w->secret, w->secret+8); - else if(w->slen >= 8) - setupDESstate(w->state, w->secret, 0); - else - error("secret too short"); + qunlock(&out->q); + poperror(); } -/* - * 40 bit DES is the same as 56 bit DES. However, - * 16 bits of the key are masked to zero. - */ -static void -initDESkey_40(OneWay *w) +static long +tlsbwrite(Chan *c, Block *b, ulong offset) { - uchar key[8]; + TlsRec *tr; + ulong n; - if(w->state){ - free(w->state); - w->state = 0; - } + n = BLEN(b); - if(w->slen >= 8){ - memmove(key, w->secret, 8); - key[0] &= 0x0f; - key[2] &= 0x0f; - key[4] &= 0x0f; - key[6] &= 0x0f; - } - - w->state = malloc(sizeof(DESstate)); - if(w->slen >= 16) - setupDESstate(w->state, key, w->secret+8); - else if(w->slen >= 8) - setupDESstate(w->state, key, 0); - else - error("secret too short"); -} + tr = dstate[CONV(c->qid)]; + if(tr == nil) + panic("tlsbread"); -static void -initRC4key(OneWay *w) -{ - if(w->state){ - free(w->state); - w->state = 0; + switch(TYPE(c->qid)) { + default: + return devbwrite(c, b, offset); + case Qhand: +//ZZZ race setting state + if(tr->state != SHandshake && tr->state != SOpen) + error(Ebadusefd); + tlsrecwrite(tr, RHandshake, b); + break; + case Qdata: +//ZZZ race setting state + if(tr->state != SOpen) + error(Ebadusefd); + tlsrecwrite(tr, RApplication, b); + break; } - w->state = smalloc(sizeof(RC4state)); - setupRC4state(w->state, w->secret, w->slen); + return n; } -/* - * 40 bit RC4 is the same as n-bit RC4. However, - * we ignore all but the first 40 bits of the key. - */ static void -initRC4key_40(OneWay *w) +setsecret(OneWay *w, uchar *secret, int n) { - if(w->state){ - free(w->state); - w->state = 0; - } - - if(w->slen > 5) - w->slen = 5; + if(w->secret) + free(w->secret); - w->state = malloc(sizeof(RC4state)); - setupRC4state(w->state, w->secret, w->slen); + w->secret = smalloc(n); + memmove(w->secret, secret, n); + w->slen = n; } /* @@ -897,12 +943,11 @@ struct Hashalg Hashalg hashtab[] = { { "md5", MD5dlen, md5, }, - { "sha1", SHA1dlen, sha1, }, { 0 } }; static int -parsehashalg(char *p, Dstate *s) +parsehashalg(char *p, TlsRec *s) { Hashalg *ha; @@ -927,34 +972,14 @@ struct Encalg void (*keyinit)(OneWay*); }; -#ifdef NOSPOOKS Encalg encrypttab[] = { - { "descbc", 8, DESCBC, initDESkey, }, /* DEPRECATED -- use des_56_cbc */ - { "desecb", 8, DESECB, initDESkey, }, /* DEPRECATED -- use des_56_ecb */ - { "des_56_cbc", 8, DESCBC, initDESkey, }, - { "des_56_ecb", 8, DESECB, initDESkey, }, - { "des_40_cbc", 8, DESCBC, initDESkey_40, }, - { "des_40_ecb", 8, DESECB, initDESkey_40, }, - { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */ - { "rc4_256", 1, RC4, initRC4key, }, { "rc4_128", 1, RC4, initRC4key_128, }, - { "rc4_40", 1, RC4, initRC4key_40, }, - { 0 } -}; -#else -Encalg encrypttab[] = -{ - { "des_40_cbc", 8, DESCBC, initDESkey_40, }, - { "des_40_ecb", 8, DESECB, initDESkey_40, }, - { "rc4", 1, RC4, initRC4key_40, }, /* DEPRECATED -- use rc4_X */ - { "rc4_40", 1, RC4, initRC4key_40, }, { 0 } }; -#endif NOSPOOKS static int -parseencryptalg(char *p, Dstate *s) +parseencryptalg(char *p, TlsRec *s) { Encalg *ea; @@ -975,28 +1000,25 @@ parseencryptalg(char *p, Dstate *s) static long tlswrite(Chan *c, void *a, long n, vlong off) { - Dstate *volatile s; + TlsRec *volatile tr; Block *volatile b; int m, t; char *p, *np, *e, buf[128]; uchar *x; ulong offset = off; - s = dstate[CONV(c->qid)]; - if(s == nil) + tr = dstate[CONV(c->qid)]; + if(tr == nil) panic("tlswrite"); t = TYPE(c->qid); - if(t == Qdata){ - if(s->state == Sincomplete) - error(Ebadusefd); - + if(t == Qdata || t == Qhand){ p = a; e = p + n; do { m = e - p; - if(m > s->max) - m = s->max; + if(m > MaxRecLen) + m = MaxRecLen; b = allocb(m); if(waserror()){ @@ -1025,13 +1047,7 @@ tlswrite(Chan *c, void *a, long n, vlong off) switch(t){ default: - panic("tlswrite"); - case Qsecretin: - setsecret(&s->in, a, n); - goto out; - case Qsecretout: - setsecret(&s->out, a, n); - goto out; + error(Ebadusefd); case Qctl: break; } @@ -1048,13 +1064,14 @@ tlswrite(Chan *c, void *a, long n, vlong off) *p++ = 0; if(strcmp(buf, "fd") == 0){ + if(s->c != nil) + error(Einuse); s->c = buftochan(p); /* default is clear (msg delimiters only) */ s->state = Sclear; s->blocklen = 1; s->diglen = 0; - s->maxpad = s->max = (1<<15) - s->diglen - 1; s->in.mid = 0; s->out.mid = 0; } else if(strcmp(buf, "alg") == 0 && p != 0){ @@ -1135,7 +1152,7 @@ tlsinit(void) int n; char *cp; - if((dstate = smalloc(sizeof(Dstate*) * maxdstate)) == 0) + if((dstate = smalloc(sizeof(TlsRec*) * maxdstate)) == 0) panic("tlsinit"); n = 1; @@ -1168,7 +1185,7 @@ tlsinit(void) } Dev tlsdevtab = { - 'D', + 'a', "tls", devreset, @@ -1189,7 +1206,7 @@ Dev tlsdevtab = { }; static Block* -encryptb(Dstate *s, Block *b, int offset) +encryptb(TlsRec *s, Block *b, int offset) { uchar *p, *ep, *p2, *ip, *eip; DESstate *ds; @@ -1221,7 +1238,7 @@ encryptb(Dstate *s, Block *b, int offset) } static Block* -decryptb(Dstate *s, Block *bin) +decryptb(TlsRec *s, Block *bin) { Block *b, **l; uchar *p, *ep, *tp, *ip, *eip; @@ -1273,7 +1290,7 @@ decryptb(Dstate *s, Block *bin) } static Block* -digestb(Dstate *s, Block *b, int offset) +digestb(TlsRec *s, Block *b, int offset) { uchar *p; DigestState ss; @@ -1304,7 +1321,7 @@ digestb(Dstate *s, Block *b, int offset) } static void -checkdigestb(Dstate *s, Block *bin) +checkdigestb(TlsRec *s, Block *bin) { uchar *p; DigestState ss; @@ -1362,7 +1379,7 @@ buftochan(char *p) /* hand up a digest connection */ static void -tlshangup(Dstate *s) +tlshangup(TlsRec *s) { Block *b; @@ -1371,18 +1388,18 @@ tlshangup(Dstate *s) s->processed = b->next; freeb(b); } - if(s->unprocessed){ + if(s->unprocessed != nil){ freeb(s->unprocessed); - s->unprocessed = 0; + s->unprocessed = nil; } s->state = Sincomplete; qunlock(&s->in.q); } -static Dstate* +static TlsRec* dsclone(Chan *ch) { - Dstate **pp, **ep, **np; + TlsRec **pp, **ep, **np; int newmax; if(waserror()) { @@ -1392,7 +1409,7 @@ dsclone(Chan *ch) lock(&dslock); ep = &dstate[maxdstate]; for(pp = dstate; pp < ep; pp++) { - if(*pp == 0) { + if(*pp == nil) { dsnew(ch, pp); break; } @@ -1401,18 +1418,18 @@ dsclone(Chan *ch) if(maxdstate >= Maxdstate) { unlock(&dslock); poperror(); - return 0; + return nil; } newmax = 2 * maxdstate; if(newmax > Maxdstate) newmax = Maxdstate; - np = smalloc(sizeof(Dstate*) * newmax); - if(np == 0) + np = smalloc(sizeof(TlsRec*) * newmax); + if(np == nil) error(Enomem); - memmove(np, dstate, sizeof(Dstate*) * maxdstate); + memmove(np, dstate, sizeof(TlsRec*) * maxdstate); dstate = np; pp = &dstate[maxdstate]; - memset(pp, 0, sizeof(Dstate*)*(newmax - maxdstate)); + memset(pp, 0, sizeof(TlsRec*)*(newmax - maxdstate)); maxdstate = newmax; dsnew(ch, pp); } @@ -1422,9 +1439,9 @@ dsclone(Chan *ch) } static void -dsnew(Chan *ch, Dstate **pp) +dsnew(Chan *ch, TlsRec **pp) { - Dstate *s; + TlsRec *s; int t; *pp = s = malloc(sizeof(*s)); @@ -1443,3 +1460,38 @@ dsnew(Chan *ch, Dstate **pp) ch->qid.path = QID(pp - dstate, t); ch->qid.vers = 0; } + +static void +put32(uchar *p, u32int x) +{ + p[0] = x>>24; + p[1] = x>>16; + p[2] = x>>8; + p[3] = x; +} + +static void +put64(uchar *p, vlong x) +{ + put32(p, (u32int)(x >> 32)); + put32(p+4, (u32int)x); +} + +static void +put16(uchar *p, int x) +{ + p[0] = x>>8; + p[1] = x; +} + +static u32int +get32(uchar *p) +{ + return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; +} + +static int +get16(uchar *p) +{ + return (p[0]<<8)|p[1]; +} diff --git a/port/parse.c b/port/parse.c index 352bd0a7db2cdc3eda39b514955aa97a5ab1f003..637bd314ae674e6e32c2844404efc1c18cf712ed 100644 --- a/port/parse.c +++ b/port/parse.c @@ -11,13 +11,20 @@ Cmdbuf* parsecmd(char *p, int n) { - Cmdbuf *cb; + Cmdbuf *volatile cb; cb = smalloc(sizeof(*cb)); if(n > sizeof(cb->buf)-1) n = sizeof(cb->buf)-1; + + if(waserror()){ + free(cb); + nexterror(); + } memmove(cb->buf, p, n); + poperror(); + if(n > 0 && cb->buf[n-1] == '\n') n--; cb->buf[n] = '\0'; diff --git a/port/portclock.c b/port/portclock.c index f44231f61389802c17a5c24a100aece5494b63bb..7d261aa7793cee61c2fe06cfe8595ff160f3025e 100644 --- a/port/portclock.c +++ b/port/portclock.c @@ -69,18 +69,18 @@ portclock(Ureg *ur) unlock(&clock0lock); } - if(up == 0 || up->state != Running){ - m->inclockintr = 0; + m->inclockintr = 0; + if(up == 0 || up->state != Running) return; - } - if(anyready()) + if(anyready()){ sched(); + splhi(); + } /* user profiling clock */ if(userureg(ur)) { (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); segclock(ur->pc); } - m->inclockintr = 0; }