diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-01-25 18:37:28 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-01-25 18:37:28 +0100 |
commit | 60bb408acca3b48b17f9158132849b894ad9f234 (patch) | |
tree | a1d36dcad51a6d47d32437a8dde5a1353ba89877 /sys/src/9/ppc | |
parent | 6f80913ac72490cca7645b85b64de5ed52a7ce91 (diff) |
ppc: remove old duplicate of devtls.c
Diffstat (limited to 'sys/src/9/ppc')
-rw-r--r-- | sys/src/9/ppc/devtls.c | 2113 |
1 files changed, 0 insertions, 2113 deletions
diff --git a/sys/src/9/ppc/devtls.c b/sys/src/9/ppc/devtls.c deleted file mode 100644 index d333b10b9..000000000 --- a/sys/src/9/ppc/devtls.c +++ /dev/null @@ -1,2113 +0,0 @@ -/* - * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 - */ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" - -#include <libsec.h> - -typedef struct OneWay OneWay; -typedef struct Secret Secret; -typedef struct TlsRec TlsRec; -typedef struct TlsErrs TlsErrs; - -enum { - Statlen= 1024, /* max. length of status or stats message */ - /* buffer limits */ - MaxRecLen = 1<<14, /* max payload length of a record layer message */ - MaxCipherRecLen = MaxRecLen + 2048, - RecHdrLen = 5, - MaxMacLen = SHA1dlen, - - /* protocol versions we can accept */ - TLSVersion = 0x0301, - SSL3Version = 0x0300, - ProtocolVersion = 0x0301, /* maximum version we speak */ - MinProtoVersion = 0x0300, /* limits on version we accept */ - MaxProtoVersion = 0x03ff, - - /* connection states */ - SHandshake = 1 << 0, /* doing handshake */ - SOpen = 1 << 1, /* application data can be sent */ - SRClose = 1 << 2, /* remote side has closed down */ - SLClose = 1 << 3, /* sent a close notify alert */ - SAlert = 1 << 5, /* sending or sent a fatal alert */ - SError = 1 << 6, /* some sort of error has occured */ - SClosed = 1 << 7, /* it is all over */ - - /* record types */ - RChangeCipherSpec = 20, - RAlert, - RHandshake, - RApplication, - - SSL2ClientHello = 1, - HSSL2ClientHello = 9, /* local convention; see tlshand.c */ - - /* alerts */ - 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 Secret -{ - char *encalg; /* name of encryption alg */ - char *hashalg; /* name of hash alg */ - int (*enc)(Secret*, uchar*, int); - int (*dec)(Secret*, uchar*, int); - int (*unpad)(uchar*, int, int); - DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); - int block; /* encryption block len, 0 if none */ - int maclen; - void *enckey; - uchar mackey[MaxMacLen]; -}; - -struct OneWay -{ - QLock io; /* locks io access */ - QLock seclock; /* locks secret paramaters */ - ulong seq; - Secret *sec; /* cipher in use */ - Secret *new; /* cipher waiting for enable */ -}; - -struct TlsRec -{ - Chan *c; /* io channel */ - int ref; /* serialized by tdlock for atomic destroy */ - int version; /* version of the protocol we are speaking */ - char verset; /* version has been set */ - char opened; /* opened command every issued? */ - char err[ERRMAX]; /* error message to return to handshake requests */ - vlong handin; /* bytes communicated by the record layer */ - vlong handout; - vlong datain; - vlong dataout; - - Lock statelk; - int state; - - /* record layer mac functions for different protocol versions */ - void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*); - - /* input side -- protected by in.io */ - OneWay in; - Block *processed; /* next bunch of application data */ - Block *unprocessed; /* data read from c but not parsed into records */ - - /* handshake queue */ - Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */ - int hqref; - Queue *handq; /* queue of handshake messages */ - Block *hprocessed; /* remainder of last block read from handq */ - QLock hqread; /* protects reads for hprocessed, handq */ - - /* output side */ - OneWay out; - - /* protections */ - char *user; - int perm; -}; - -struct TlsErrs{ - int err; - int sslerr; - int tlserr; - int fatal; - char *msg; -}; - -static TlsErrs tlserrs[] = { - {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"}, - {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"}, - {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"}, - {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"}, - {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"}, - {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"}, - {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security paramters"}, - {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"}, - {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"}, - {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"}, - {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"}, - {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"}, - {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"}, - {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"}, - {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"}, - {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"}, - {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"}, - {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"}, - {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"}, - {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"}, - {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"}, - {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"}, - {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"}, - {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"}, -}; - -enum -{ - /* max. open tls connections */ - MaxTlsDevs = 1024 -}; - -static Lock tdlock; -static int tdhiwat; -static int maxtlsdevs = 128; -static TlsRec **tlsdevs; -static char **trnames; -static char *encalgs; -static char *hashalgs; - -enum{ - Qtopdir = 1, /* top level directory */ - Qprotodir, - Qclonus, - Qencalgs, - Qhashalgs, - Qconvdir, /* directory for a conversation */ - Qdata, - Qctl, - Qhand, - Qstatus, - Qstats, -}; - -#define TYPE(x) ((x).path & 0xf) -#define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1)) -#define QID(c, y) (((c)<<5) | (y)) - -static void checkstate(TlsRec *, int, int); -static void ensure(TlsRec*, Block**, int); -static void consume(Block**, uchar*, int); -static Chan* buftochan(char*); -static void tlshangup(TlsRec*); -static void tlsError(TlsRec*, char *); -static void alertHand(TlsRec*, char *); -static TlsRec *newtls(Chan *c); -static TlsRec *mktlsrec(void); -static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); -static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); -static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); -static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); -static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); -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 tlsSetState(TlsRec *tr, int new, int old); -static void rcvAlert(TlsRec *tr, int err); -static void sendAlert(TlsRec *tr, int err); -static void rcvError(TlsRec *tr, int err, char *msg, ...); -static int rc4enc(Secret *sec, uchar *buf, int n); -static int des3enc(Secret *sec, uchar *buf, int n); -static int des3dec(Secret *sec, uchar *buf, int n); -static int noenc(Secret *sec, uchar *buf, int n); -static int sslunpad(uchar *buf, int n, int block); -static int tlsunpad(uchar *buf, int n, int block); -static void freeSec(Secret *sec); -static char *tlsstate(int s); - -#pragma varargck argpos rcvError 3 - -static char *tlsnames[] = { -[Qclonus] "clone", -[Qencalgs] "encalgs", -[Qhashalgs] "hashalgs", -[Qdata] "data", -[Qctl] "ctl", -[Qhand] "hand", -[Qstatus] "status", -[Qstats] "stats", -}; - -static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats }; - -static int -tlsgen(Chan *c, char*, Dirtab *, int, int s, Dir *dp) -{ - Qid q; - TlsRec *tr; - char *name, *nm; - int perm, t; - - q.vers = 0; - q.type = QTFILE; - - t = TYPE(c->qid); - switch(t) { - case Qtopdir: - if(s == DEVDOTDOT){ - q.path = QID(0, Qtopdir); - q.type = QTDIR; - devdir(c, q, "#a", 0, eve, 0555, dp); - return 1; - } - if(s > 0) - return -1; - q.path = QID(0, Qprotodir); - q.type = QTDIR; - devdir(c, q, "tls", 0, eve, 0555, dp); - return 1; - case Qprotodir: - if(s == DEVDOTDOT){ - q.path = QID(0, Qtopdir); - q.type = QTDIR; - devdir(c, q, ".", 0, eve, 0555, dp); - return 1; - } - if(s < 3){ - switch(s) { - default: - return -1; - case 0: - q.path = QID(0, Qclonus); - break; - case 1: - q.path = QID(0, Qencalgs); - break; - case 2: - q.path = QID(0, Qhashalgs); - break; - } - perm = 0444; - if(TYPE(q) == Qclonus) - perm = 0555; - devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp); - return 1; - } - s -= 3; - if(s >= tdhiwat) - return -1; - q.path = QID(s, Qconvdir); - q.type = QTDIR; - lock(&tdlock); - tr = tlsdevs[s]; - if(tr != nil) - nm = tr->user; - else - nm = eve; - if((name = trnames[s]) == nil) { - name = trnames[s] = smalloc(16); - sprint(name, "%d", s); - } - devdir(c, q, name, 0, nm, 0555, dp); - unlock(&tdlock); - return 1; - case Qconvdir: - if(s == DEVDOTDOT){ - q.path = QID(0, Qprotodir); - q.type = QTDIR; - devdir(c, q, "tls", 0, eve, 0555, dp); - return 1; - } - if(s < 0 || s >= nelem(convdir)) - return -1; - lock(&tdlock); - tr = tlsdevs[CONV(c->qid)]; - if(tr != nil){ - nm = tr->user; - perm = tr->perm; - }else{ - perm = 0; - nm = eve; - } - t = convdir[s]; - if(t == Qstatus || t == Qstats) - perm &= 0444; - q.path = QID(CONV(c->qid), t); - devdir(c, q, tlsnames[t], 0, nm, perm, dp); - unlock(&tdlock); - return 1; - case Qclonus: - case Qencalgs: - case Qhashalgs: - perm = 0444; - if(t == Qclonus) - perm = 0555; - devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp); - return 1; - default: - lock(&tdlock); - tr = tlsdevs[CONV(c->qid)]; - if(tr != nil){ - nm = tr->user; - perm = tr->perm; - }else{ - perm = 0; - nm = eve; - } - if(t == Qstatus || t == Qstats) - perm &= 0444; - devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp); - unlock(&tdlock); - return 1; - } - return -1; -} - -static Chan* -tlsattach(char *spec) -{ - Chan *c; - - c = devattach('a', spec); - c->qid.path = QID(0, Qtopdir); - c->qid.type = QTDIR; - c->qid.vers = 0; - return c; -} - -static Walkqid* -tlswalk(Chan *c, Chan *nc, char **name, int nname) -{ - return devwalk(c, nc, name, nname, nil, 0, tlsgen); -} - -static int -tlsstat(Chan *c, uchar *db, int n) -{ - return devstat(c, db, n, nil, 0, tlsgen); -} - -static Chan* -tlsopen(Chan *c, int omode) -{ - TlsRec *tr, **pp; - int t, perm; - - perm = 0; - omode &= 3; - switch(omode) { - case OREAD: - perm = 4; - break; - case OWRITE: - perm = 2; - break; - case ORDWR: - perm = 6; - break; - } - - t = TYPE(c->qid); - switch(t) { - default: - panic("tlsopen"); - case Qtopdir: - case Qprotodir: - case Qconvdir: - if(omode != OREAD) - error(Eperm); - break; - case Qclonus: - tr = newtls(c); - if(tr == nil) - error(Enodev); - break; - case Qctl: - case Qdata: - case Qhand: - case Qstatus: - case Qstats: - if((t == Qstatus || t == Qstats) && omode != OREAD) - error(Eperm); - if(waserror()) { - unlock(&tdlock); - nexterror(); - } - lock(&tdlock); - pp = &tlsdevs[CONV(c->qid)]; - tr = *pp; - if(tr == nil) - error("must open connection using clone"); - if((perm & (tr->perm>>6)) != perm - && (strcmp(up->user, tr->user) != 0 - || (perm & tr->perm) != perm)) - error(Eperm); - if(t == Qhand){ - if(waserror()){ - unlock(&tr->hqlock); - nexterror(); - } - lock(&tr->hqlock); - if(tr->handq != nil) - error(Einuse); - tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil); - if(tr->handq == nil) - error("can't allocate handshake queue"); - tr->hqref = 1; - unlock(&tr->hqlock); - poperror(); - } - tr->ref++; - unlock(&tdlock); - poperror(); - break; - case Qencalgs: - case Qhashalgs: - if(omode != OREAD) - error(Eperm); - break; - } - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - c->iounit = qiomaxatomic; - return c; -} - -static int -tlswstat(Chan *c, uchar *dp, int n) -{ - Dir *d; - TlsRec *tr; - int rv; - - d = nil; - if(waserror()){ - free(d); - unlock(&tdlock); - nexterror(); - } - - lock(&tdlock); - tr = tlsdevs[CONV(c->qid)]; - if(tr == nil) - error(Ebadusefd); - if(strcmp(tr->user, up->user) != 0) - error(Eperm); - - d = smalloc(n + sizeof *d); - rv = convM2D(dp, n, &d[0], (char*) &d[1]); - if(rv == 0) - error(Eshortstat); - if(!emptystr(d->uid)) - kstrdup(&tr->user, d->uid); - if(d->mode != ~0UL) - tr->perm = d->mode; - - free(d); - poperror(); - unlock(&tdlock); - - return rv; -} - -static void -dechandq(TlsRec *tr) -{ - lock(&tr->hqlock); - if(--tr->hqref == 0){ - if(tr->handq != nil){ - qfree(tr->handq); - tr->handq = nil; - } - if(tr->hprocessed != nil){ - freeb(tr->hprocessed); - tr->hprocessed = nil; - } - } - unlock(&tr->hqlock); -} - -static void -tlsclose(Chan *c) -{ - TlsRec *tr; - int t; - - t = TYPE(c->qid); - switch(t) { - case Qctl: - case Qdata: - case Qhand: - case Qstatus: - case Qstats: - if((c->flag & COPEN) == 0) - break; - - tr = tlsdevs[CONV(c->qid)]; - if(tr == nil) - break; - - if(t == Qhand) - dechandq(tr); - - lock(&tdlock); - if(--tr->ref > 0) { - unlock(&tdlock); - return; - } - tlsdevs[CONV(c->qid)] = nil; - unlock(&tdlock); - - if(tr->c != nil && !waserror()){ - checkstate(tr, 0, SOpen|SHandshake|SRClose); - sendAlert(tr, ECloseNotify); - poperror(); - } - tlshangup(tr); - if(tr->c != nil) - cclose(tr->c); - freeSec(tr->in.sec); - freeSec(tr->in.new); - freeSec(tr->out.sec); - freeSec(tr->out.new); - free(tr->user); - free(tr); - break; - } -} - -/* - * make sure we have at least 'n' bytes in list 'l' - */ -static void -ensure(TlsRec *s, Block **l, int n) -{ - int sofar, i; - Block *b, *bl; - - sofar = 0; - for(b = *l; b; b = b->next){ - sofar += BLEN(b); - if(sofar >= n) - return; - l = &b->next; - } - - while(sofar < n){ - bl = devtab[s->c->type]->bread(s->c, MaxCipherRecLen + RecHdrLen, 0); - if(bl == 0) - error(Ehungup); - *l = bl; - i = 0; - for(b = bl; b; b = b->next){ - i += BLEN(b); - l = &b->next; - } - if(i == 0) - error(Ehungup); - sofar += i; - } -} - -/* - * copy 'n' bytes from 'l' into 'p' and free - * the bytes in 'l' - */ -static void -consume(Block **l, uchar *p, int n) -{ - Block *b; - int i; - - for(; *l && n > 0; n -= i){ - b = *l; - i = BLEN(b); - if(i > n) - i = n; - memmove(p, b->rp, i); - b->rp += i; - p += i; - if(BLEN(b) < 0) - panic("consume"); - if(BLEN(b)) - break; - *l = b->next; - freeb(b); - } -} - -/* - * give back n bytes - */ -static void -regurgitate(TlsRec *s, uchar *p, int n) -{ - Block *b; - - if(n <= 0) - return; - b = s->unprocessed; - if(s->unprocessed == nil || b->rp - b->base < n) { - b = allocb(n); - memmove(b->wp, p, n); - b->wp += n; - b->next = s->unprocessed; - s->unprocessed = b; - } else { - b->rp -= n; - memmove(b->rp, p, n); - } -} - -/* - * remove at most n bytes from the queue - */ -static Block* -qgrab(Block **l, int n) -{ - Block *bb, *b; - int i; - - b = *l; - if(BLEN(b) == n){ - *l = b->next; - b->next = nil; - return b; - } - - i = 0; - for(bb = b; bb != nil && i < n; bb = bb->next) - i += BLEN(bb); - if(i > n) - i = n; - - bb = allocb(i); - consume(l, bb->wp, i); - bb->wp += i; - return bb; -} - -static void -tlsclosed(TlsRec *tr, int new) -{ - lock(&tr->statelk); - if(tr->state == SOpen || tr->state == SHandshake) - tr->state = new; - else if((new | tr->state) == (SRClose|SLClose)) - tr->state = SClosed; - unlock(&tr->statelk); - alertHand(tr, "close notify"); -} - -/* - * read and process one tls record layer message - * must be called with tr->in.io held - * We can't let Eintrs lose data, since doing so will get - * us out of sync with the sender and break the reliablity - * of the channel. Eintr only happens during the reads in - * consume. Therefore we put back any bytes consumed before - * the last call to ensure. - */ -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, unpad_len; - - nconsumed = 0; - if(waserror()){ - if(strcmp(up->errstr, Eintr) == 0 && !waserror()){ - regurgitate(tr, header, nconsumed); - poperror(); - }else - tlsError(tr, "channel error"); - nexterror(); - } - ensure(tr, &tr->unprocessed, RecHdrLen); - consume(&tr->unprocessed, header, RecHdrLen); - nconsumed = RecHdrLen; - - if((tr->handin == 0) && (header[0] & 0x80)){ - /* Cope with an SSL3 ClientHello expressed in SSL2 record format. - This is sent by some clients that we must interoperate - with, such as Java's JSSE and Microsoft's Internet Explorer. */ - len = (get16(header) & ~0x8000) - 3; - type = header[2]; - ver = get16(header + 3); - if(type != SSL2ClientHello || len < 22) - rcvError(tr, EProtocolVersion, "invalid initial SSL2-like message"); - }else{ /* normal SSL3 record format */ - type = header[0]; - ver = get16(header+1); - len = get16(header+3); - } - if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion)) - rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'", - tr->version, tr->verset?"/set":"", len, type, ver, (char*)header); - if(len > MaxCipherRecLen || len < 0) - rcvError(tr, ERecordOverflow, "record message too long %d", len); - ensure(tr, &tr->unprocessed, len); - nconsumed = 0; - poperror(); - - /* - * If an Eintr happens after this, we'll get out of sync. - * Make sure nothing we call can sleep. - * Errors are ok, as they kill the connection. - * Luckily, allocb won't sleep, it'll just error out. - */ - b = nil; - if(waserror()){ - if(b != nil) - freeb(b); - tlsError(tr, "channel error"); - nexterror(); - } - b = qgrab(&tr->unprocessed, len); - - in = &tr->in; - if(waserror()){ - qunlock(&in->seclock); - nexterror(); - } - qlock(&in->seclock); - p = b->rp; - if(in->sec != nil) { - /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here - should look alike, including timing of the response. */ - unpad_len = (*in->sec->dec)(in->sec, p, len); - if(unpad_len > in->sec->maclen) - len = unpad_len - in->sec->maclen; - - /* update length */ - put16(header+3, len); - put64(seq, in->seq); - in->seq++; - (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac); - if(unpad_len <= in->sec->maclen || memcmp(hmac, p+len, in->sec->maclen) != 0) - rcvError(tr, EBadRecordMac, "record mac mismatch"); - b->wp = b->rp + len; - } - qunlock(&in->seclock); - poperror(); - if(len <= 0) - rcvError(tr, EDecodeError, "runt record message"); - - switch(type) { - default: - rcvError(tr, EIllegalParameter, "invalid record message 0x%x", type); - break; - case RChangeCipherSpec: - if(len != 1 || p[0] != 1) - rcvError(tr, EDecodeError, "invalid change cipher spec"); - qlock(&in->seclock); - if(in->new == nil){ - qunlock(&in->seclock); - rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec"); - } - freeSec(in->sec); - in->sec = in->new; - in->new = nil; - in->seq = 0; - qunlock(&in->seclock); - break; - case RAlert: - if(len != 2) - rcvError(tr, EDecodeError, "invalid alert"); - if(p[0] == 2) - rcvAlert(tr, p[1]); - if(p[0] != 1) - rcvError(tr, EIllegalParameter, "invalid alert fatal code"); - - /* - * propate non-fatal alerts to handshaker - */ - if(p[1] == ECloseNotify) { - tlsclosed(tr, SRClose); - if(tr->opened) - error("tls hungup"); - error("close notify"); - } - if(p[1] == ENoRenegotiation) - alertHand(tr, "no renegotiation"); - else if(p[1] == EUserCanceled) - alertHand(tr, "handshake canceled by user"); - else - rcvError(tr, EIllegalParameter, "invalid alert code"); - break; - case RHandshake: - /* - * don't worry about dropping the block - * qbwrite always queues even if flow controlled and interrupted. - * - * if there isn't any handshaker, ignore the request, - * but notify the other side we are doing so. - */ - lock(&tr->hqlock); - if(tr->handq != nil){ - tr->hqref++; - unlock(&tr->hqlock); - if(waserror()){ - dechandq(tr); - nexterror(); - } - b = padblock(b, 1); - *b->rp = RHandshake; - qbwrite(tr->handq, b); - b = nil; - poperror(); - dechandq(tr); - }else{ - unlock(&tr->hqlock); - if(tr->verset && tr->version != SSL3Version && !waserror()){ - sendAlert(tr, ENoRenegotiation); - poperror(); - } - } - break; - case SSL2ClientHello: - lock(&tr->hqlock); - if(tr->handq != nil){ - tr->hqref++; - unlock(&tr->hqlock); - if(waserror()){ - dechandq(tr); - nexterror(); - } - /* Pass the SSL2 format data, so that the handshake code can compute - the correct checksums. HSSL2ClientHello = HandshakeType 9 is - unused in RFC2246. */ - b = padblock(b, 8); - b->rp[0] = RHandshake; - b->rp[1] = HSSL2ClientHello; - put24(&b->rp[2], len+3); - b->rp[5] = SSL2ClientHello; - put16(&b->rp[6], ver); - qbwrite(tr->handq, b); - b = nil; - poperror(); - dechandq(tr); - }else{ - unlock(&tr->hqlock); - if(tr->verset && tr->version != SSL3Version && !waserror()){ - sendAlert(tr, ENoRenegotiation); - poperror(); - } - } - break; - case RApplication: - if(!tr->opened) - rcvError(tr, EUnexpectedMessage, "application message received before handshake completed"); - tr->processed = b; - b = nil; - break; - } - if(b != nil) - freeb(b); - poperror(); -} - -/* - * got a fatal alert message - */ -static void -rcvAlert(TlsRec *tr, int err) -{ - char *s; - int i; - - s = "unknown error"; - for(i=0; i < nelem(tlserrs); i++){ - if(tlserrs[i].err == err){ - s = tlserrs[i].msg; - break; - } - } - - tlsError(tr, s); - if(!tr->opened) - error(s); - error("tls error"); -} - -/* - * found an error while decoding the input stream - */ -static void -rcvError(TlsRec *tr, int err, char *fmt, ...) -{ - char msg[ERRMAX]; - va_list arg; - - va_start(arg, fmt); - vseprint(msg, msg+sizeof(msg), fmt, arg); - va_end(arg); - - sendAlert(tr, err); - - if(!tr->opened) - error(msg); - error("tls error"); -} - -/* - * make sure the next hand operation returns with a 'msg' error - */ -static void -alertHand(TlsRec *tr, char *msg) -{ - Block *b; - int n; - - lock(&tr->hqlock); - if(tr->handq == nil){ - unlock(&tr->hqlock); - return; - } - tr->hqref++; - unlock(&tr->hqlock); - - n = strlen(msg); - if(waserror()){ - dechandq(tr); - nexterror(); - } - b = allocb(n + 2); - *b->wp++ = RAlert; - memmove(b->wp, msg, n + 1); - b->wp += n + 1; - - qbwrite(tr->handq, b); - - poperror(); - dechandq(tr); -} - -static void -checkstate(TlsRec *tr, int ishand, int ok) -{ - int state; - - lock(&tr->statelk); - state = tr->state; - unlock(&tr->statelk); - if(state & ok) - return; - switch(state){ - case SHandshake: - case SOpen: - break; - case SError: - case SAlert: - if(ishand) - error(tr->err); - error("tls error"); - case SRClose: - case SLClose: - case SClosed: - error("tls hungup"); - } - error("tls improperly configured"); -} - -static Block* -tlsbread(Chan *c, long n, ulong offset) -{ - int ty; - Block *b; - TlsRec *volatile tr; - - ty = TYPE(c->qid); - switch(ty) { - default: - return devbread(c, n, offset); - case Qhand: - case Qdata: - break; - } - - tr = tlsdevs[CONV(c->qid)]; - if(tr == nil) - panic("tlsbread"); - - if(waserror()){ - qunlock(&tr->in.io); - nexterror(); - } - qlock(&tr->in.io); - if(ty == Qdata){ - checkstate(tr, 0, SOpen); - while(tr->processed == nil) - tlsrecread(tr); - - /* return at most what was asked for */ - b = qgrab(&tr->processed, n); - qunlock(&tr->in.io); - poperror(); - tr->datain += BLEN(b); - }else{ - checkstate(tr, 1, SOpen|SHandshake|SLClose); - - /* - * it's ok to look at state without the lock - * since it only protects reading records, - * and we have that tr->in.io held. - */ - while(!tr->opened && tr->hprocessed == nil && !qcanread(tr->handq)) - tlsrecread(tr); - - qunlock(&tr->in.io); - poperror(); - - if(waserror()){ - qunlock(&tr->hqread); - nexterror(); - } - qlock(&tr->hqread); - if(tr->hprocessed == nil){ - b = qbread(tr->handq, MaxRecLen + 1); - if(*b->rp++ == RAlert){ - strecpy(up->errstr, up->errstr+ERRMAX, (char*)b->rp); - freeb(b); - nexterror(); - } - tr->hprocessed = b; - } - b = qgrab(&tr->hprocessed, n); - poperror(); - qunlock(&tr->hqread); - tr->handin += BLEN(b); - } - - return b; -} - -static long -tlsread(Chan *c, void *a, long n, vlong off) -{ - Block *volatile b; - Block *nb; - uchar *va; - int i, ty; - char *buf, *s, *e; - ulong offset = off; - TlsRec * tr; - - if(c->qid.type & QTDIR) - return devdirread(c, a, n, 0, 0, tlsgen); - - tr = tlsdevs[CONV(c->qid)]; - ty = TYPE(c->qid); - switch(ty) { - default: - error(Ebadusefd); - case Qstatus: - buf = smalloc(Statlen); - qlock(&tr->in.seclock); - qlock(&tr->out.seclock); - s = buf; - e = buf + Statlen; - s = seprint(s, e, "State: %s\n", tlsstate(tr->state)); - s = seprint(s, e, "Version: 0x%x\n", tr->version); - if(tr->in.sec != nil) - s = seprint(s, e, "EncIn: %s\nHashIn: %s\n", tr->in.sec->encalg, tr->in.sec->hashalg); - if(tr->in.new != nil) - s = seprint(s, e, "NewEncIn: %s\nNewHashIn: %s\n", tr->in.new->encalg, tr->in.new->hashalg); - if(tr->out.sec != nil) - s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg); - if(tr->out.new != nil) - seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg); - qunlock(&tr->in.seclock); - qunlock(&tr->out.seclock); - n = readstr(offset, a, n, buf); - free(buf); - return n; - case Qstats: - buf = smalloc(Statlen); - s = buf; - e = buf + Statlen; - s = seprint(s, e, "DataIn: %lld\n", tr->datain); - s = seprint(s, e, "DataOut: %lld\n", tr->dataout); - s = seprint(s, e, "HandIn: %lld\n", tr->handin); - seprint(s, e, "HandOut: %lld\n", tr->handout); - n = readstr(offset, a, n, buf); - free(buf); - return n; - case Qctl: - buf = smalloc(Statlen); - snprint(buf, Statlen, "%llud", CONV(c->qid)); - n = readstr(offset, a, n, buf); - free(buf); - return n; - case Qdata: - case Qhand: - b = tlsbread(c, n, offset); - break; - case Qencalgs: - return readstr(offset, a, n, encalgs); - case Qhashalgs: - return readstr(offset, a, n, hashalgs); - } - - if(waserror()){ - freeblist(b); - nexterror(); - } - - n = 0; - va = a; - for(nb = b; nb; nb = nb->next){ - i = BLEN(nb); - memmove(va+n, nb->rp, i); - n += i; - } - - freeblist(b); - poperror(); - - return n; -} - -/* - * write a block in tls records - */ -static void -tlsrecwrite(TlsRec *tr, int type, Block *b) -{ - Block *volatile bb; - Block *nb; - uchar *p, seq[8]; - OneWay *volatile out; - int n, maclen, pad, ok; - - out = &tr->out; - bb = b; - if(waserror()){ - qunlock(&out->io); - if(bb != nil) - freeb(bb); - nexterror(); - } - qlock(&out->io); - - ok = SHandshake|SOpen|SRClose; - if(type == RAlert) - ok |= SAlert; - while(bb != nil){ - checkstate(tr, type != RApplication, ok); - - /* - * get at most one maximal record's input, - * with padding on the front for header and - * back for mac and maximal block padding. - */ - if(waserror()){ - qunlock(&out->seclock); - nexterror(); - } - qlock(&out->seclock); - maclen = 0; - pad = 0; - if(out->sec != nil){ - maclen = out->sec->maclen; - pad = maclen + out->sec->block; - } - n = BLEN(bb); - if(n > MaxRecLen){ - n = MaxRecLen; - nb = allocb(n + pad + RecHdrLen); - memmove(nb->wp + RecHdrLen, bb->rp, n); - bb->rp += n; - }else{ - /* - * carefully reuse bb so it will get freed if we're out of memory - */ - bb = padblock(bb, RecHdrLen); - if(pad) - nb = padblock(bb, -pad); - else - nb = bb; - bb = nil; - } - - p = nb->rp; - p[0] = type; - put16(p+1, tr->version); - put16(p+3, n); - - if(out->sec != nil){ - put64(seq, out->seq); - out->seq++; - (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n); - n += maclen; - - /* encrypt */ - n = (*out->sec->enc)(out->sec, p + RecHdrLen, n); - nb->wp = p + RecHdrLen + n; - - /* update length */ - put16(p+3, n); - } - if(type == RChangeCipherSpec){ - if(out->new == nil) - error("change cipher without a new cipher"); - freeSec(out->sec); - out->sec = out->new; - out->new = nil; - out->seq = 0; - } - qunlock(&out->seclock); - poperror(); - - /* - * if bwrite error's, we assume the block is queued. - * if not, we're out of sync with the receiver and will not recover. - */ - if(waserror()){ - if(strcmp(up->errstr, "interrupted") != 0) - tlsError(tr, "channel error"); - nexterror(); - } - devtab[tr->c->type]->bwrite(tr->c, nb, 0); - poperror(); - } - qunlock(&out->io); - poperror(); -} - -static long -tlsbwrite(Chan *c, Block *b, ulong offset) -{ - int ty; - ulong n; - TlsRec *tr; - - n = BLEN(b); - - tr = tlsdevs[CONV(c->qid)]; - if(tr == nil) - panic("tlsbread"); - - ty = TYPE(c->qid); - switch(ty) { - default: - return devbwrite(c, b, offset); - case Qhand: - tlsrecwrite(tr, RHandshake, b); - tr->handout += n; - break; - case Qdata: - checkstate(tr, 0, SOpen); - tlsrecwrite(tr, RApplication, b); - tr->dataout += n; - break; - } - - return n; -} - -typedef struct Hashalg Hashalg; -struct Hashalg -{ - char *name; - int maclen; - void (*initkey)(Hashalg *, int, Secret *, uchar*); -}; - -static void -initmd5key(Hashalg *ha, int version, Secret *s, uchar *p) -{ - s->maclen = ha->maclen; - if(version == SSL3Version) - s->mac = sslmac_md5; - else - s->mac = hmac_md5; - memmove(s->mackey, p, ha->maclen); -} - -static void -initclearmac(Hashalg *, int, Secret *s, uchar *) -{ - s->maclen = 0; - s->mac = nomac; -} - -static void -initsha1key(Hashalg *ha, int version, Secret *s, uchar *p) -{ - s->maclen = ha->maclen; - if(version == SSL3Version) - s->mac = sslmac_sha1; - else - s->mac = hmac_sha1; - memmove(s->mackey, p, ha->maclen); -} - -static Hashalg hashtab[] = -{ - { "clear", 0, initclearmac, }, - { "md5", MD5dlen, initmd5key, }, - { "sha1", SHA1dlen, initsha1key, }, - { 0 } -}; - -static Hashalg* -parsehashalg(char *p) -{ - Hashalg *ha; - - for(ha = hashtab; ha->name; ha++) - if(strcmp(p, ha->name) == 0) - return ha; - error("unsupported hash algorithm"); - return nil; -} - -typedef struct Encalg Encalg; -struct Encalg -{ - char *name; - int keylen; - int ivlen; - void (*initkey)(Encalg *ea, Secret *, uchar*, uchar*); -}; - -static void -initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *) -{ - s->enckey = smalloc(sizeof(RC4state)); - s->enc = rc4enc; - s->dec = rc4enc; - s->block = 0; - setupRC4state(s->enckey, p, ea->keylen); -} - -static void -initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv) -{ - s->enckey = smalloc(sizeof(DES3state)); - s->enc = des3enc; - s->dec = des3dec; - s->block = 8; - setupDES3state(s->enckey, (uchar(*)[8])p, iv); -} - -static void -initclearenc(Encalg *, Secret *s, uchar *, uchar *) -{ - s->enc = noenc; - s->dec = noenc; - s->block = 0; -} - -static Encalg encrypttab[] = -{ - { "clear", 0, 0, initclearenc }, - { "rc4_128", 128/8, 0, initRC4key }, - { "3des_ede_cbc", 3 * 8, 8, initDES3key }, - { 0 } -}; - -static Encalg* -parseencalg(char *p) -{ - Encalg *ea; - - for(ea = encrypttab; ea->name; ea++) - if(strcmp(p, ea->name) == 0) - return ea; - error("unsupported encryption algorithm"); - return nil; -} - -static long -tlswrite(Chan *c, void *a, long n, vlong off) -{ - Encalg *ea; - Hashalg *ha; - TlsRec *volatile tr; - Secret *volatile tos, *volatile toc; - Block *volatile b; - Cmdbuf *volatile cb; - int m, ty; - char *p, *e; - uchar *volatile x; - ulong offset = off; - - tr = tlsdevs[CONV(c->qid)]; - if(tr == nil) - panic("tlswrite"); - - ty = TYPE(c->qid); - switch(ty){ - case Qdata: - case Qhand: - p = a; - e = p + n; - do{ - m = e - p; - if(m > MaxRecLen) - m = MaxRecLen; - - b = allocb(m); - if(waserror()){ - freeb(b); - nexterror(); - } - memmove(b->wp, p, m); - poperror(); - b->wp += m; - - tlsbwrite(c, b, offset); - - p += m; - }while(p < e); - return n; - case Qctl: - break; - default: - error(Ebadusefd); - return -1; - } - - cb = parsecmd(a, n); - if(waserror()){ - free(cb); - nexterror(); - } - if(cb->nf < 1) - error("short control request"); - - /* mutex with operations using what we're about to change */ - if(waserror()){ - qunlock(&tr->in.seclock); - qunlock(&tr->out.seclock); - nexterror(); - } - qlock(&tr->in.seclock); - qlock(&tr->out.seclock); - - if(strcmp(cb->f[0], "fd") == 0){ - if(cb->nf != 3) - error("usage: fd open-fd version"); - if(tr->c != nil) - error(Einuse); - m = strtol(cb->f[2], nil, 0); - if(m < MinProtoVersion || m > MaxProtoVersion) - error("unsupported version"); - tr->c = buftochan(cb->f[1]); - tr->version = m; - tlsSetState(tr, SHandshake, SClosed); - }else if(strcmp(cb->f[0], "version") == 0){ - if(cb->nf != 2) - error("usage: version vers"); - if(tr->c == nil) - error("must set fd before version"); - if(tr->verset) - error("version already set"); - m = strtol(cb->f[1], nil, 0); - if(m == SSL3Version) - tr->packMac = sslPackMac; - else if(m == TLSVersion) - tr->packMac = tlsPackMac; - else - error("unsupported version"); - tr->verset = 1; - tr->version = m; - }else if(strcmp(cb->f[0], "secret") == 0){ - if(cb->nf != 5) - error("usage: secret hashalg encalg isclient secretdata"); - if(tr->c == nil || !tr->verset) - error("must set fd and version before secrets"); - - if(tr->in.new != nil){ - freeSec(tr->in.new); - tr->in.new = nil; - } - if(tr->out.new != nil){ - freeSec(tr->out.new); - tr->out.new = nil; - } - - ha = parsehashalg(cb->f[1]); - ea = parseencalg(cb->f[2]); - - p = cb->f[4]; - m = (strlen(p)*3)/2; - x = smalloc(m); - tos = nil; - toc = nil; - if(waserror()){ - freeSec(tos); - freeSec(toc); - free(x); - nexterror(); - } - m = dec64(x, m, p, strlen(p)); - if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) - error("not enough secret data provided"); - - tos = smalloc(sizeof(Secret)); - toc = smalloc(sizeof(Secret)); - if(!ha->initkey || !ea->initkey) - error("misimplemented secret algorithm"); - (*ha->initkey)(ha, tr->version, tos, &x[0]); - (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]); - (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]); - (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]); - - if(!tos->mac || !tos->enc || !tos->dec - || !toc->mac || !toc->enc || !toc->dec) - error("missing algorithm implementations"); - if(strtol(cb->f[3], nil, 0) == 0){ - tr->in.new = tos; - tr->out.new = toc; - }else{ - tr->in.new = toc; - tr->out.new = tos; - } - if(tr->version == SSL3Version){ - toc->unpad = sslunpad; - tos->unpad = sslunpad; - }else{ - toc->unpad = tlsunpad; - tos->unpad = tlsunpad; - } - toc->encalg = ea->name; - toc->hashalg = ha->name; - tos->encalg = ea->name; - tos->hashalg = ha->name; - - free(x); - poperror(); - }else if(strcmp(cb->f[0], "changecipher") == 0){ - if(cb->nf != 1) - error("usage: changecipher"); - if(tr->out.new == nil) - error("can't change cipher spec without setting secret"); - - qunlock(&tr->in.seclock); - qunlock(&tr->out.seclock); - poperror(); - free(cb); - poperror(); - - /* - * the real work is done as the message is written - * so the stream is encrypted in sync. - */ - b = allocb(1); - *b->wp++ = 1; - tlsrecwrite(tr, RChangeCipherSpec, b); - return n; - }else if(strcmp(cb->f[0], "opened") == 0){ - if(cb->nf != 1) - error("usage: opened"); - if(tr->in.sec == nil || tr->out.sec == nil) - error("cipher must be configured before enabling data messages"); - lock(&tr->statelk); - if(tr->state != SHandshake && tr->state != SOpen){ - unlock(&tr->statelk); - error("can't enable data messages"); - } - tr->state = SOpen; - unlock(&tr->statelk); - tr->opened = 1; - }else if(strcmp(cb->f[0], "alert") == 0){ - if(cb->nf != 2) - error("usage: alert n"); - if(tr->c == nil) - error("must set fd before sending alerts"); - m = strtol(cb->f[1], nil, 0); - - qunlock(&tr->in.seclock); - qunlock(&tr->out.seclock); - poperror(); - free(cb); - poperror(); - - sendAlert(tr, m); - - if(m == ECloseNotify) - tlsclosed(tr, SLClose); - - return n; - } else - error(Ebadarg); - - qunlock(&tr->in.seclock); - qunlock(&tr->out.seclock); - poperror(); - free(cb); - poperror(); - - return n; -} - -static void -tlsinit(void) -{ - struct Encalg *e; - struct Hashalg *h; - int n; - char *cp; - - tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs); - trnames = smalloc((sizeof *trnames) * maxtlsdevs); - - n = 1; - for(e = encrypttab; e->name != nil; e++) - n += strlen(e->name) + 1; - cp = encalgs = smalloc(n); - for(e = encrypttab;;){ - strcpy(cp, e->name); - cp += strlen(e->name); - e++; - if(e->name == nil) - break; - *cp++ = ' '; - } - *cp = 0; - - n = 1; - for(h = hashtab; h->name != nil; h++) - n += strlen(h->name) + 1; - cp = hashalgs = smalloc(n); - for(h = hashtab;;){ - strcpy(cp, h->name); - cp += strlen(h->name); - h++; - if(h->name == nil) - break; - *cp++ = ' '; - } - *cp = 0; -} - -Dev tlsdevtab = { - 'a', - "tls", - - devreset, - tlsinit, - devshutdown, - tlsattach, - tlswalk, - tlsstat, - tlsopen, - devcreate, - tlsclose, - tlsread, - tlsbread, - tlswrite, - tlsbwrite, - devremove, - tlswstat, -}; - -/* get channel associated with an fd */ -static Chan* -buftochan(char *p) -{ - Chan *c; - int fd; - - if(p == 0) - error(Ebadarg); - fd = strtoul(p, 0, 0); - if(fd < 0) - error(Ebadarg); - c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ - return c; -} - -static void -sendAlert(TlsRec *tr, int err) -{ - Block *b; - int i, fatal; - char *msg; - - fatal = 1; - msg = "tls unknown alert"; - for(i=0; i < nelem(tlserrs); i++) { - if(tlserrs[i].err == err) { - msg = tlserrs[i].msg; - if(tr->version == SSL3Version) - err = tlserrs[i].sslerr; - else - err = tlserrs[i].tlserr; - fatal = tlserrs[i].fatal; - break; - } - } - - if(!waserror()){ - b = allocb(2); - *b->wp++ = fatal + 1; - *b->wp++ = err; - if(fatal) - tlsSetState(tr, SAlert, SOpen|SHandshake|SRClose); - tlsrecwrite(tr, RAlert, b); - poperror(); - } - if(fatal) - tlsError(tr, msg); -} - -static void -tlsError(TlsRec *tr, char *msg) -{ - int s; - - lock(&tr->statelk); - s = tr->state; - tr->state = SError; - if(s != SError){ - strncpy(tr->err, msg, ERRMAX - 1); - tr->err[ERRMAX - 1] = '\0'; - } - unlock(&tr->statelk); - if(s != SError) - alertHand(tr, msg); -} - -static void -tlsSetState(TlsRec *tr, int new, int old) -{ - lock(&tr->statelk); - if(tr->state & old) - tr->state = new; - unlock(&tr->statelk); -} - -/* hand up a digest connection */ -static void -tlshangup(TlsRec *tr) -{ - Block *b; - - qlock(&tr->in.io); - for(b = tr->processed; b; b = tr->processed){ - tr->processed = b->next; - freeb(b); - } - if(tr->unprocessed != nil){ - freeb(tr->unprocessed); - tr->unprocessed = nil; - } - qunlock(&tr->in.io); - - tlsSetState(tr, SClosed, ~0); -} - -static TlsRec* -newtls(Chan *ch) -{ - TlsRec **pp, **ep, **np; - char **nmp; - int t, newmax; - - if(waserror()) { - unlock(&tdlock); - nexterror(); - } - lock(&tdlock); - ep = &tlsdevs[maxtlsdevs]; - for(pp = tlsdevs; pp < ep; pp++) - if(*pp == nil) - break; - if(pp >= ep) { - if(maxtlsdevs >= MaxTlsDevs) { - unlock(&tdlock); - poperror(); - return nil; - } - newmax = 2 * maxtlsdevs; - if(newmax > MaxTlsDevs) - newmax = MaxTlsDevs; - np = smalloc(sizeof(TlsRec*) * newmax); - memmove(np, tlsdevs, sizeof(TlsRec*) * maxtlsdevs); - tlsdevs = np; - pp = &tlsdevs[maxtlsdevs]; - memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs)); - - nmp = smalloc(sizeof *nmp * newmax); - memmove(nmp, trnames, sizeof *nmp * maxtlsdevs); - trnames = nmp; - - maxtlsdevs = newmax; - } - *pp = mktlsrec(); - if(pp - tlsdevs >= tdhiwat) - tdhiwat++; - t = TYPE(ch->qid); - if(t == Qclonus) - t = Qctl; - ch->qid.path = QID(pp - tlsdevs, t); - ch->qid.vers = 0; - unlock(&tdlock); - poperror(); - return *pp; -} - -static TlsRec * -mktlsrec(void) -{ - TlsRec *tr; - - tr = mallocz(sizeof(*tr), 1); - if(tr == nil) - error(Enomem); - tr->state = SClosed; - tr->ref = 1; - kstrdup(&tr->user, up->user); - tr->perm = 0660; - return tr; -} - -static char* -tlsstate(int s) -{ - switch(s){ - case SHandshake: - return "Handshaking"; - case SOpen: - return "Established"; - case SRClose: - return "RemoteClosed"; - case SLClose: - return "LocalClosed"; - case SAlert: - return "Alerting"; - case SError: - return "Errored"; - case SClosed: - return "Closed"; - } - return "Unknown"; -} - -static void -freeSec(Secret *s) -{ - if(s != nil){ - free(s->enckey); - free(s); - } -} - -static int -noenc(Secret *, uchar *, int n) -{ - return n; -} - -static int -rc4enc(Secret *sec, uchar *buf, int n) -{ - rc4(sec->enckey, buf, n); - return n; -} - -static int -tlsunpad(uchar *buf, int n, int block) -{ - int pad, nn; - - pad = buf[n - 1]; - nn = n - 1 - pad; - if(nn <= 0 || n % block) - return -1; - while(--n > nn) - if(pad != buf[n - 1]) - return -1; - return nn; -} - -static int -sslunpad(uchar *buf, int n, int block) -{ - int pad, nn; - - pad = buf[n - 1]; - nn = n - 1 - pad; - if(nn <= 0 || n % block) - return -1; - return nn; -} - -static int -blockpad(uchar *buf, int n, int block) -{ - int pad, nn; - - nn = n + block; - nn -= nn % block; - pad = nn - (n + 1); - while(n < nn) - buf[n++] = pad; - return nn; -} - -static int -des3enc(Secret *sec, uchar *buf, int n) -{ - n = blockpad(buf, n, 8); - des3CBCencrypt(buf, n, sec->enckey); - return n; -} - -static int -des3dec(Secret *sec, uchar *buf, int n) -{ - des3CBCdecrypt(buf, n, sec->enckey); - return (*sec->unpad)(buf, n, 8); -} -static DigestState* -nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *) -{ - return nil; -} - -/* - * sslmac: mac calculations for ssl 3.0 only; tls 1.0 uses the standard hmac. - */ -static DigestState* -sslmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, - DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen, int padlen) -{ - int i; - uchar pad[48], innerdigest[20]; - - if(xlen > sizeof(innerdigest) - || padlen > sizeof(pad)) - return nil; - - if(klen>64) - return nil; - - /* first time through */ - if(s == nil){ - for(i=0; i<padlen; i++) - pad[i] = 0x36; - s = (*x)(key, klen, nil, nil); - s = (*x)(pad, padlen, nil, s); - if(s == nil) - return nil; - } - - s = (*x)(p, len, nil, s); - if(digest == nil) - return s; - - /* last time through */ - for(i=0; i<padlen; i++) - pad[i] = 0x5c; - (*x)(nil, 0, innerdigest, s); - s = (*x)(key, klen, nil, nil); - s = (*x)(pad, padlen, nil, s); - (*x)(innerdigest, xlen, digest, s); - return nil; -} - -static DigestState* -sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s) -{ - return sslmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen, 40); -} - -static DigestState* -sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s) -{ - return sslmac_x(p, len, key, klen, digest, s, md5, MD5dlen, 48); -} - -static void -sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac) -{ - DigestState *s; - uchar buf[11]; - - memmove(buf, seq, 8); - buf[8] = header[0]; - buf[9] = header[3]; - buf[10] = header[4]; - - s = (*sec->mac)(buf, 11, mackey, sec->maclen, 0, 0); - (*sec->mac)(body, len, mackey, sec->maclen, mac, s); -} - -static void -tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac) -{ - DigestState *s; - uchar buf[13]; - - memmove(buf, seq, 8); - memmove(&buf[8], header, 5); - - s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0); - (*sec->mac)(body, len, mackey, sec->maclen, mac, s); -} - -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 -put24(uchar *p, int x) -{ - p[0] = x>>16; - p[1] = x>>8; - p[2] = 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]; -} |