19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0
39a747e4fSDavid du Colombier */
49a747e4fSDavid du Colombier #include "u.h"
59a747e4fSDavid du Colombier #include "../port/lib.h"
69a747e4fSDavid du Colombier #include "mem.h"
79a747e4fSDavid du Colombier #include "dat.h"
89a747e4fSDavid du Colombier #include "fns.h"
99a747e4fSDavid du Colombier #include "../port/error.h"
109a747e4fSDavid du Colombier
119a747e4fSDavid du Colombier #include <libsec.h>
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier typedef struct OneWay OneWay;
149a747e4fSDavid du Colombier typedef struct Secret Secret;
159a747e4fSDavid du Colombier typedef struct TlsRec TlsRec;
169a747e4fSDavid du Colombier typedef struct TlsErrs TlsErrs;
179a747e4fSDavid du Colombier
189a747e4fSDavid du Colombier enum {
199a747e4fSDavid du Colombier Statlen= 1024, /* max. length of status or stats message */
209a747e4fSDavid du Colombier /* buffer limits */
219a747e4fSDavid du Colombier MaxRecLen = 1<<14, /* max payload length of a record layer message */
229a747e4fSDavid du Colombier MaxCipherRecLen = MaxRecLen + 2048,
239a747e4fSDavid du Colombier RecHdrLen = 5,
249a747e4fSDavid du Colombier MaxMacLen = SHA1dlen,
259a747e4fSDavid du Colombier
269a747e4fSDavid du Colombier /* protocol versions we can accept */
279a747e4fSDavid du Colombier TLSVersion = 0x0301,
289a747e4fSDavid du Colombier SSL3Version = 0x0300,
299a747e4fSDavid du Colombier ProtocolVersion = 0x0301, /* maximum version we speak */
309a747e4fSDavid du Colombier MinProtoVersion = 0x0300, /* limits on version we accept */
319a747e4fSDavid du Colombier MaxProtoVersion = 0x03ff,
329a747e4fSDavid du Colombier
339a747e4fSDavid du Colombier /* connection states */
349a747e4fSDavid du Colombier SHandshake = 1 << 0, /* doing handshake */
359a747e4fSDavid du Colombier SOpen = 1 << 1, /* application data can be sent */
369a747e4fSDavid du Colombier SRClose = 1 << 2, /* remote side has closed down */
379a747e4fSDavid du Colombier SLClose = 1 << 3, /* sent a close notify alert */
389a747e4fSDavid du Colombier SAlert = 1 << 5, /* sending or sent a fatal alert */
399a747e4fSDavid du Colombier SError = 1 << 6, /* some sort of error has occured */
409a747e4fSDavid du Colombier SClosed = 1 << 7, /* it is all over */
419a747e4fSDavid du Colombier
429a747e4fSDavid du Colombier /* record types */
439a747e4fSDavid du Colombier RChangeCipherSpec = 20,
449a747e4fSDavid du Colombier RAlert,
459a747e4fSDavid du Colombier RHandshake,
469a747e4fSDavid du Colombier RApplication,
479a747e4fSDavid du Colombier
489a747e4fSDavid du Colombier SSL2ClientHello = 1,
499a747e4fSDavid du Colombier HSSL2ClientHello = 9, /* local convention; see tlshand.c */
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier /* alerts */
529a747e4fSDavid du Colombier ECloseNotify = 0,
539a747e4fSDavid du Colombier EUnexpectedMessage = 10,
549a747e4fSDavid du Colombier EBadRecordMac = 20,
559a747e4fSDavid du Colombier EDecryptionFailed = 21,
569a747e4fSDavid du Colombier ERecordOverflow = 22,
579a747e4fSDavid du Colombier EDecompressionFailure = 30,
589a747e4fSDavid du Colombier EHandshakeFailure = 40,
599a747e4fSDavid du Colombier ENoCertificate = 41,
609a747e4fSDavid du Colombier EBadCertificate = 42,
619a747e4fSDavid du Colombier EUnsupportedCertificate = 43,
629a747e4fSDavid du Colombier ECertificateRevoked = 44,
639a747e4fSDavid du Colombier ECertificateExpired = 45,
649a747e4fSDavid du Colombier ECertificateUnknown = 46,
659a747e4fSDavid du Colombier EIllegalParameter = 47,
669a747e4fSDavid du Colombier EUnknownCa = 48,
679a747e4fSDavid du Colombier EAccessDenied = 49,
689a747e4fSDavid du Colombier EDecodeError = 50,
699a747e4fSDavid du Colombier EDecryptError = 51,
709a747e4fSDavid du Colombier EExportRestriction = 60,
719a747e4fSDavid du Colombier EProtocolVersion = 70,
729a747e4fSDavid du Colombier EInsufficientSecurity = 71,
739a747e4fSDavid du Colombier EInternalError = 80,
749a747e4fSDavid du Colombier EUserCanceled = 90,
759a747e4fSDavid du Colombier ENoRenegotiation = 100,
769a747e4fSDavid du Colombier
779a747e4fSDavid du Colombier EMAX = 256
789a747e4fSDavid du Colombier };
799a747e4fSDavid du Colombier
809a747e4fSDavid du Colombier struct Secret
819a747e4fSDavid du Colombier {
829a747e4fSDavid du Colombier char *encalg; /* name of encryption alg */
839a747e4fSDavid du Colombier char *hashalg; /* name of hash alg */
849a747e4fSDavid du Colombier int (*enc)(Secret*, uchar*, int);
859a747e4fSDavid du Colombier int (*dec)(Secret*, uchar*, int);
869a747e4fSDavid du Colombier int (*unpad)(uchar*, int, int);
879a747e4fSDavid du Colombier DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
889a747e4fSDavid du Colombier int block; /* encryption block len, 0 if none */
899a747e4fSDavid du Colombier int maclen;
909a747e4fSDavid du Colombier void *enckey;
919a747e4fSDavid du Colombier uchar mackey[MaxMacLen];
929a747e4fSDavid du Colombier };
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier struct OneWay
959a747e4fSDavid du Colombier {
969a747e4fSDavid du Colombier QLock io; /* locks io access */
979a747e4fSDavid du Colombier QLock seclock; /* locks secret paramaters */
989a747e4fSDavid du Colombier ulong seq;
999a747e4fSDavid du Colombier Secret *sec; /* cipher in use */
1009a747e4fSDavid du Colombier Secret *new; /* cipher waiting for enable */
1019a747e4fSDavid du Colombier };
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier struct TlsRec
1049a747e4fSDavid du Colombier {
1059a747e4fSDavid du Colombier Chan *c; /* io channel */
1069a747e4fSDavid du Colombier int ref; /* serialized by tdlock for atomic destroy */
1079a747e4fSDavid du Colombier int version; /* version of the protocol we are speaking */
1089a747e4fSDavid du Colombier char verset; /* version has been set */
1099a747e4fSDavid du Colombier char opened; /* opened command every issued? */
1109a747e4fSDavid du Colombier char err[ERRMAX]; /* error message to return to handshake requests */
1119a747e4fSDavid du Colombier vlong handin; /* bytes communicated by the record layer */
1129a747e4fSDavid du Colombier vlong handout;
1139a747e4fSDavid du Colombier vlong datain;
1149a747e4fSDavid du Colombier vlong dataout;
1159a747e4fSDavid du Colombier
1169a747e4fSDavid du Colombier Lock statelk;
1179a747e4fSDavid du Colombier int state;
1183751babcSDavid du Colombier int debug;
1199a747e4fSDavid du Colombier
1209a747e4fSDavid du Colombier /* record layer mac functions for different protocol versions */
1219a747e4fSDavid du Colombier void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*);
1229a747e4fSDavid du Colombier
1239a747e4fSDavid du Colombier /* input side -- protected by in.io */
1249a747e4fSDavid du Colombier OneWay in;
1259a747e4fSDavid du Colombier Block *processed; /* next bunch of application data */
1269a747e4fSDavid du Colombier Block *unprocessed; /* data read from c but not parsed into records */
1279a747e4fSDavid du Colombier
1289a747e4fSDavid du Colombier /* handshake queue */
1299a747e4fSDavid du Colombier Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */
1309a747e4fSDavid du Colombier int hqref;
1319a747e4fSDavid du Colombier Queue *handq; /* queue of handshake messages */
1329a747e4fSDavid du Colombier Block *hprocessed; /* remainder of last block read from handq */
1339a747e4fSDavid du Colombier QLock hqread; /* protects reads for hprocessed, handq */
1349a747e4fSDavid du Colombier
1359a747e4fSDavid du Colombier /* output side */
1369a747e4fSDavid du Colombier OneWay out;
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier /* protections */
1399a747e4fSDavid du Colombier char *user;
1409a747e4fSDavid du Colombier int perm;
1419a747e4fSDavid du Colombier };
1429a747e4fSDavid du Colombier
1439a747e4fSDavid du Colombier struct TlsErrs{
1449a747e4fSDavid du Colombier int err;
1459a747e4fSDavid du Colombier int sslerr;
1469a747e4fSDavid du Colombier int tlserr;
1479a747e4fSDavid du Colombier int fatal;
1489a747e4fSDavid du Colombier char *msg;
1499a747e4fSDavid du Colombier };
1509a747e4fSDavid du Colombier
1519a747e4fSDavid du Colombier static TlsErrs tlserrs[] = {
1529a747e4fSDavid du Colombier {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"},
1539a747e4fSDavid du Colombier {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"},
1549a747e4fSDavid du Colombier {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"},
1559a747e4fSDavid du Colombier {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"},
1569a747e4fSDavid du Colombier {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"},
1579a747e4fSDavid du Colombier {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"},
158f0ed0fb6SDavid du Colombier {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security parameters"},
1599a747e4fSDavid du Colombier {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"},
1609a747e4fSDavid du Colombier {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"},
1619a747e4fSDavid du Colombier {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"},
1629a747e4fSDavid du Colombier {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"},
1639a747e4fSDavid du Colombier {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"},
1649a747e4fSDavid du Colombier {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"},
1659a747e4fSDavid du Colombier {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"},
1669a747e4fSDavid du Colombier {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"},
1679a747e4fSDavid du Colombier {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"},
1689a747e4fSDavid du Colombier {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"},
1699a747e4fSDavid du Colombier {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"},
1709a747e4fSDavid du Colombier {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"},
1719a747e4fSDavid du Colombier {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"},
1729a747e4fSDavid du Colombier {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"},
1739a747e4fSDavid du Colombier {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"},
1749a747e4fSDavid du Colombier {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"},
1759a747e4fSDavid du Colombier {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"},
1769a747e4fSDavid du Colombier };
1779a747e4fSDavid du Colombier
1789a747e4fSDavid du Colombier enum
1799a747e4fSDavid du Colombier {
1809a747e4fSDavid du Colombier /* max. open tls connections */
1819a747e4fSDavid du Colombier MaxTlsDevs = 1024
1829a747e4fSDavid du Colombier };
1839a747e4fSDavid du Colombier
1849a747e4fSDavid du Colombier static Lock tdlock;
1859a747e4fSDavid du Colombier static int tdhiwat;
1869a747e4fSDavid du Colombier static int maxtlsdevs = 128;
1879a747e4fSDavid du Colombier static TlsRec **tlsdevs;
1889a747e4fSDavid du Colombier static char **trnames;
1899a747e4fSDavid du Colombier static char *encalgs;
1909a747e4fSDavid du Colombier static char *hashalgs;
1919a747e4fSDavid du Colombier
1929a747e4fSDavid du Colombier enum{
1939a747e4fSDavid du Colombier Qtopdir = 1, /* top level directory */
1949a747e4fSDavid du Colombier Qprotodir,
1959a747e4fSDavid du Colombier Qclonus,
1969a747e4fSDavid du Colombier Qencalgs,
1979a747e4fSDavid du Colombier Qhashalgs,
1989a747e4fSDavid du Colombier Qconvdir, /* directory for a conversation */
1999a747e4fSDavid du Colombier Qdata,
2009a747e4fSDavid du Colombier Qctl,
2019a747e4fSDavid du Colombier Qhand,
2029a747e4fSDavid du Colombier Qstatus,
2039a747e4fSDavid du Colombier Qstats,
2049a747e4fSDavid du Colombier };
2059a747e4fSDavid du Colombier
2069a747e4fSDavid du Colombier #define TYPE(x) ((x).path & 0xf)
2079a747e4fSDavid du Colombier #define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1))
2089a747e4fSDavid du Colombier #define QID(c, y) (((c)<<5) | (y))
2099a747e4fSDavid du Colombier
2109a747e4fSDavid du Colombier static void checkstate(TlsRec *, int, int);
2119a747e4fSDavid du Colombier static void ensure(TlsRec*, Block**, int);
2129a747e4fSDavid du Colombier static void consume(Block**, uchar*, int);
2139a747e4fSDavid du Colombier static Chan* buftochan(char*);
2149a747e4fSDavid du Colombier static void tlshangup(TlsRec*);
2159a747e4fSDavid du Colombier static void tlsError(TlsRec*, char *);
2169a747e4fSDavid du Colombier static void alertHand(TlsRec*, char *);
2179a747e4fSDavid du Colombier static TlsRec *newtls(Chan *c);
2189a747e4fSDavid du Colombier static TlsRec *mktlsrec(void);
2199a747e4fSDavid du Colombier static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
2209a747e4fSDavid du Colombier static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
2219a747e4fSDavid du Colombier static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
2229a747e4fSDavid du Colombier static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
2239a747e4fSDavid du Colombier static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
2249a747e4fSDavid du Colombier static void put64(uchar *p, vlong x);
2259a747e4fSDavid du Colombier static void put32(uchar *p, u32int);
2269a747e4fSDavid du Colombier static void put24(uchar *p, int);
2279a747e4fSDavid du Colombier static void put16(uchar *p, int);
2289a747e4fSDavid du Colombier static u32int get32(uchar *p);
2299a747e4fSDavid du Colombier static int get16(uchar *p);
2309a747e4fSDavid du Colombier static void tlsSetState(TlsRec *tr, int new, int old);
2319a747e4fSDavid du Colombier static void rcvAlert(TlsRec *tr, int err);
2329a747e4fSDavid du Colombier static void sendAlert(TlsRec *tr, int err);
2339a747e4fSDavid du Colombier static void rcvError(TlsRec *tr, int err, char *msg, ...);
2349a747e4fSDavid du Colombier static int rc4enc(Secret *sec, uchar *buf, int n);
2359a747e4fSDavid du Colombier static int des3enc(Secret *sec, uchar *buf, int n);
2369a747e4fSDavid du Colombier static int des3dec(Secret *sec, uchar *buf, int n);
237ad6ca847SDavid du Colombier static int aesenc(Secret *sec, uchar *buf, int n);
238ad6ca847SDavid du Colombier static int aesdec(Secret *sec, uchar *buf, int n);
2399a747e4fSDavid du Colombier static int noenc(Secret *sec, uchar *buf, int n);
2409a747e4fSDavid du Colombier static int sslunpad(uchar *buf, int n, int block);
2419a747e4fSDavid du Colombier static int tlsunpad(uchar *buf, int n, int block);
2429a747e4fSDavid du Colombier static void freeSec(Secret *sec);
2439a747e4fSDavid du Colombier static char *tlsstate(int s);
2443751babcSDavid du Colombier static void pdump(int, void*, char*);
2459a747e4fSDavid du Colombier
2469a747e4fSDavid du Colombier #pragma varargck argpos rcvError 3
2479a747e4fSDavid du Colombier
2489a747e4fSDavid du Colombier static char *tlsnames[] = {
2499a747e4fSDavid du Colombier [Qclonus] "clone",
2509a747e4fSDavid du Colombier [Qencalgs] "encalgs",
2519a747e4fSDavid du Colombier [Qhashalgs] "hashalgs",
2529a747e4fSDavid du Colombier [Qdata] "data",
2539a747e4fSDavid du Colombier [Qctl] "ctl",
2549a747e4fSDavid du Colombier [Qhand] "hand",
2559a747e4fSDavid du Colombier [Qstatus] "status",
2569a747e4fSDavid du Colombier [Qstats] "stats",
2579a747e4fSDavid du Colombier };
2589a747e4fSDavid du Colombier
2599a747e4fSDavid du Colombier static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats };
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier static int
tlsgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)2629a747e4fSDavid du Colombier tlsgen(Chan *c, char*, Dirtab *, int, int s, Dir *dp)
2639a747e4fSDavid du Colombier {
2649a747e4fSDavid du Colombier Qid q;
2659a747e4fSDavid du Colombier TlsRec *tr;
2669a747e4fSDavid du Colombier char *name, *nm;
2679a747e4fSDavid du Colombier int perm, t;
2689a747e4fSDavid du Colombier
2699a747e4fSDavid du Colombier q.vers = 0;
2709a747e4fSDavid du Colombier q.type = QTFILE;
2719a747e4fSDavid du Colombier
2729a747e4fSDavid du Colombier t = TYPE(c->qid);
2739a747e4fSDavid du Colombier switch(t) {
2749a747e4fSDavid du Colombier case Qtopdir:
2759a747e4fSDavid du Colombier if(s == DEVDOTDOT){
2769a747e4fSDavid du Colombier q.path = QID(0, Qtopdir);
2779a747e4fSDavid du Colombier q.type = QTDIR;
2789a747e4fSDavid du Colombier devdir(c, q, "#a", 0, eve, 0555, dp);
2799a747e4fSDavid du Colombier return 1;
2809a747e4fSDavid du Colombier }
2819a747e4fSDavid du Colombier if(s > 0)
2829a747e4fSDavid du Colombier return -1;
2839a747e4fSDavid du Colombier q.path = QID(0, Qprotodir);
2849a747e4fSDavid du Colombier q.type = QTDIR;
2859a747e4fSDavid du Colombier devdir(c, q, "tls", 0, eve, 0555, dp);
2869a747e4fSDavid du Colombier return 1;
2879a747e4fSDavid du Colombier case Qprotodir:
2889a747e4fSDavid du Colombier if(s == DEVDOTDOT){
2899a747e4fSDavid du Colombier q.path = QID(0, Qtopdir);
2909a747e4fSDavid du Colombier q.type = QTDIR;
2919a747e4fSDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp);
2929a747e4fSDavid du Colombier return 1;
2939a747e4fSDavid du Colombier }
2949a747e4fSDavid du Colombier if(s < 3){
2959a747e4fSDavid du Colombier switch(s) {
2969a747e4fSDavid du Colombier default:
2979a747e4fSDavid du Colombier return -1;
2989a747e4fSDavid du Colombier case 0:
2999a747e4fSDavid du Colombier q.path = QID(0, Qclonus);
3009a747e4fSDavid du Colombier break;
3019a747e4fSDavid du Colombier case 1:
3029a747e4fSDavid du Colombier q.path = QID(0, Qencalgs);
3039a747e4fSDavid du Colombier break;
3049a747e4fSDavid du Colombier case 2:
3059a747e4fSDavid du Colombier q.path = QID(0, Qhashalgs);
3069a747e4fSDavid du Colombier break;
3079a747e4fSDavid du Colombier }
3089a747e4fSDavid du Colombier perm = 0444;
3099a747e4fSDavid du Colombier if(TYPE(q) == Qclonus)
3109a747e4fSDavid du Colombier perm = 0555;
3119a747e4fSDavid du Colombier devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp);
3129a747e4fSDavid du Colombier return 1;
3139a747e4fSDavid du Colombier }
3149a747e4fSDavid du Colombier s -= 3;
3159a747e4fSDavid du Colombier if(s >= tdhiwat)
3169a747e4fSDavid du Colombier return -1;
3179a747e4fSDavid du Colombier q.path = QID(s, Qconvdir);
3189a747e4fSDavid du Colombier q.type = QTDIR;
3199a747e4fSDavid du Colombier lock(&tdlock);
3209a747e4fSDavid du Colombier tr = tlsdevs[s];
3219a747e4fSDavid du Colombier if(tr != nil)
3229a747e4fSDavid du Colombier nm = tr->user;
3239a747e4fSDavid du Colombier else
3249a747e4fSDavid du Colombier nm = eve;
3259a747e4fSDavid du Colombier if((name = trnames[s]) == nil){
3269a747e4fSDavid du Colombier name = trnames[s] = smalloc(16);
327*4e3613abSDavid du Colombier snprint(name, 16, "%d", s);
3289a747e4fSDavid du Colombier }
3299a747e4fSDavid du Colombier devdir(c, q, name, 0, nm, 0555, dp);
3309a747e4fSDavid du Colombier unlock(&tdlock);
3319a747e4fSDavid du Colombier return 1;
3329a747e4fSDavid du Colombier case Qconvdir:
3339a747e4fSDavid du Colombier if(s == DEVDOTDOT){
3349a747e4fSDavid du Colombier q.path = QID(0, Qprotodir);
3359a747e4fSDavid du Colombier q.type = QTDIR;
3369a747e4fSDavid du Colombier devdir(c, q, "tls", 0, eve, 0555, dp);
3379a747e4fSDavid du Colombier return 1;
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier if(s < 0 || s >= nelem(convdir))
3409a747e4fSDavid du Colombier return -1;
3419a747e4fSDavid du Colombier lock(&tdlock);
3429a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
3439a747e4fSDavid du Colombier if(tr != nil){
3449a747e4fSDavid du Colombier nm = tr->user;
3459a747e4fSDavid du Colombier perm = tr->perm;
3469a747e4fSDavid du Colombier }else{
3479a747e4fSDavid du Colombier perm = 0;
3489a747e4fSDavid du Colombier nm = eve;
3499a747e4fSDavid du Colombier }
3509a747e4fSDavid du Colombier t = convdir[s];
3519a747e4fSDavid du Colombier if(t == Qstatus || t == Qstats)
3529a747e4fSDavid du Colombier perm &= 0444;
3539a747e4fSDavid du Colombier q.path = QID(CONV(c->qid), t);
3549a747e4fSDavid du Colombier devdir(c, q, tlsnames[t], 0, nm, perm, dp);
3559a747e4fSDavid du Colombier unlock(&tdlock);
3569a747e4fSDavid du Colombier return 1;
3579a747e4fSDavid du Colombier case Qclonus:
3589a747e4fSDavid du Colombier case Qencalgs:
3599a747e4fSDavid du Colombier case Qhashalgs:
3609a747e4fSDavid du Colombier perm = 0444;
3619a747e4fSDavid du Colombier if(t == Qclonus)
3629a747e4fSDavid du Colombier perm = 0555;
3639a747e4fSDavid du Colombier devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp);
3649a747e4fSDavid du Colombier return 1;
3659a747e4fSDavid du Colombier default:
3669a747e4fSDavid du Colombier lock(&tdlock);
3679a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
3689a747e4fSDavid du Colombier if(tr != nil){
3699a747e4fSDavid du Colombier nm = tr->user;
3709a747e4fSDavid du Colombier perm = tr->perm;
3719a747e4fSDavid du Colombier }else{
3729a747e4fSDavid du Colombier perm = 0;
3739a747e4fSDavid du Colombier nm = eve;
3749a747e4fSDavid du Colombier }
3759a747e4fSDavid du Colombier if(t == Qstatus || t == Qstats)
3769a747e4fSDavid du Colombier perm &= 0444;
3779a747e4fSDavid du Colombier devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp);
3789a747e4fSDavid du Colombier unlock(&tdlock);
3799a747e4fSDavid du Colombier return 1;
3809a747e4fSDavid du Colombier }
3819a747e4fSDavid du Colombier }
3829a747e4fSDavid du Colombier
3839a747e4fSDavid du Colombier static Chan*
tlsattach(char * spec)3849a747e4fSDavid du Colombier tlsattach(char *spec)
3859a747e4fSDavid du Colombier {
3869a747e4fSDavid du Colombier Chan *c;
3879a747e4fSDavid du Colombier
3889a747e4fSDavid du Colombier c = devattach('a', spec);
3899a747e4fSDavid du Colombier c->qid.path = QID(0, Qtopdir);
3909a747e4fSDavid du Colombier c->qid.type = QTDIR;
3919a747e4fSDavid du Colombier c->qid.vers = 0;
3929a747e4fSDavid du Colombier return c;
3939a747e4fSDavid du Colombier }
3949a747e4fSDavid du Colombier
3959a747e4fSDavid du Colombier static Walkqid*
tlswalk(Chan * c,Chan * nc,char ** name,int nname)3969a747e4fSDavid du Colombier tlswalk(Chan *c, Chan *nc, char **name, int nname)
3979a747e4fSDavid du Colombier {
3989a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, tlsgen);
3999a747e4fSDavid du Colombier }
4009a747e4fSDavid du Colombier
4019a747e4fSDavid du Colombier static int
tlsstat(Chan * c,uchar * db,int n)4029a747e4fSDavid du Colombier tlsstat(Chan *c, uchar *db, int n)
4039a747e4fSDavid du Colombier {
4049a747e4fSDavid du Colombier return devstat(c, db, n, nil, 0, tlsgen);
4059a747e4fSDavid du Colombier }
4069a747e4fSDavid du Colombier
4079a747e4fSDavid du Colombier static Chan*
tlsopen(Chan * c,int omode)4089a747e4fSDavid du Colombier tlsopen(Chan *c, int omode)
4099a747e4fSDavid du Colombier {
4109a747e4fSDavid du Colombier TlsRec *tr, **pp;
4119a747e4fSDavid du Colombier int t, perm;
4129a747e4fSDavid du Colombier
4139a747e4fSDavid du Colombier perm = 0;
4149a747e4fSDavid du Colombier omode &= 3;
4159a747e4fSDavid du Colombier switch(omode) {
4169a747e4fSDavid du Colombier case OREAD:
4179a747e4fSDavid du Colombier perm = 4;
4189a747e4fSDavid du Colombier break;
4199a747e4fSDavid du Colombier case OWRITE:
4209a747e4fSDavid du Colombier perm = 2;
4219a747e4fSDavid du Colombier break;
4229a747e4fSDavid du Colombier case ORDWR:
4239a747e4fSDavid du Colombier perm = 6;
4249a747e4fSDavid du Colombier break;
4259a747e4fSDavid du Colombier }
4269a747e4fSDavid du Colombier
4279a747e4fSDavid du Colombier t = TYPE(c->qid);
4289a747e4fSDavid du Colombier switch(t) {
4299a747e4fSDavid du Colombier default:
4309a747e4fSDavid du Colombier panic("tlsopen");
4319a747e4fSDavid du Colombier case Qtopdir:
4329a747e4fSDavid du Colombier case Qprotodir:
4339a747e4fSDavid du Colombier case Qconvdir:
4349a747e4fSDavid du Colombier if(omode != OREAD)
4359a747e4fSDavid du Colombier error(Eperm);
4369a747e4fSDavid du Colombier break;
4379a747e4fSDavid du Colombier case Qclonus:
4389a747e4fSDavid du Colombier tr = newtls(c);
4399a747e4fSDavid du Colombier if(tr == nil)
4409a747e4fSDavid du Colombier error(Enodev);
4419a747e4fSDavid du Colombier break;
4429a747e4fSDavid du Colombier case Qctl:
4439a747e4fSDavid du Colombier case Qdata:
4449a747e4fSDavid du Colombier case Qhand:
4459a747e4fSDavid du Colombier case Qstatus:
4469a747e4fSDavid du Colombier case Qstats:
4479a747e4fSDavid du Colombier if((t == Qstatus || t == Qstats) && omode != OREAD)
4489a747e4fSDavid du Colombier error(Eperm);
4499a747e4fSDavid du Colombier if(waserror()) {
4509a747e4fSDavid du Colombier unlock(&tdlock);
4519a747e4fSDavid du Colombier nexterror();
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier lock(&tdlock);
4549a747e4fSDavid du Colombier pp = &tlsdevs[CONV(c->qid)];
4559a747e4fSDavid du Colombier tr = *pp;
4569a747e4fSDavid du Colombier if(tr == nil)
4579a747e4fSDavid du Colombier error("must open connection using clone");
4589a747e4fSDavid du Colombier if((perm & (tr->perm>>6)) != perm
4599a747e4fSDavid du Colombier && (strcmp(up->user, tr->user) != 0
4609a747e4fSDavid du Colombier || (perm & tr->perm) != perm))
4619a747e4fSDavid du Colombier error(Eperm);
4629a747e4fSDavid du Colombier if(t == Qhand){
4639a747e4fSDavid du Colombier if(waserror()){
4649a747e4fSDavid du Colombier unlock(&tr->hqlock);
4659a747e4fSDavid du Colombier nexterror();
4669a747e4fSDavid du Colombier }
4679a747e4fSDavid du Colombier lock(&tr->hqlock);
4689a747e4fSDavid du Colombier if(tr->handq != nil)
4699a747e4fSDavid du Colombier error(Einuse);
4709a747e4fSDavid du Colombier tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil);
4719a747e4fSDavid du Colombier if(tr->handq == nil)
4728cd4f5a6SDavid du Colombier error("cannot allocate handshake queue");
4739a747e4fSDavid du Colombier tr->hqref = 1;
4749a747e4fSDavid du Colombier unlock(&tr->hqlock);
4759a747e4fSDavid du Colombier poperror();
4769a747e4fSDavid du Colombier }
4779a747e4fSDavid du Colombier tr->ref++;
4789a747e4fSDavid du Colombier unlock(&tdlock);
4799a747e4fSDavid du Colombier poperror();
4809a747e4fSDavid du Colombier break;
4819a747e4fSDavid du Colombier case Qencalgs:
4829a747e4fSDavid du Colombier case Qhashalgs:
4839a747e4fSDavid du Colombier if(omode != OREAD)
4849a747e4fSDavid du Colombier error(Eperm);
4859a747e4fSDavid du Colombier break;
4869a747e4fSDavid du Colombier }
4879a747e4fSDavid du Colombier c->mode = openmode(omode);
4889a747e4fSDavid du Colombier c->flag |= COPEN;
4899a747e4fSDavid du Colombier c->offset = 0;
4909a747e4fSDavid du Colombier c->iounit = qiomaxatomic;
4919a747e4fSDavid du Colombier return c;
4929a747e4fSDavid du Colombier }
4939a747e4fSDavid du Colombier
4949a747e4fSDavid du Colombier static int
tlswstat(Chan * c,uchar * dp,int n)4959a747e4fSDavid du Colombier tlswstat(Chan *c, uchar *dp, int n)
4969a747e4fSDavid du Colombier {
4979a747e4fSDavid du Colombier Dir *d;
4989a747e4fSDavid du Colombier TlsRec *tr;
4999a747e4fSDavid du Colombier int rv;
5009a747e4fSDavid du Colombier
5019a747e4fSDavid du Colombier d = nil;
5029a747e4fSDavid du Colombier if(waserror()){
5039a747e4fSDavid du Colombier free(d);
5049a747e4fSDavid du Colombier unlock(&tdlock);
5059a747e4fSDavid du Colombier nexterror();
5069a747e4fSDavid du Colombier }
5079a747e4fSDavid du Colombier
5089a747e4fSDavid du Colombier lock(&tdlock);
5099a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
5109a747e4fSDavid du Colombier if(tr == nil)
5119a747e4fSDavid du Colombier error(Ebadusefd);
5129a747e4fSDavid du Colombier if(strcmp(tr->user, up->user) != 0)
5139a747e4fSDavid du Colombier error(Eperm);
5149a747e4fSDavid du Colombier
5159a747e4fSDavid du Colombier d = smalloc(n + sizeof *d);
5169a747e4fSDavid du Colombier rv = convM2D(dp, n, &d[0], (char*) &d[1]);
5179a747e4fSDavid du Colombier if(rv == 0)
5189a747e4fSDavid du Colombier error(Eshortstat);
5199a747e4fSDavid du Colombier if(!emptystr(d->uid))
5209a747e4fSDavid du Colombier kstrdup(&tr->user, d->uid);
5219a747e4fSDavid du Colombier if(d->mode != ~0UL)
5229a747e4fSDavid du Colombier tr->perm = d->mode;
5239a747e4fSDavid du Colombier
5249a747e4fSDavid du Colombier free(d);
5259a747e4fSDavid du Colombier poperror();
5269a747e4fSDavid du Colombier unlock(&tdlock);
5279a747e4fSDavid du Colombier
5289a747e4fSDavid du Colombier return rv;
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier
5319a747e4fSDavid du Colombier static void
dechandq(TlsRec * tr)5329a747e4fSDavid du Colombier dechandq(TlsRec *tr)
5339a747e4fSDavid du Colombier {
5349a747e4fSDavid du Colombier lock(&tr->hqlock);
5359a747e4fSDavid du Colombier if(--tr->hqref == 0){
5369a747e4fSDavid du Colombier if(tr->handq != nil){
5379a747e4fSDavid du Colombier qfree(tr->handq);
5389a747e4fSDavid du Colombier tr->handq = nil;
5399a747e4fSDavid du Colombier }
5409a747e4fSDavid du Colombier if(tr->hprocessed != nil){
5419a747e4fSDavid du Colombier freeb(tr->hprocessed);
5429a747e4fSDavid du Colombier tr->hprocessed = nil;
5439a747e4fSDavid du Colombier }
5449a747e4fSDavid du Colombier }
5459a747e4fSDavid du Colombier unlock(&tr->hqlock);
5469a747e4fSDavid du Colombier }
5479a747e4fSDavid du Colombier
5489a747e4fSDavid du Colombier static void
tlsclose(Chan * c)5499a747e4fSDavid du Colombier tlsclose(Chan *c)
5509a747e4fSDavid du Colombier {
5519a747e4fSDavid du Colombier TlsRec *tr;
5529a747e4fSDavid du Colombier int t;
5539a747e4fSDavid du Colombier
5549a747e4fSDavid du Colombier t = TYPE(c->qid);
5559a747e4fSDavid du Colombier switch(t) {
5569a747e4fSDavid du Colombier case Qctl:
5579a747e4fSDavid du Colombier case Qdata:
5589a747e4fSDavid du Colombier case Qhand:
5599a747e4fSDavid du Colombier case Qstatus:
5609a747e4fSDavid du Colombier case Qstats:
5619a747e4fSDavid du Colombier if((c->flag & COPEN) == 0)
5629a747e4fSDavid du Colombier break;
5639a747e4fSDavid du Colombier
5649a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
5659a747e4fSDavid du Colombier if(tr == nil)
5669a747e4fSDavid du Colombier break;
5679a747e4fSDavid du Colombier
5689a747e4fSDavid du Colombier if(t == Qhand)
5699a747e4fSDavid du Colombier dechandq(tr);
5709a747e4fSDavid du Colombier
5719a747e4fSDavid du Colombier lock(&tdlock);
5729a747e4fSDavid du Colombier if(--tr->ref > 0) {
5739a747e4fSDavid du Colombier unlock(&tdlock);
5749a747e4fSDavid du Colombier return;
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier tlsdevs[CONV(c->qid)] = nil;
5779a747e4fSDavid du Colombier unlock(&tdlock);
5789a747e4fSDavid du Colombier
5799a747e4fSDavid du Colombier if(tr->c != nil && !waserror()){
5809a747e4fSDavid du Colombier checkstate(tr, 0, SOpen|SHandshake|SRClose);
5819a747e4fSDavid du Colombier sendAlert(tr, ECloseNotify);
5829a747e4fSDavid du Colombier poperror();
5839a747e4fSDavid du Colombier }
5849a747e4fSDavid du Colombier tlshangup(tr);
5859a747e4fSDavid du Colombier if(tr->c != nil)
5869a747e4fSDavid du Colombier cclose(tr->c);
5879a747e4fSDavid du Colombier freeSec(tr->in.sec);
5889a747e4fSDavid du Colombier freeSec(tr->in.new);
5899a747e4fSDavid du Colombier freeSec(tr->out.sec);
5909a747e4fSDavid du Colombier freeSec(tr->out.new);
5919a747e4fSDavid du Colombier free(tr->user);
5929a747e4fSDavid du Colombier free(tr);
5939a747e4fSDavid du Colombier break;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier }
5969a747e4fSDavid du Colombier
5979a747e4fSDavid du Colombier /*
5989a747e4fSDavid du Colombier * make sure we have at least 'n' bytes in list 'l'
5999a747e4fSDavid du Colombier */
6009a747e4fSDavid du Colombier static void
ensure(TlsRec * s,Block ** l,int n)6019a747e4fSDavid du Colombier ensure(TlsRec *s, Block **l, int n)
6029a747e4fSDavid du Colombier {
6039a747e4fSDavid du Colombier int sofar, i;
6049a747e4fSDavid du Colombier Block *b, *bl;
6059a747e4fSDavid du Colombier
6069a747e4fSDavid du Colombier sofar = 0;
6079a747e4fSDavid du Colombier for(b = *l; b; b = b->next){
6089a747e4fSDavid du Colombier sofar += BLEN(b);
6099a747e4fSDavid du Colombier if(sofar >= n)
6109a747e4fSDavid du Colombier return;
6119a747e4fSDavid du Colombier l = &b->next;
6129a747e4fSDavid du Colombier }
6139a747e4fSDavid du Colombier
6149a747e4fSDavid du Colombier while(sofar < n){
6159a747e4fSDavid du Colombier bl = devtab[s->c->type]->bread(s->c, MaxCipherRecLen + RecHdrLen, 0);
6169a747e4fSDavid du Colombier if(bl == 0)
6179a747e4fSDavid du Colombier error(Ehungup);
6189a747e4fSDavid du Colombier *l = bl;
6199a747e4fSDavid du Colombier i = 0;
6209a747e4fSDavid du Colombier for(b = bl; b; b = b->next){
6219a747e4fSDavid du Colombier i += BLEN(b);
6229a747e4fSDavid du Colombier l = &b->next;
6239a747e4fSDavid du Colombier }
6249a747e4fSDavid du Colombier if(i == 0)
6259a747e4fSDavid du Colombier error(Ehungup);
6269a747e4fSDavid du Colombier sofar += i;
6279a747e4fSDavid du Colombier }
6283751babcSDavid du Colombier if(s->debug) pprint("ensure read %d\n", sofar);
6299a747e4fSDavid du Colombier }
6309a747e4fSDavid du Colombier
6319a747e4fSDavid du Colombier /*
6329a747e4fSDavid du Colombier * copy 'n' bytes from 'l' into 'p' and free
6339a747e4fSDavid du Colombier * the bytes in 'l'
6349a747e4fSDavid du Colombier */
6359a747e4fSDavid du Colombier static void
consume(Block ** l,uchar * p,int n)6369a747e4fSDavid du Colombier consume(Block **l, uchar *p, int n)
6379a747e4fSDavid du Colombier {
6389a747e4fSDavid du Colombier Block *b;
6399a747e4fSDavid du Colombier int i;
6409a747e4fSDavid du Colombier
6419a747e4fSDavid du Colombier for(; *l && n > 0; n -= i){
6429a747e4fSDavid du Colombier b = *l;
6439a747e4fSDavid du Colombier i = BLEN(b);
6449a747e4fSDavid du Colombier if(i > n)
6459a747e4fSDavid du Colombier i = n;
6469a747e4fSDavid du Colombier memmove(p, b->rp, i);
6479a747e4fSDavid du Colombier b->rp += i;
6489a747e4fSDavid du Colombier p += i;
6499a747e4fSDavid du Colombier if(BLEN(b) < 0)
6509a747e4fSDavid du Colombier panic("consume");
6519a747e4fSDavid du Colombier if(BLEN(b))
6529a747e4fSDavid du Colombier break;
6539a747e4fSDavid du Colombier *l = b->next;
6549a747e4fSDavid du Colombier freeb(b);
6559a747e4fSDavid du Colombier }
6569a747e4fSDavid du Colombier }
6579a747e4fSDavid du Colombier
6589a747e4fSDavid du Colombier /*
6599a747e4fSDavid du Colombier * give back n bytes
6609a747e4fSDavid du Colombier */
6619a747e4fSDavid du Colombier static void
regurgitate(TlsRec * s,uchar * p,int n)6629a747e4fSDavid du Colombier regurgitate(TlsRec *s, uchar *p, int n)
6639a747e4fSDavid du Colombier {
6649a747e4fSDavid du Colombier Block *b;
6659a747e4fSDavid du Colombier
6669a747e4fSDavid du Colombier if(n <= 0)
6679a747e4fSDavid du Colombier return;
6689a747e4fSDavid du Colombier b = s->unprocessed;
6699a747e4fSDavid du Colombier if(s->unprocessed == nil || b->rp - b->base < n) {
6709a747e4fSDavid du Colombier b = allocb(n);
6719a747e4fSDavid du Colombier memmove(b->wp, p, n);
6729a747e4fSDavid du Colombier b->wp += n;
6739a747e4fSDavid du Colombier b->next = s->unprocessed;
6749a747e4fSDavid du Colombier s->unprocessed = b;
6759a747e4fSDavid du Colombier } else {
6769a747e4fSDavid du Colombier b->rp -= n;
6779a747e4fSDavid du Colombier memmove(b->rp, p, n);
6789a747e4fSDavid du Colombier }
6799a747e4fSDavid du Colombier }
6809a747e4fSDavid du Colombier
6819a747e4fSDavid du Colombier /*
6829a747e4fSDavid du Colombier * remove at most n bytes from the queue
6839a747e4fSDavid du Colombier */
6849a747e4fSDavid du Colombier static Block*
qgrab(Block ** l,int n)6859a747e4fSDavid du Colombier qgrab(Block **l, int n)
6869a747e4fSDavid du Colombier {
6879a747e4fSDavid du Colombier Block *bb, *b;
6889a747e4fSDavid du Colombier int i;
6899a747e4fSDavid du Colombier
6909a747e4fSDavid du Colombier b = *l;
6919a747e4fSDavid du Colombier if(BLEN(b) == n){
6929a747e4fSDavid du Colombier *l = b->next;
6939a747e4fSDavid du Colombier b->next = nil;
6949a747e4fSDavid du Colombier return b;
6959a747e4fSDavid du Colombier }
6969a747e4fSDavid du Colombier
6979a747e4fSDavid du Colombier i = 0;
6989a747e4fSDavid du Colombier for(bb = b; bb != nil && i < n; bb = bb->next)
6999a747e4fSDavid du Colombier i += BLEN(bb);
7009a747e4fSDavid du Colombier if(i > n)
7019a747e4fSDavid du Colombier i = n;
7029a747e4fSDavid du Colombier
7039a747e4fSDavid du Colombier bb = allocb(i);
7049a747e4fSDavid du Colombier consume(l, bb->wp, i);
7059a747e4fSDavid du Colombier bb->wp += i;
7069a747e4fSDavid du Colombier return bb;
7079a747e4fSDavid du Colombier }
7089a747e4fSDavid du Colombier
7099a747e4fSDavid du Colombier static void
tlsclosed(TlsRec * tr,int new)7109a747e4fSDavid du Colombier tlsclosed(TlsRec *tr, int new)
7119a747e4fSDavid du Colombier {
7129a747e4fSDavid du Colombier lock(&tr->statelk);
7139a747e4fSDavid du Colombier if(tr->state == SOpen || tr->state == SHandshake)
7149a747e4fSDavid du Colombier tr->state = new;
7159a747e4fSDavid du Colombier else if((new | tr->state) == (SRClose|SLClose))
7169a747e4fSDavid du Colombier tr->state = SClosed;
7179a747e4fSDavid du Colombier unlock(&tr->statelk);
7189a747e4fSDavid du Colombier alertHand(tr, "close notify");
7199a747e4fSDavid du Colombier }
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier /*
7229a747e4fSDavid du Colombier * read and process one tls record layer message
7239a747e4fSDavid du Colombier * must be called with tr->in.io held
7249a747e4fSDavid du Colombier * We can't let Eintrs lose data, since doing so will get
7259a747e4fSDavid du Colombier * us out of sync with the sender and break the reliablity
7269a747e4fSDavid du Colombier * of the channel. Eintr only happens during the reads in
7279a747e4fSDavid du Colombier * consume. Therefore we put back any bytes consumed before
7289a747e4fSDavid du Colombier * the last call to ensure.
7299a747e4fSDavid du Colombier */
7309a747e4fSDavid du Colombier static void
tlsrecread(TlsRec * tr)7319a747e4fSDavid du Colombier tlsrecread(TlsRec *tr)
7329a747e4fSDavid du Colombier {
7339a747e4fSDavid du Colombier OneWay *volatile in;
7349a747e4fSDavid du Colombier Block *volatile b;
7359b7bf7dfSDavid du Colombier uchar *p, seq[8], header[RecHdrLen], hmac[MaxMacLen];
7369a747e4fSDavid du Colombier int volatile nconsumed;
737a6a9e072SDavid du Colombier int len, type, ver, unpad_len;
7389a747e4fSDavid du Colombier
7399a747e4fSDavid du Colombier nconsumed = 0;
7409a747e4fSDavid du Colombier if(waserror()){
7419a747e4fSDavid du Colombier if(strcmp(up->errstr, Eintr) == 0 && !waserror()){
7429a747e4fSDavid du Colombier regurgitate(tr, header, nconsumed);
7439a747e4fSDavid du Colombier poperror();
7449a747e4fSDavid du Colombier }else
7459a747e4fSDavid du Colombier tlsError(tr, "channel error");
7469a747e4fSDavid du Colombier nexterror();
7479a747e4fSDavid du Colombier }
7489a747e4fSDavid du Colombier ensure(tr, &tr->unprocessed, RecHdrLen);
7499a747e4fSDavid du Colombier consume(&tr->unprocessed, header, RecHdrLen);
7503751babcSDavid du Colombier if(tr->debug)pprint("consumed %d header\n", RecHdrLen);
7519a747e4fSDavid du Colombier nconsumed = RecHdrLen;
7529a747e4fSDavid du Colombier
7539a747e4fSDavid du Colombier if((tr->handin == 0) && (header[0] & 0x80)){
7549a747e4fSDavid du Colombier /* Cope with an SSL3 ClientHello expressed in SSL2 record format.
7559a747e4fSDavid du Colombier This is sent by some clients that we must interoperate
7569a747e4fSDavid du Colombier with, such as Java's JSSE and Microsoft's Internet Explorer. */
7579a747e4fSDavid du Colombier len = (get16(header) & ~0x8000) - 3;
7589a747e4fSDavid du Colombier type = header[2];
7599a747e4fSDavid du Colombier ver = get16(header + 3);
7609a747e4fSDavid du Colombier if(type != SSL2ClientHello || len < 22)
7619a747e4fSDavid du Colombier rcvError(tr, EProtocolVersion, "invalid initial SSL2-like message");
7629a747e4fSDavid du Colombier }else{ /* normal SSL3 record format */
7639a747e4fSDavid du Colombier type = header[0];
7649a747e4fSDavid du Colombier ver = get16(header+1);
7659a747e4fSDavid du Colombier len = get16(header+3);
7669a747e4fSDavid du Colombier }
7679a747e4fSDavid du Colombier if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion))
7689a747e4fSDavid du Colombier rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'",
7699a747e4fSDavid du Colombier tr->version, tr->verset?"/set":"", len, type, ver, (char*)header);
7709a747e4fSDavid du Colombier if(len > MaxCipherRecLen || len < 0)
7719a747e4fSDavid du Colombier rcvError(tr, ERecordOverflow, "record message too long %d", len);
7729a747e4fSDavid du Colombier ensure(tr, &tr->unprocessed, len);
7739a747e4fSDavid du Colombier nconsumed = 0;
7749a747e4fSDavid du Colombier poperror();
7759a747e4fSDavid du Colombier
7769a747e4fSDavid du Colombier /*
7779a747e4fSDavid du Colombier * If an Eintr happens after this, we'll get out of sync.
7789a747e4fSDavid du Colombier * Make sure nothing we call can sleep.
7799a747e4fSDavid du Colombier * Errors are ok, as they kill the connection.
7809a747e4fSDavid du Colombier * Luckily, allocb won't sleep, it'll just error out.
7819a747e4fSDavid du Colombier */
7829a747e4fSDavid du Colombier b = nil;
7839a747e4fSDavid du Colombier if(waserror()){
7849a747e4fSDavid du Colombier if(b != nil)
7859a747e4fSDavid du Colombier freeb(b);
7869a747e4fSDavid du Colombier tlsError(tr, "channel error");
7879a747e4fSDavid du Colombier nexterror();
7889a747e4fSDavid du Colombier }
7899a747e4fSDavid du Colombier b = qgrab(&tr->unprocessed, len);
7903751babcSDavid du Colombier if(tr->debug) pprint("consumed unprocessed %d\n", len);
7919a747e4fSDavid du Colombier
7929a747e4fSDavid du Colombier in = &tr->in;
7939a747e4fSDavid du Colombier if(waserror()){
7949a747e4fSDavid du Colombier qunlock(&in->seclock);
7959a747e4fSDavid du Colombier nexterror();
7969a747e4fSDavid du Colombier }
7979a747e4fSDavid du Colombier qlock(&in->seclock);
7989a747e4fSDavid du Colombier p = b->rp;
7999a747e4fSDavid du Colombier if(in->sec != nil) {
800a6a9e072SDavid du Colombier /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here
801a6a9e072SDavid du Colombier should look alike, including timing of the response. */
802a6a9e072SDavid du Colombier unpad_len = (*in->sec->dec)(in->sec, p, len);
8033751babcSDavid du Colombier if(unpad_len >= in->sec->maclen)
804a6a9e072SDavid du Colombier len = unpad_len - in->sec->maclen;
8053751babcSDavid du Colombier if(tr->debug) pprint("decrypted %d\n", unpad_len);
8063751babcSDavid du Colombier if(tr->debug) pdump(unpad_len, p, "decrypted:");
8079a747e4fSDavid du Colombier
8089a747e4fSDavid du Colombier /* update length */
8099a747e4fSDavid du Colombier put16(header+3, len);
8109a747e4fSDavid du Colombier put64(seq, in->seq);
8119a747e4fSDavid du Colombier in->seq++;
8129a747e4fSDavid du Colombier (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac);
8133751babcSDavid du Colombier if(unpad_len < in->sec->maclen)
814dc5a79c1SDavid du Colombier rcvError(tr, EBadRecordMac, "short record mac");
815dc5a79c1SDavid du Colombier if(memcmp(hmac, p+len, in->sec->maclen) != 0)
8169a747e4fSDavid du Colombier rcvError(tr, EBadRecordMac, "record mac mismatch");
8179a747e4fSDavid du Colombier b->wp = b->rp + len;
8189a747e4fSDavid du Colombier }
8199a747e4fSDavid du Colombier qunlock(&in->seclock);
8209a747e4fSDavid du Colombier poperror();
8213751babcSDavid du Colombier if(len < 0)
8229a747e4fSDavid du Colombier rcvError(tr, EDecodeError, "runt record message");
8239a747e4fSDavid du Colombier
8249a747e4fSDavid du Colombier switch(type) {
8259a747e4fSDavid du Colombier default:
826567483c8SDavid du Colombier rcvError(tr, EIllegalParameter, "invalid record message %#x", type);
8279a747e4fSDavid du Colombier break;
8289a747e4fSDavid du Colombier case RChangeCipherSpec:
8299a747e4fSDavid du Colombier if(len != 1 || p[0] != 1)
8309a747e4fSDavid du Colombier rcvError(tr, EDecodeError, "invalid change cipher spec");
8319a747e4fSDavid du Colombier qlock(&in->seclock);
8329a747e4fSDavid du Colombier if(in->new == nil){
8339a747e4fSDavid du Colombier qunlock(&in->seclock);
8349a747e4fSDavid du Colombier rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec");
8359a747e4fSDavid du Colombier }
8369a747e4fSDavid du Colombier freeSec(in->sec);
8379a747e4fSDavid du Colombier in->sec = in->new;
8389a747e4fSDavid du Colombier in->new = nil;
8399a747e4fSDavid du Colombier in->seq = 0;
8409a747e4fSDavid du Colombier qunlock(&in->seclock);
8419a747e4fSDavid du Colombier break;
8429a747e4fSDavid du Colombier case RAlert:
8439a747e4fSDavid du Colombier if(len != 2)
8449a747e4fSDavid du Colombier rcvError(tr, EDecodeError, "invalid alert");
8459a747e4fSDavid du Colombier if(p[0] == 2)
8469a747e4fSDavid du Colombier rcvAlert(tr, p[1]);
8479a747e4fSDavid du Colombier if(p[0] != 1)
8489a747e4fSDavid du Colombier rcvError(tr, EIllegalParameter, "invalid alert fatal code");
8499a747e4fSDavid du Colombier
8509a747e4fSDavid du Colombier /*
8519a747e4fSDavid du Colombier * propate non-fatal alerts to handshaker
8529a747e4fSDavid du Colombier */
8539a747e4fSDavid du Colombier if(p[1] == ECloseNotify) {
8549a747e4fSDavid du Colombier tlsclosed(tr, SRClose);
8559a747e4fSDavid du Colombier if(tr->opened)
8569a747e4fSDavid du Colombier error("tls hungup");
8579a747e4fSDavid du Colombier error("close notify");
8589a747e4fSDavid du Colombier }
8599a747e4fSDavid du Colombier if(p[1] == ENoRenegotiation)
8609a747e4fSDavid du Colombier alertHand(tr, "no renegotiation");
8619a747e4fSDavid du Colombier else if(p[1] == EUserCanceled)
8629a747e4fSDavid du Colombier alertHand(tr, "handshake canceled by user");
8639a747e4fSDavid du Colombier else
8649a747e4fSDavid du Colombier rcvError(tr, EIllegalParameter, "invalid alert code");
8659a747e4fSDavid du Colombier break;
8669a747e4fSDavid du Colombier case RHandshake:
8679a747e4fSDavid du Colombier /*
8689a747e4fSDavid du Colombier * don't worry about dropping the block
8699a747e4fSDavid du Colombier * qbwrite always queues even if flow controlled and interrupted.
8709a747e4fSDavid du Colombier *
8719a747e4fSDavid du Colombier * if there isn't any handshaker, ignore the request,
8729a747e4fSDavid du Colombier * but notify the other side we are doing so.
8739a747e4fSDavid du Colombier */
8749a747e4fSDavid du Colombier lock(&tr->hqlock);
8759a747e4fSDavid du Colombier if(tr->handq != nil){
8769a747e4fSDavid du Colombier tr->hqref++;
8779a747e4fSDavid du Colombier unlock(&tr->hqlock);
8789a747e4fSDavid du Colombier if(waserror()){
8799a747e4fSDavid du Colombier dechandq(tr);
8809a747e4fSDavid du Colombier nexterror();
8819a747e4fSDavid du Colombier }
8829a747e4fSDavid du Colombier b = padblock(b, 1);
8839a747e4fSDavid du Colombier *b->rp = RHandshake;
8849a747e4fSDavid du Colombier qbwrite(tr->handq, b);
8859a747e4fSDavid du Colombier b = nil;
8869a747e4fSDavid du Colombier poperror();
8879a747e4fSDavid du Colombier dechandq(tr);
8889a747e4fSDavid du Colombier }else{
8899a747e4fSDavid du Colombier unlock(&tr->hqlock);
8909a747e4fSDavid du Colombier if(tr->verset && tr->version != SSL3Version && !waserror()){
8919a747e4fSDavid du Colombier sendAlert(tr, ENoRenegotiation);
8929a747e4fSDavid du Colombier poperror();
8939a747e4fSDavid du Colombier }
8949a747e4fSDavid du Colombier }
8959a747e4fSDavid du Colombier break;
8969a747e4fSDavid du Colombier case SSL2ClientHello:
8979a747e4fSDavid du Colombier lock(&tr->hqlock);
8989a747e4fSDavid du Colombier if(tr->handq != nil){
8999a747e4fSDavid du Colombier tr->hqref++;
9009a747e4fSDavid du Colombier unlock(&tr->hqlock);
9019a747e4fSDavid du Colombier if(waserror()){
9029a747e4fSDavid du Colombier dechandq(tr);
9039a747e4fSDavid du Colombier nexterror();
9049a747e4fSDavid du Colombier }
9059a747e4fSDavid du Colombier /* Pass the SSL2 format data, so that the handshake code can compute
9069a747e4fSDavid du Colombier the correct checksums. HSSL2ClientHello = HandshakeType 9 is
9079a747e4fSDavid du Colombier unused in RFC2246. */
9089a747e4fSDavid du Colombier b = padblock(b, 8);
9099a747e4fSDavid du Colombier b->rp[0] = RHandshake;
9109a747e4fSDavid du Colombier b->rp[1] = HSSL2ClientHello;
9119a747e4fSDavid du Colombier put24(&b->rp[2], len+3);
9129a747e4fSDavid du Colombier b->rp[5] = SSL2ClientHello;
9139a747e4fSDavid du Colombier put16(&b->rp[6], ver);
9149a747e4fSDavid du Colombier qbwrite(tr->handq, b);
9159a747e4fSDavid du Colombier b = nil;
9169a747e4fSDavid du Colombier poperror();
9179a747e4fSDavid du Colombier dechandq(tr);
9189a747e4fSDavid du Colombier }else{
9199a747e4fSDavid du Colombier unlock(&tr->hqlock);
9209a747e4fSDavid du Colombier if(tr->verset && tr->version != SSL3Version && !waserror()){
9219a747e4fSDavid du Colombier sendAlert(tr, ENoRenegotiation);
9229a747e4fSDavid du Colombier poperror();
9239a747e4fSDavid du Colombier }
9249a747e4fSDavid du Colombier }
9259a747e4fSDavid du Colombier break;
9269a747e4fSDavid du Colombier case RApplication:
9279a747e4fSDavid du Colombier if(!tr->opened)
9289a747e4fSDavid du Colombier rcvError(tr, EUnexpectedMessage, "application message received before handshake completed");
9293751babcSDavid du Colombier if(BLEN(b) > 0){
9309a747e4fSDavid du Colombier tr->processed = b;
9319a747e4fSDavid du Colombier b = nil;
9323751babcSDavid du Colombier }
9339a747e4fSDavid du Colombier break;
9349a747e4fSDavid du Colombier }
9359a747e4fSDavid du Colombier if(b != nil)
9369a747e4fSDavid du Colombier freeb(b);
9379a747e4fSDavid du Colombier poperror();
9389a747e4fSDavid du Colombier }
9399a747e4fSDavid du Colombier
9409a747e4fSDavid du Colombier /*
9419a747e4fSDavid du Colombier * got a fatal alert message
9429a747e4fSDavid du Colombier */
9439a747e4fSDavid du Colombier static void
rcvAlert(TlsRec * tr,int err)9449a747e4fSDavid du Colombier rcvAlert(TlsRec *tr, int err)
9459a747e4fSDavid du Colombier {
9469a747e4fSDavid du Colombier char *s;
9479a747e4fSDavid du Colombier int i;
9489a747e4fSDavid du Colombier
9499a747e4fSDavid du Colombier s = "unknown error";
9509a747e4fSDavid du Colombier for(i=0; i < nelem(tlserrs); i++){
9519a747e4fSDavid du Colombier if(tlserrs[i].err == err){
9529a747e4fSDavid du Colombier s = tlserrs[i].msg;
9539a747e4fSDavid du Colombier break;
9549a747e4fSDavid du Colombier }
9559a747e4fSDavid du Colombier }
9563751babcSDavid du Colombier if(tr->debug) pprint("rcvAlert: %s\n", s);
9579a747e4fSDavid du Colombier
9589a747e4fSDavid du Colombier tlsError(tr, s);
9599a747e4fSDavid du Colombier if(!tr->opened)
9609a747e4fSDavid du Colombier error(s);
9619a747e4fSDavid du Colombier error("tls error");
9629a747e4fSDavid du Colombier }
9639a747e4fSDavid du Colombier
9649a747e4fSDavid du Colombier /*
9659a747e4fSDavid du Colombier * found an error while decoding the input stream
9669a747e4fSDavid du Colombier */
9679a747e4fSDavid du Colombier static void
rcvError(TlsRec * tr,int err,char * fmt,...)9689a747e4fSDavid du Colombier rcvError(TlsRec *tr, int err, char *fmt, ...)
9699a747e4fSDavid du Colombier {
9709a747e4fSDavid du Colombier char msg[ERRMAX];
9719a747e4fSDavid du Colombier va_list arg;
9729a747e4fSDavid du Colombier
9739a747e4fSDavid du Colombier va_start(arg, fmt);
9749a747e4fSDavid du Colombier vseprint(msg, msg+sizeof(msg), fmt, arg);
9759a747e4fSDavid du Colombier va_end(arg);
9763751babcSDavid du Colombier if(tr->debug) pprint("rcvError: %s\n", msg);
9779a747e4fSDavid du Colombier
9789a747e4fSDavid du Colombier sendAlert(tr, err);
9799a747e4fSDavid du Colombier
9809a747e4fSDavid du Colombier if(!tr->opened)
9819a747e4fSDavid du Colombier error(msg);
9829a747e4fSDavid du Colombier error("tls error");
9839a747e4fSDavid du Colombier }
9849a747e4fSDavid du Colombier
9859a747e4fSDavid du Colombier /*
9869a747e4fSDavid du Colombier * make sure the next hand operation returns with a 'msg' error
9879a747e4fSDavid du Colombier */
9889a747e4fSDavid du Colombier static void
alertHand(TlsRec * tr,char * msg)9899a747e4fSDavid du Colombier alertHand(TlsRec *tr, char *msg)
9909a747e4fSDavid du Colombier {
9919a747e4fSDavid du Colombier Block *b;
9929a747e4fSDavid du Colombier int n;
9939a747e4fSDavid du Colombier
9949a747e4fSDavid du Colombier lock(&tr->hqlock);
9959a747e4fSDavid du Colombier if(tr->handq == nil){
9969a747e4fSDavid du Colombier unlock(&tr->hqlock);
9979a747e4fSDavid du Colombier return;
9989a747e4fSDavid du Colombier }
9999a747e4fSDavid du Colombier tr->hqref++;
10009a747e4fSDavid du Colombier unlock(&tr->hqlock);
10019a747e4fSDavid du Colombier
10029a747e4fSDavid du Colombier n = strlen(msg);
10039a747e4fSDavid du Colombier if(waserror()){
10049a747e4fSDavid du Colombier dechandq(tr);
10059a747e4fSDavid du Colombier nexterror();
10069a747e4fSDavid du Colombier }
10079a747e4fSDavid du Colombier b = allocb(n + 2);
10089a747e4fSDavid du Colombier *b->wp++ = RAlert;
10099a747e4fSDavid du Colombier memmove(b->wp, msg, n + 1);
10109a747e4fSDavid du Colombier b->wp += n + 1;
10119a747e4fSDavid du Colombier
10129a747e4fSDavid du Colombier qbwrite(tr->handq, b);
10139a747e4fSDavid du Colombier
10149a747e4fSDavid du Colombier poperror();
10159a747e4fSDavid du Colombier dechandq(tr);
10169a747e4fSDavid du Colombier }
10179a747e4fSDavid du Colombier
10189a747e4fSDavid du Colombier static void
checkstate(TlsRec * tr,int ishand,int ok)10199a747e4fSDavid du Colombier checkstate(TlsRec *tr, int ishand, int ok)
10209a747e4fSDavid du Colombier {
10219a747e4fSDavid du Colombier int state;
10229a747e4fSDavid du Colombier
10239a747e4fSDavid du Colombier lock(&tr->statelk);
10249a747e4fSDavid du Colombier state = tr->state;
10259a747e4fSDavid du Colombier unlock(&tr->statelk);
10269a747e4fSDavid du Colombier if(state & ok)
10279a747e4fSDavid du Colombier return;
10289a747e4fSDavid du Colombier switch(state){
10299a747e4fSDavid du Colombier case SHandshake:
10309a747e4fSDavid du Colombier case SOpen:
10319a747e4fSDavid du Colombier break;
10329a747e4fSDavid du Colombier case SError:
10339a747e4fSDavid du Colombier case SAlert:
10349a747e4fSDavid du Colombier if(ishand)
10359a747e4fSDavid du Colombier error(tr->err);
10369a747e4fSDavid du Colombier error("tls error");
10379a747e4fSDavid du Colombier case SRClose:
10389a747e4fSDavid du Colombier case SLClose:
10399a747e4fSDavid du Colombier case SClosed:
10409a747e4fSDavid du Colombier error("tls hungup");
10419a747e4fSDavid du Colombier }
10429a747e4fSDavid du Colombier error("tls improperly configured");
10439a747e4fSDavid du Colombier }
10449a747e4fSDavid du Colombier
10459a747e4fSDavid du Colombier static Block*
tlsbread(Chan * c,long n,ulong offset)10469a747e4fSDavid du Colombier tlsbread(Chan *c, long n, ulong offset)
10479a747e4fSDavid du Colombier {
10489a747e4fSDavid du Colombier int ty;
10499a747e4fSDavid du Colombier Block *b;
10509a747e4fSDavid du Colombier TlsRec *volatile tr;
10519a747e4fSDavid du Colombier
10529a747e4fSDavid du Colombier ty = TYPE(c->qid);
10539a747e4fSDavid du Colombier switch(ty) {
10549a747e4fSDavid du Colombier default:
10559a747e4fSDavid du Colombier return devbread(c, n, offset);
10569a747e4fSDavid du Colombier case Qhand:
10579a747e4fSDavid du Colombier case Qdata:
10589a747e4fSDavid du Colombier break;
10599a747e4fSDavid du Colombier }
10609a747e4fSDavid du Colombier
10619a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
10629a747e4fSDavid du Colombier if(tr == nil)
10639a747e4fSDavid du Colombier panic("tlsbread");
10649a747e4fSDavid du Colombier
10659a747e4fSDavid du Colombier if(waserror()){
10669a747e4fSDavid du Colombier qunlock(&tr->in.io);
10679a747e4fSDavid du Colombier nexterror();
10689a747e4fSDavid du Colombier }
10699a747e4fSDavid du Colombier qlock(&tr->in.io);
10709a747e4fSDavid du Colombier if(ty == Qdata){
10719a747e4fSDavid du Colombier checkstate(tr, 0, SOpen);
10729a747e4fSDavid du Colombier while(tr->processed == nil)
10739a747e4fSDavid du Colombier tlsrecread(tr);
10749a747e4fSDavid du Colombier
10759a747e4fSDavid du Colombier /* return at most what was asked for */
10769a747e4fSDavid du Colombier b = qgrab(&tr->processed, n);
1077e464ed1aSDavid du Colombier if(tr->debug) pprint("consumed processed %ld\n", BLEN(b));
10783751babcSDavid du Colombier if(tr->debug) pdump(BLEN(b), b->rp, "consumed:");
10799a747e4fSDavid du Colombier qunlock(&tr->in.io);
10809a747e4fSDavid du Colombier poperror();
10819a747e4fSDavid du Colombier tr->datain += BLEN(b);
10829a747e4fSDavid du Colombier }else{
10839a747e4fSDavid du Colombier checkstate(tr, 1, SOpen|SHandshake|SLClose);
10849a747e4fSDavid du Colombier
10859a747e4fSDavid du Colombier /*
10869a747e4fSDavid du Colombier * it's ok to look at state without the lock
10879a747e4fSDavid du Colombier * since it only protects reading records,
10889a747e4fSDavid du Colombier * and we have that tr->in.io held.
10899a747e4fSDavid du Colombier */
10909a747e4fSDavid du Colombier while(!tr->opened && tr->hprocessed == nil && !qcanread(tr->handq))
10919a747e4fSDavid du Colombier tlsrecread(tr);
10929a747e4fSDavid du Colombier
10939a747e4fSDavid du Colombier qunlock(&tr->in.io);
10949a747e4fSDavid du Colombier poperror();
10959a747e4fSDavid du Colombier
10969a747e4fSDavid du Colombier if(waserror()){
10979a747e4fSDavid du Colombier qunlock(&tr->hqread);
10989a747e4fSDavid du Colombier nexterror();
10999a747e4fSDavid du Colombier }
11009a747e4fSDavid du Colombier qlock(&tr->hqread);
11019a747e4fSDavid du Colombier if(tr->hprocessed == nil){
11029a747e4fSDavid du Colombier b = qbread(tr->handq, MaxRecLen + 1);
11039a747e4fSDavid du Colombier if(*b->rp++ == RAlert){
1104dc5a79c1SDavid du Colombier kstrcpy(up->errstr, (char*)b->rp, ERRMAX);
11059a747e4fSDavid du Colombier freeb(b);
11069a747e4fSDavid du Colombier nexterror();
11079a747e4fSDavid du Colombier }
11089a747e4fSDavid du Colombier tr->hprocessed = b;
11099a747e4fSDavid du Colombier }
11109a747e4fSDavid du Colombier b = qgrab(&tr->hprocessed, n);
11119a747e4fSDavid du Colombier poperror();
11129a747e4fSDavid du Colombier qunlock(&tr->hqread);
11139a747e4fSDavid du Colombier tr->handin += BLEN(b);
11149a747e4fSDavid du Colombier }
11159a747e4fSDavid du Colombier
11169a747e4fSDavid du Colombier return b;
11179a747e4fSDavid du Colombier }
11189a747e4fSDavid du Colombier
11199a747e4fSDavid du Colombier static long
tlsread(Chan * c,void * a,long n,vlong off)11209a747e4fSDavid du Colombier tlsread(Chan *c, void *a, long n, vlong off)
11219a747e4fSDavid du Colombier {
11229a747e4fSDavid du Colombier Block *volatile b;
11239a747e4fSDavid du Colombier Block *nb;
11249a747e4fSDavid du Colombier uchar *va;
11259a747e4fSDavid du Colombier int i, ty;
11269a747e4fSDavid du Colombier char *buf, *s, *e;
11279a747e4fSDavid du Colombier ulong offset = off;
11289a747e4fSDavid du Colombier TlsRec * tr;
11299a747e4fSDavid du Colombier
11309a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
11319a747e4fSDavid du Colombier return devdirread(c, a, n, 0, 0, tlsgen);
11329a747e4fSDavid du Colombier
11339a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
11349a747e4fSDavid du Colombier ty = TYPE(c->qid);
11359a747e4fSDavid du Colombier switch(ty) {
11369a747e4fSDavid du Colombier default:
11379a747e4fSDavid du Colombier error(Ebadusefd);
11389a747e4fSDavid du Colombier case Qstatus:
11399a747e4fSDavid du Colombier buf = smalloc(Statlen);
11409a747e4fSDavid du Colombier qlock(&tr->in.seclock);
11419a747e4fSDavid du Colombier qlock(&tr->out.seclock);
11429a747e4fSDavid du Colombier s = buf;
11439a747e4fSDavid du Colombier e = buf + Statlen;
11449a747e4fSDavid du Colombier s = seprint(s, e, "State: %s\n", tlsstate(tr->state));
1145567483c8SDavid du Colombier s = seprint(s, e, "Version: %#x\n", tr->version);
11469a747e4fSDavid du Colombier if(tr->in.sec != nil)
11479a747e4fSDavid du Colombier s = seprint(s, e, "EncIn: %s\nHashIn: %s\n", tr->in.sec->encalg, tr->in.sec->hashalg);
11489a747e4fSDavid du Colombier if(tr->in.new != nil)
11499a747e4fSDavid du Colombier s = seprint(s, e, "NewEncIn: %s\nNewHashIn: %s\n", tr->in.new->encalg, tr->in.new->hashalg);
11509a747e4fSDavid du Colombier if(tr->out.sec != nil)
11519a747e4fSDavid du Colombier s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg);
11529a747e4fSDavid du Colombier if(tr->out.new != nil)
11539a747e4fSDavid du Colombier seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg);
11549a747e4fSDavid du Colombier qunlock(&tr->in.seclock);
11559a747e4fSDavid du Colombier qunlock(&tr->out.seclock);
11569a747e4fSDavid du Colombier n = readstr(offset, a, n, buf);
11579a747e4fSDavid du Colombier free(buf);
11589a747e4fSDavid du Colombier return n;
11599a747e4fSDavid du Colombier case Qstats:
11609a747e4fSDavid du Colombier buf = smalloc(Statlen);
11619a747e4fSDavid du Colombier s = buf;
11629a747e4fSDavid du Colombier e = buf + Statlen;
11639a747e4fSDavid du Colombier s = seprint(s, e, "DataIn: %lld\n", tr->datain);
11649a747e4fSDavid du Colombier s = seprint(s, e, "DataOut: %lld\n", tr->dataout);
11659a747e4fSDavid du Colombier s = seprint(s, e, "HandIn: %lld\n", tr->handin);
11669a747e4fSDavid du Colombier seprint(s, e, "HandOut: %lld\n", tr->handout);
11679a747e4fSDavid du Colombier n = readstr(offset, a, n, buf);
11689a747e4fSDavid du Colombier free(buf);
11699a747e4fSDavid du Colombier return n;
11709a747e4fSDavid du Colombier case Qctl:
11719a747e4fSDavid du Colombier buf = smalloc(Statlen);
11729a747e4fSDavid du Colombier snprint(buf, Statlen, "%llud", CONV(c->qid));
11739a747e4fSDavid du Colombier n = readstr(offset, a, n, buf);
11749a747e4fSDavid du Colombier free(buf);
11759a747e4fSDavid du Colombier return n;
11769a747e4fSDavid du Colombier case Qdata:
11779a747e4fSDavid du Colombier case Qhand:
11789a747e4fSDavid du Colombier b = tlsbread(c, n, offset);
11799a747e4fSDavid du Colombier break;
11809a747e4fSDavid du Colombier case Qencalgs:
11819a747e4fSDavid du Colombier return readstr(offset, a, n, encalgs);
11829a747e4fSDavid du Colombier case Qhashalgs:
11839a747e4fSDavid du Colombier return readstr(offset, a, n, hashalgs);
11849a747e4fSDavid du Colombier }
11859a747e4fSDavid du Colombier
11869a747e4fSDavid du Colombier if(waserror()){
11879a747e4fSDavid du Colombier freeblist(b);
11889a747e4fSDavid du Colombier nexterror();
11899a747e4fSDavid du Colombier }
11909a747e4fSDavid du Colombier
11919a747e4fSDavid du Colombier n = 0;
11929a747e4fSDavid du Colombier va = a;
11939a747e4fSDavid du Colombier for(nb = b; nb; nb = nb->next){
11949a747e4fSDavid du Colombier i = BLEN(nb);
11959a747e4fSDavid du Colombier memmove(va+n, nb->rp, i);
11969a747e4fSDavid du Colombier n += i;
11979a747e4fSDavid du Colombier }
11989a747e4fSDavid du Colombier
11999a747e4fSDavid du Colombier freeblist(b);
12009a747e4fSDavid du Colombier poperror();
12019a747e4fSDavid du Colombier
12029a747e4fSDavid du Colombier return n;
12039a747e4fSDavid du Colombier }
12049a747e4fSDavid du Colombier
12059a747e4fSDavid du Colombier /*
12069a747e4fSDavid du Colombier * write a block in tls records
12079a747e4fSDavid du Colombier */
12089a747e4fSDavid du Colombier static void
tlsrecwrite(TlsRec * tr,int type,Block * b)12099a747e4fSDavid du Colombier tlsrecwrite(TlsRec *tr, int type, Block *b)
12109a747e4fSDavid du Colombier {
12119a747e4fSDavid du Colombier Block *volatile bb;
12129a747e4fSDavid du Colombier Block *nb;
12139a747e4fSDavid du Colombier uchar *p, seq[8];
12149a747e4fSDavid du Colombier OneWay *volatile out;
12159a747e4fSDavid du Colombier int n, maclen, pad, ok;
12169a747e4fSDavid du Colombier
12179a747e4fSDavid du Colombier out = &tr->out;
12189a747e4fSDavid du Colombier bb = b;
12199a747e4fSDavid du Colombier if(waserror()){
12209a747e4fSDavid du Colombier qunlock(&out->io);
12219a747e4fSDavid du Colombier if(bb != nil)
12229a747e4fSDavid du Colombier freeb(bb);
12239a747e4fSDavid du Colombier nexterror();
12249a747e4fSDavid du Colombier }
12259a747e4fSDavid du Colombier qlock(&out->io);
1226e464ed1aSDavid du Colombier if(tr->debug)pprint("send %ld\n", BLEN(b));
12273751babcSDavid du Colombier if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
12283751babcSDavid du Colombier
12299a747e4fSDavid du Colombier
12309a747e4fSDavid du Colombier ok = SHandshake|SOpen|SRClose;
12319a747e4fSDavid du Colombier if(type == RAlert)
12329a747e4fSDavid du Colombier ok |= SAlert;
12339a747e4fSDavid du Colombier while(bb != nil){
12349a747e4fSDavid du Colombier checkstate(tr, type != RApplication, ok);
12359a747e4fSDavid du Colombier
12369a747e4fSDavid du Colombier /*
12379a747e4fSDavid du Colombier * get at most one maximal record's input,
12389a747e4fSDavid du Colombier * with padding on the front for header and
12399a747e4fSDavid du Colombier * back for mac and maximal block padding.
12409a747e4fSDavid du Colombier */
12419a747e4fSDavid du Colombier if(waserror()){
12429a747e4fSDavid du Colombier qunlock(&out->seclock);
12439a747e4fSDavid du Colombier nexterror();
12449a747e4fSDavid du Colombier }
12459a747e4fSDavid du Colombier qlock(&out->seclock);
12469a747e4fSDavid du Colombier maclen = 0;
12479a747e4fSDavid du Colombier pad = 0;
12489a747e4fSDavid du Colombier if(out->sec != nil){
12499a747e4fSDavid du Colombier maclen = out->sec->maclen;
12509a747e4fSDavid du Colombier pad = maclen + out->sec->block;
12519a747e4fSDavid du Colombier }
12529a747e4fSDavid du Colombier n = BLEN(bb);
12539a747e4fSDavid du Colombier if(n > MaxRecLen){
12549a747e4fSDavid du Colombier n = MaxRecLen;
12559a747e4fSDavid du Colombier nb = allocb(n + pad + RecHdrLen);
12569a747e4fSDavid du Colombier memmove(nb->wp + RecHdrLen, bb->rp, n);
12579a747e4fSDavid du Colombier bb->rp += n;
12589a747e4fSDavid du Colombier }else{
12599a747e4fSDavid du Colombier /*
12609a747e4fSDavid du Colombier * carefully reuse bb so it will get freed if we're out of memory
12619a747e4fSDavid du Colombier */
12629a747e4fSDavid du Colombier bb = padblock(bb, RecHdrLen);
12639a747e4fSDavid du Colombier if(pad)
12649a747e4fSDavid du Colombier nb = padblock(bb, -pad);
12659a747e4fSDavid du Colombier else
12669a747e4fSDavid du Colombier nb = bb;
12679a747e4fSDavid du Colombier bb = nil;
12689a747e4fSDavid du Colombier }
12699a747e4fSDavid du Colombier
12709a747e4fSDavid du Colombier p = nb->rp;
12719a747e4fSDavid du Colombier p[0] = type;
12729a747e4fSDavid du Colombier put16(p+1, tr->version);
12739a747e4fSDavid du Colombier put16(p+3, n);
12749a747e4fSDavid du Colombier
12759a747e4fSDavid du Colombier if(out->sec != nil){
12769a747e4fSDavid du Colombier put64(seq, out->seq);
12779a747e4fSDavid du Colombier out->seq++;
12789a747e4fSDavid du Colombier (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n);
12799a747e4fSDavid du Colombier n += maclen;
12809a747e4fSDavid du Colombier
12819a747e4fSDavid du Colombier /* encrypt */
12829a747e4fSDavid du Colombier n = (*out->sec->enc)(out->sec, p + RecHdrLen, n);
12839a747e4fSDavid du Colombier nb->wp = p + RecHdrLen + n;
12849a747e4fSDavid du Colombier
12859a747e4fSDavid du Colombier /* update length */
12869a747e4fSDavid du Colombier put16(p+3, n);
12879a747e4fSDavid du Colombier }
12889a747e4fSDavid du Colombier if(type == RChangeCipherSpec){
12899a747e4fSDavid du Colombier if(out->new == nil)
12909a747e4fSDavid du Colombier error("change cipher without a new cipher");
12919a747e4fSDavid du Colombier freeSec(out->sec);
12929a747e4fSDavid du Colombier out->sec = out->new;
12939a747e4fSDavid du Colombier out->new = nil;
12949a747e4fSDavid du Colombier out->seq = 0;
12959a747e4fSDavid du Colombier }
12969a747e4fSDavid du Colombier qunlock(&out->seclock);
12979a747e4fSDavid du Colombier poperror();
12989a747e4fSDavid du Colombier
12999a747e4fSDavid du Colombier /*
13009a747e4fSDavid du Colombier * if bwrite error's, we assume the block is queued.
13019a747e4fSDavid du Colombier * if not, we're out of sync with the receiver and will not recover.
13029a747e4fSDavid du Colombier */
13039a747e4fSDavid du Colombier if(waserror()){
13049a747e4fSDavid du Colombier if(strcmp(up->errstr, "interrupted") != 0)
13059a747e4fSDavid du Colombier tlsError(tr, "channel error");
13069a747e4fSDavid du Colombier nexterror();
13079a747e4fSDavid du Colombier }
13089a747e4fSDavid du Colombier devtab[tr->c->type]->bwrite(tr->c, nb, 0);
13099a747e4fSDavid du Colombier poperror();
13109a747e4fSDavid du Colombier }
13119a747e4fSDavid du Colombier qunlock(&out->io);
13129a747e4fSDavid du Colombier poperror();
13139a747e4fSDavid du Colombier }
13149a747e4fSDavid du Colombier
13159a747e4fSDavid du Colombier static long
tlsbwrite(Chan * c,Block * b,ulong offset)13169a747e4fSDavid du Colombier tlsbwrite(Chan *c, Block *b, ulong offset)
13179a747e4fSDavid du Colombier {
13189a747e4fSDavid du Colombier int ty;
13199a747e4fSDavid du Colombier ulong n;
13209a747e4fSDavid du Colombier TlsRec *tr;
13219a747e4fSDavid du Colombier
13229a747e4fSDavid du Colombier n = BLEN(b);
13239a747e4fSDavid du Colombier
13249a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
13259a747e4fSDavid du Colombier if(tr == nil)
13269b7bf7dfSDavid du Colombier panic("tlsbwrite");
13279a747e4fSDavid du Colombier
13289a747e4fSDavid du Colombier ty = TYPE(c->qid);
13299a747e4fSDavid du Colombier switch(ty) {
13309a747e4fSDavid du Colombier default:
13319a747e4fSDavid du Colombier return devbwrite(c, b, offset);
13329a747e4fSDavid du Colombier case Qhand:
13339a747e4fSDavid du Colombier tlsrecwrite(tr, RHandshake, b);
13349a747e4fSDavid du Colombier tr->handout += n;
13359a747e4fSDavid du Colombier break;
13369a747e4fSDavid du Colombier case Qdata:
13379a747e4fSDavid du Colombier checkstate(tr, 0, SOpen);
13389a747e4fSDavid du Colombier tlsrecwrite(tr, RApplication, b);
13399a747e4fSDavid du Colombier tr->dataout += n;
13409a747e4fSDavid du Colombier break;
13419a747e4fSDavid du Colombier }
13429a747e4fSDavid du Colombier
13439a747e4fSDavid du Colombier return n;
13449a747e4fSDavid du Colombier }
13459a747e4fSDavid du Colombier
13469a747e4fSDavid du Colombier typedef struct Hashalg Hashalg;
13479a747e4fSDavid du Colombier struct Hashalg
13489a747e4fSDavid du Colombier {
13499a747e4fSDavid du Colombier char *name;
13509a747e4fSDavid du Colombier int maclen;
13519a747e4fSDavid du Colombier void (*initkey)(Hashalg *, int, Secret *, uchar*);
13529a747e4fSDavid du Colombier };
13539a747e4fSDavid du Colombier
13549a747e4fSDavid du Colombier static void
initmd5key(Hashalg * ha,int version,Secret * s,uchar * p)13559a747e4fSDavid du Colombier initmd5key(Hashalg *ha, int version, Secret *s, uchar *p)
13569a747e4fSDavid du Colombier {
13579a747e4fSDavid du Colombier s->maclen = ha->maclen;
13589a747e4fSDavid du Colombier if(version == SSL3Version)
13599a747e4fSDavid du Colombier s->mac = sslmac_md5;
13609a747e4fSDavid du Colombier else
13619a747e4fSDavid du Colombier s->mac = hmac_md5;
13629a747e4fSDavid du Colombier memmove(s->mackey, p, ha->maclen);
13639a747e4fSDavid du Colombier }
13649a747e4fSDavid du Colombier
13659a747e4fSDavid du Colombier static void
initclearmac(Hashalg *,int,Secret * s,uchar *)13669a747e4fSDavid du Colombier initclearmac(Hashalg *, int, Secret *s, uchar *)
13679a747e4fSDavid du Colombier {
13689a747e4fSDavid du Colombier s->maclen = 0;
13699a747e4fSDavid du Colombier s->mac = nomac;
13709a747e4fSDavid du Colombier }
13719a747e4fSDavid du Colombier
13729a747e4fSDavid du Colombier static void
initsha1key(Hashalg * ha,int version,Secret * s,uchar * p)13739a747e4fSDavid du Colombier initsha1key(Hashalg *ha, int version, Secret *s, uchar *p)
13749a747e4fSDavid du Colombier {
13759a747e4fSDavid du Colombier s->maclen = ha->maclen;
13769a747e4fSDavid du Colombier if(version == SSL3Version)
13779a747e4fSDavid du Colombier s->mac = sslmac_sha1;
13789a747e4fSDavid du Colombier else
13799a747e4fSDavid du Colombier s->mac = hmac_sha1;
13809a747e4fSDavid du Colombier memmove(s->mackey, p, ha->maclen);
13819a747e4fSDavid du Colombier }
13829a747e4fSDavid du Colombier
13839a747e4fSDavid du Colombier static Hashalg hashtab[] =
13849a747e4fSDavid du Colombier {
13859a747e4fSDavid du Colombier { "clear", 0, initclearmac, },
13869a747e4fSDavid du Colombier { "md5", MD5dlen, initmd5key, },
13879a747e4fSDavid du Colombier { "sha1", SHA1dlen, initsha1key, },
13889a747e4fSDavid du Colombier { 0 }
13899a747e4fSDavid du Colombier };
13909a747e4fSDavid du Colombier
13919a747e4fSDavid du Colombier static Hashalg*
parsehashalg(char * p)13929a747e4fSDavid du Colombier parsehashalg(char *p)
13939a747e4fSDavid du Colombier {
13949a747e4fSDavid du Colombier Hashalg *ha;
13959a747e4fSDavid du Colombier
13969a747e4fSDavid du Colombier for(ha = hashtab; ha->name; ha++)
13979a747e4fSDavid du Colombier if(strcmp(p, ha->name) == 0)
13989a747e4fSDavid du Colombier return ha;
13999a747e4fSDavid du Colombier error("unsupported hash algorithm");
14009a747e4fSDavid du Colombier return nil;
14019a747e4fSDavid du Colombier }
14029a747e4fSDavid du Colombier
14039a747e4fSDavid du Colombier typedef struct Encalg Encalg;
14049a747e4fSDavid du Colombier struct Encalg
14059a747e4fSDavid du Colombier {
14069a747e4fSDavid du Colombier char *name;
14079a747e4fSDavid du Colombier int keylen;
14089a747e4fSDavid du Colombier int ivlen;
14099a747e4fSDavid du Colombier void (*initkey)(Encalg *ea, Secret *, uchar*, uchar*);
14109a747e4fSDavid du Colombier };
14119a747e4fSDavid du Colombier
14129a747e4fSDavid du Colombier static void
initRC4key(Encalg * ea,Secret * s,uchar * p,uchar *)14139a747e4fSDavid du Colombier initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *)
14149a747e4fSDavid du Colombier {
14159a747e4fSDavid du Colombier s->enckey = smalloc(sizeof(RC4state));
14169a747e4fSDavid du Colombier s->enc = rc4enc;
14179a747e4fSDavid du Colombier s->dec = rc4enc;
14189a747e4fSDavid du Colombier s->block = 0;
14199a747e4fSDavid du Colombier setupRC4state(s->enckey, p, ea->keylen);
14209a747e4fSDavid du Colombier }
14219a747e4fSDavid du Colombier
14229a747e4fSDavid du Colombier static void
initDES3key(Encalg *,Secret * s,uchar * p,uchar * iv)14239a747e4fSDavid du Colombier initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv)
14249a747e4fSDavid du Colombier {
14259a747e4fSDavid du Colombier s->enckey = smalloc(sizeof(DES3state));
14269a747e4fSDavid du Colombier s->enc = des3enc;
14279a747e4fSDavid du Colombier s->dec = des3dec;
14289a747e4fSDavid du Colombier s->block = 8;
14299a747e4fSDavid du Colombier setupDES3state(s->enckey, (uchar(*)[8])p, iv);
14309a747e4fSDavid du Colombier }
14319a747e4fSDavid du Colombier
14329a747e4fSDavid du Colombier static void
initAESkey(Encalg * ea,Secret * s,uchar * p,uchar * iv)1433ad6ca847SDavid du Colombier initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
1434ad6ca847SDavid du Colombier {
1435ad6ca847SDavid du Colombier s->enckey = smalloc(sizeof(AESstate));
1436ad6ca847SDavid du Colombier s->enc = aesenc;
1437ad6ca847SDavid du Colombier s->dec = aesdec;
1438ad6ca847SDavid du Colombier s->block = 16;
1439ad6ca847SDavid du Colombier setupAESstate(s->enckey, p, ea->keylen, iv);
1440ad6ca847SDavid du Colombier }
1441ad6ca847SDavid du Colombier
1442ad6ca847SDavid du Colombier static void
initclearenc(Encalg *,Secret * s,uchar *,uchar *)14439a747e4fSDavid du Colombier initclearenc(Encalg *, Secret *s, uchar *, uchar *)
14449a747e4fSDavid du Colombier {
14459a747e4fSDavid du Colombier s->enc = noenc;
14469a747e4fSDavid du Colombier s->dec = noenc;
14479a747e4fSDavid du Colombier s->block = 0;
14489a747e4fSDavid du Colombier }
14499a747e4fSDavid du Colombier
14509a747e4fSDavid du Colombier static Encalg encrypttab[] =
14519a747e4fSDavid du Colombier {
14529a747e4fSDavid du Colombier { "clear", 0, 0, initclearenc },
14539a747e4fSDavid du Colombier { "rc4_128", 128/8, 0, initRC4key },
14549a747e4fSDavid du Colombier { "3des_ede_cbc", 3 * 8, 8, initDES3key },
1455ad6ca847SDavid du Colombier { "aes_128_cbc", 128/8, 16, initAESkey },
1456ad6ca847SDavid du Colombier { "aes_256_cbc", 256/8, 16, initAESkey },
14579a747e4fSDavid du Colombier { 0 }
14589a747e4fSDavid du Colombier };
14599a747e4fSDavid du Colombier
14609a747e4fSDavid du Colombier static Encalg*
parseencalg(char * p)14619a747e4fSDavid du Colombier parseencalg(char *p)
14629a747e4fSDavid du Colombier {
14639a747e4fSDavid du Colombier Encalg *ea;
14649a747e4fSDavid du Colombier
14659a747e4fSDavid du Colombier for(ea = encrypttab; ea->name; ea++)
14669a747e4fSDavid du Colombier if(strcmp(p, ea->name) == 0)
14679a747e4fSDavid du Colombier return ea;
14689a747e4fSDavid du Colombier error("unsupported encryption algorithm");
14699a747e4fSDavid du Colombier return nil;
14709a747e4fSDavid du Colombier }
14719a747e4fSDavid du Colombier
14729a747e4fSDavid du Colombier static long
tlswrite(Chan * c,void * a,long n,vlong off)14739a747e4fSDavid du Colombier tlswrite(Chan *c, void *a, long n, vlong off)
14749a747e4fSDavid du Colombier {
14759a747e4fSDavid du Colombier Encalg *ea;
14769a747e4fSDavid du Colombier Hashalg *ha;
14779a747e4fSDavid du Colombier TlsRec *volatile tr;
14789a747e4fSDavid du Colombier Secret *volatile tos, *volatile toc;
14799a747e4fSDavid du Colombier Block *volatile b;
14809a747e4fSDavid du Colombier Cmdbuf *volatile cb;
14819a747e4fSDavid du Colombier int m, ty;
14829a747e4fSDavid du Colombier char *p, *e;
14839a747e4fSDavid du Colombier uchar *volatile x;
14849a747e4fSDavid du Colombier ulong offset = off;
14859a747e4fSDavid du Colombier
14869a747e4fSDavid du Colombier tr = tlsdevs[CONV(c->qid)];
14879a747e4fSDavid du Colombier if(tr == nil)
14889a747e4fSDavid du Colombier panic("tlswrite");
14899a747e4fSDavid du Colombier
14909a747e4fSDavid du Colombier ty = TYPE(c->qid);
14919a747e4fSDavid du Colombier switch(ty){
14929a747e4fSDavid du Colombier case Qdata:
14939a747e4fSDavid du Colombier case Qhand:
14949a747e4fSDavid du Colombier p = a;
14959a747e4fSDavid du Colombier e = p + n;
14969a747e4fSDavid du Colombier do{
14979a747e4fSDavid du Colombier m = e - p;
14989a747e4fSDavid du Colombier if(m > MaxRecLen)
14999a747e4fSDavid du Colombier m = MaxRecLen;
15009a747e4fSDavid du Colombier
15019a747e4fSDavid du Colombier b = allocb(m);
15029a747e4fSDavid du Colombier if(waserror()){
15039a747e4fSDavid du Colombier freeb(b);
15049a747e4fSDavid du Colombier nexterror();
15059a747e4fSDavid du Colombier }
15069a747e4fSDavid du Colombier memmove(b->wp, p, m);
15079a747e4fSDavid du Colombier poperror();
15089a747e4fSDavid du Colombier b->wp += m;
15099a747e4fSDavid du Colombier
15109a747e4fSDavid du Colombier tlsbwrite(c, b, offset);
15119a747e4fSDavid du Colombier
15129a747e4fSDavid du Colombier p += m;
15139a747e4fSDavid du Colombier }while(p < e);
15149a747e4fSDavid du Colombier return n;
15159a747e4fSDavid du Colombier case Qctl:
15169a747e4fSDavid du Colombier break;
15179a747e4fSDavid du Colombier default:
15189a747e4fSDavid du Colombier error(Ebadusefd);
15199a747e4fSDavid du Colombier return -1;
15209a747e4fSDavid du Colombier }
15219a747e4fSDavid du Colombier
15229a747e4fSDavid du Colombier cb = parsecmd(a, n);
15239a747e4fSDavid du Colombier if(waserror()){
15249a747e4fSDavid du Colombier free(cb);
15259a747e4fSDavid du Colombier nexterror();
15269a747e4fSDavid du Colombier }
15279a747e4fSDavid du Colombier if(cb->nf < 1)
15289a747e4fSDavid du Colombier error("short control request");
15299a747e4fSDavid du Colombier
15309a747e4fSDavid du Colombier /* mutex with operations using what we're about to change */
15319a747e4fSDavid du Colombier if(waserror()){
15329a747e4fSDavid du Colombier qunlock(&tr->in.seclock);
15339a747e4fSDavid du Colombier qunlock(&tr->out.seclock);
15349a747e4fSDavid du Colombier nexterror();
15359a747e4fSDavid du Colombier }
15369a747e4fSDavid du Colombier qlock(&tr->in.seclock);
15379a747e4fSDavid du Colombier qlock(&tr->out.seclock);
15389a747e4fSDavid du Colombier
15399a747e4fSDavid du Colombier if(strcmp(cb->f[0], "fd") == 0){
15409a747e4fSDavid du Colombier if(cb->nf != 3)
15419a747e4fSDavid du Colombier error("usage: fd open-fd version");
15429a747e4fSDavid du Colombier if(tr->c != nil)
15439a747e4fSDavid du Colombier error(Einuse);
15449a747e4fSDavid du Colombier m = strtol(cb->f[2], nil, 0);
15459a747e4fSDavid du Colombier if(m < MinProtoVersion || m > MaxProtoVersion)
15469a747e4fSDavid du Colombier error("unsupported version");
15479a747e4fSDavid du Colombier tr->c = buftochan(cb->f[1]);
15489a747e4fSDavid du Colombier tr->version = m;
15499a747e4fSDavid du Colombier tlsSetState(tr, SHandshake, SClosed);
15509a747e4fSDavid du Colombier }else if(strcmp(cb->f[0], "version") == 0){
15519a747e4fSDavid du Colombier if(cb->nf != 2)
15529a747e4fSDavid du Colombier error("usage: version vers");
15539a747e4fSDavid du Colombier if(tr->c == nil)
15549a747e4fSDavid du Colombier error("must set fd before version");
15559a747e4fSDavid du Colombier if(tr->verset)
15569a747e4fSDavid du Colombier error("version already set");
15579a747e4fSDavid du Colombier m = strtol(cb->f[1], nil, 0);
15589a747e4fSDavid du Colombier if(m == SSL3Version)
15599a747e4fSDavid du Colombier tr->packMac = sslPackMac;
15609a747e4fSDavid du Colombier else if(m == TLSVersion)
15619a747e4fSDavid du Colombier tr->packMac = tlsPackMac;
15629a747e4fSDavid du Colombier else
15639a747e4fSDavid du Colombier error("unsupported version");
15649a747e4fSDavid du Colombier tr->verset = 1;
15659a747e4fSDavid du Colombier tr->version = m;
15669a747e4fSDavid du Colombier }else if(strcmp(cb->f[0], "secret") == 0){
15679a747e4fSDavid du Colombier if(cb->nf != 5)
15689a747e4fSDavid du Colombier error("usage: secret hashalg encalg isclient secretdata");
15699a747e4fSDavid du Colombier if(tr->c == nil || !tr->verset)
15709a747e4fSDavid du Colombier error("must set fd and version before secrets");
15719a747e4fSDavid du Colombier
15729a747e4fSDavid du Colombier if(tr->in.new != nil){
15739a747e4fSDavid du Colombier freeSec(tr->in.new);
15749a747e4fSDavid du Colombier tr->in.new = nil;
15759a747e4fSDavid du Colombier }
15769a747e4fSDavid du Colombier if(tr->out.new != nil){
15779a747e4fSDavid du Colombier freeSec(tr->out.new);
15789a747e4fSDavid du Colombier tr->out.new = nil;
15799a747e4fSDavid du Colombier }
15809a747e4fSDavid du Colombier
15819a747e4fSDavid du Colombier ha = parsehashalg(cb->f[1]);
15829a747e4fSDavid du Colombier ea = parseencalg(cb->f[2]);
15839a747e4fSDavid du Colombier
15849a747e4fSDavid du Colombier p = cb->f[4];
15859a747e4fSDavid du Colombier m = (strlen(p)*3)/2;
15869a747e4fSDavid du Colombier x = smalloc(m);
15879a747e4fSDavid du Colombier tos = nil;
15889a747e4fSDavid du Colombier toc = nil;
15899a747e4fSDavid du Colombier if(waserror()){
15909a747e4fSDavid du Colombier freeSec(tos);
15919a747e4fSDavid du Colombier freeSec(toc);
15929a747e4fSDavid du Colombier free(x);
15939a747e4fSDavid du Colombier nexterror();
15949a747e4fSDavid du Colombier }
15959a747e4fSDavid du Colombier m = dec64(x, m, p, strlen(p));
15969a747e4fSDavid du Colombier if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen)
15979a747e4fSDavid du Colombier error("not enough secret data provided");
15989a747e4fSDavid du Colombier
15999a747e4fSDavid du Colombier tos = smalloc(sizeof(Secret));
16009a747e4fSDavid du Colombier toc = smalloc(sizeof(Secret));
16019a747e4fSDavid du Colombier if(!ha->initkey || !ea->initkey)
16029a747e4fSDavid du Colombier error("misimplemented secret algorithm");
16039a747e4fSDavid du Colombier (*ha->initkey)(ha, tr->version, tos, &x[0]);
16049a747e4fSDavid du Colombier (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]);
16059a747e4fSDavid du Colombier (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]);
16069a747e4fSDavid du Colombier (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]);
16079a747e4fSDavid du Colombier
16089a747e4fSDavid du Colombier if(!tos->mac || !tos->enc || !tos->dec
16099a747e4fSDavid du Colombier || !toc->mac || !toc->enc || !toc->dec)
16109a747e4fSDavid du Colombier error("missing algorithm implementations");
16119a747e4fSDavid du Colombier if(strtol(cb->f[3], nil, 0) == 0){
16129a747e4fSDavid du Colombier tr->in.new = tos;
16139a747e4fSDavid du Colombier tr->out.new = toc;
16149a747e4fSDavid du Colombier }else{
16159a747e4fSDavid du Colombier tr->in.new = toc;
16169a747e4fSDavid du Colombier tr->out.new = tos;
16179a747e4fSDavid du Colombier }
16189a747e4fSDavid du Colombier if(tr->version == SSL3Version){
16199a747e4fSDavid du Colombier toc->unpad = sslunpad;
16209a747e4fSDavid du Colombier tos->unpad = sslunpad;
16219a747e4fSDavid du Colombier }else{
16229a747e4fSDavid du Colombier toc->unpad = tlsunpad;
16239a747e4fSDavid du Colombier tos->unpad = tlsunpad;
16249a747e4fSDavid du Colombier }
16259a747e4fSDavid du Colombier toc->encalg = ea->name;
16269a747e4fSDavid du Colombier toc->hashalg = ha->name;
16279a747e4fSDavid du Colombier tos->encalg = ea->name;
16289a747e4fSDavid du Colombier tos->hashalg = ha->name;
16299a747e4fSDavid du Colombier
16309a747e4fSDavid du Colombier free(x);
16319a747e4fSDavid du Colombier poperror();
16329a747e4fSDavid du Colombier }else if(strcmp(cb->f[0], "changecipher") == 0){
16339a747e4fSDavid du Colombier if(cb->nf != 1)
16349a747e4fSDavid du Colombier error("usage: changecipher");
16359a747e4fSDavid du Colombier if(tr->out.new == nil)
16368cd4f5a6SDavid du Colombier error("cannot change cipher spec without setting secret");
16379a747e4fSDavid du Colombier
16389a747e4fSDavid du Colombier qunlock(&tr->in.seclock);
16399a747e4fSDavid du Colombier qunlock(&tr->out.seclock);
16409a747e4fSDavid du Colombier poperror();
16419a747e4fSDavid du Colombier free(cb);
16429a747e4fSDavid du Colombier poperror();
16439a747e4fSDavid du Colombier
16449a747e4fSDavid du Colombier /*
16459a747e4fSDavid du Colombier * the real work is done as the message is written
16469a747e4fSDavid du Colombier * so the stream is encrypted in sync.
16479a747e4fSDavid du Colombier */
16489a747e4fSDavid du Colombier b = allocb(1);
16499a747e4fSDavid du Colombier *b->wp++ = 1;
16509a747e4fSDavid du Colombier tlsrecwrite(tr, RChangeCipherSpec, b);
16519a747e4fSDavid du Colombier return n;
16529a747e4fSDavid du Colombier }else if(strcmp(cb->f[0], "opened") == 0){
16539a747e4fSDavid du Colombier if(cb->nf != 1)
16549a747e4fSDavid du Colombier error("usage: opened");
16559a747e4fSDavid du Colombier if(tr->in.sec == nil || tr->out.sec == nil)
16569a747e4fSDavid du Colombier error("cipher must be configured before enabling data messages");
16579a747e4fSDavid du Colombier lock(&tr->statelk);
16589a747e4fSDavid du Colombier if(tr->state != SHandshake && tr->state != SOpen){
16599a747e4fSDavid du Colombier unlock(&tr->statelk);
16608cd4f5a6SDavid du Colombier error("cannot enable data messages");
16619a747e4fSDavid du Colombier }
16629a747e4fSDavid du Colombier tr->state = SOpen;
16639a747e4fSDavid du Colombier unlock(&tr->statelk);
16649a747e4fSDavid du Colombier tr->opened = 1;
16659a747e4fSDavid du Colombier }else if(strcmp(cb->f[0], "alert") == 0){
16669a747e4fSDavid du Colombier if(cb->nf != 2)
16679a747e4fSDavid du Colombier error("usage: alert n");
16689a747e4fSDavid du Colombier if(tr->c == nil)
16699a747e4fSDavid du Colombier error("must set fd before sending alerts");
16709a747e4fSDavid du Colombier m = strtol(cb->f[1], nil, 0);
16719a747e4fSDavid du Colombier
16729a747e4fSDavid du Colombier qunlock(&tr->in.seclock);
16739a747e4fSDavid du Colombier qunlock(&tr->out.seclock);
16749a747e4fSDavid du Colombier poperror();
16759a747e4fSDavid du Colombier free(cb);
16769a747e4fSDavid du Colombier poperror();
16779a747e4fSDavid du Colombier
16789a747e4fSDavid du Colombier sendAlert(tr, m);
16799a747e4fSDavid du Colombier
16809a747e4fSDavid du Colombier if(m == ECloseNotify)
16819a747e4fSDavid du Colombier tlsclosed(tr, SLClose);
16829a747e4fSDavid du Colombier
16839a747e4fSDavid du Colombier return n;
16843751babcSDavid du Colombier } else if(strcmp(cb->f[0], "debug") == 0){
16853751babcSDavid du Colombier if(cb->nf == 2){
16863751babcSDavid du Colombier if(strcmp(cb->f[1], "on") == 0)
16873751babcSDavid du Colombier tr->debug = 1;
16883751babcSDavid du Colombier else
16893751babcSDavid du Colombier tr->debug = 0;
16903751babcSDavid du Colombier } else
16913751babcSDavid du Colombier tr->debug = 1;
16929a747e4fSDavid du Colombier } else
16939a747e4fSDavid du Colombier error(Ebadarg);
16949a747e4fSDavid du Colombier
16959a747e4fSDavid du Colombier qunlock(&tr->in.seclock);
16969a747e4fSDavid du Colombier qunlock(&tr->out.seclock);
16979a747e4fSDavid du Colombier poperror();
16989a747e4fSDavid du Colombier free(cb);
16999a747e4fSDavid du Colombier poperror();
17009a747e4fSDavid du Colombier
17019a747e4fSDavid du Colombier return n;
17029a747e4fSDavid du Colombier }
17039a747e4fSDavid du Colombier
17049a747e4fSDavid du Colombier static void
tlsinit(void)17059a747e4fSDavid du Colombier tlsinit(void)
17069a747e4fSDavid du Colombier {
17079a747e4fSDavid du Colombier struct Encalg *e;
17089a747e4fSDavid du Colombier struct Hashalg *h;
17099a747e4fSDavid du Colombier int n;
17109a747e4fSDavid du Colombier char *cp;
17113751babcSDavid du Colombier static int already;
17123751babcSDavid du Colombier
17133751babcSDavid du Colombier if(!already){
17143751babcSDavid du Colombier fmtinstall('H', encodefmt);
17153751babcSDavid du Colombier already = 1;
17163751babcSDavid du Colombier }
17179a747e4fSDavid du Colombier
17189a747e4fSDavid du Colombier tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs);
17199a747e4fSDavid du Colombier trnames = smalloc((sizeof *trnames) * maxtlsdevs);
17209a747e4fSDavid du Colombier
17219a747e4fSDavid du Colombier n = 1;
17229a747e4fSDavid du Colombier for(e = encrypttab; e->name != nil; e++)
17239a747e4fSDavid du Colombier n += strlen(e->name) + 1;
17249a747e4fSDavid du Colombier cp = encalgs = smalloc(n);
17259a747e4fSDavid du Colombier for(e = encrypttab;;){
17269a747e4fSDavid du Colombier strcpy(cp, e->name);
17279a747e4fSDavid du Colombier cp += strlen(e->name);
17289a747e4fSDavid du Colombier e++;
17299a747e4fSDavid du Colombier if(e->name == nil)
17309a747e4fSDavid du Colombier break;
17319a747e4fSDavid du Colombier *cp++ = ' ';
17329a747e4fSDavid du Colombier }
17339a747e4fSDavid du Colombier *cp = 0;
17349a747e4fSDavid du Colombier
17359a747e4fSDavid du Colombier n = 1;
17369a747e4fSDavid du Colombier for(h = hashtab; h->name != nil; h++)
17379a747e4fSDavid du Colombier n += strlen(h->name) + 1;
17389a747e4fSDavid du Colombier cp = hashalgs = smalloc(n);
17399a747e4fSDavid du Colombier for(h = hashtab;;){
17409a747e4fSDavid du Colombier strcpy(cp, h->name);
17419a747e4fSDavid du Colombier cp += strlen(h->name);
17429a747e4fSDavid du Colombier h++;
17439a747e4fSDavid du Colombier if(h->name == nil)
17449a747e4fSDavid du Colombier break;
17459a747e4fSDavid du Colombier *cp++ = ' ';
17469a747e4fSDavid du Colombier }
17479a747e4fSDavid du Colombier *cp = 0;
17489a747e4fSDavid du Colombier }
17499a747e4fSDavid du Colombier
17509a747e4fSDavid du Colombier Dev tlsdevtab = {
17519a747e4fSDavid du Colombier 'a',
17529a747e4fSDavid du Colombier "tls",
17539a747e4fSDavid du Colombier
17549a747e4fSDavid du Colombier devreset,
17559a747e4fSDavid du Colombier tlsinit,
17569a747e4fSDavid du Colombier devshutdown,
17579a747e4fSDavid du Colombier tlsattach,
17589a747e4fSDavid du Colombier tlswalk,
17599a747e4fSDavid du Colombier tlsstat,
17609a747e4fSDavid du Colombier tlsopen,
17619a747e4fSDavid du Colombier devcreate,
17629a747e4fSDavid du Colombier tlsclose,
17639a747e4fSDavid du Colombier tlsread,
17649a747e4fSDavid du Colombier tlsbread,
17659a747e4fSDavid du Colombier tlswrite,
17669a747e4fSDavid du Colombier tlsbwrite,
17679a747e4fSDavid du Colombier devremove,
17689a747e4fSDavid du Colombier tlswstat,
17699a747e4fSDavid du Colombier };
17709a747e4fSDavid du Colombier
17719a747e4fSDavid du Colombier /* get channel associated with an fd */
17729a747e4fSDavid du Colombier static Chan*
buftochan(char * p)17739a747e4fSDavid du Colombier buftochan(char *p)
17749a747e4fSDavid du Colombier {
17759a747e4fSDavid du Colombier Chan *c;
17769a747e4fSDavid du Colombier int fd;
17779a747e4fSDavid du Colombier
17789a747e4fSDavid du Colombier if(p == 0)
17799a747e4fSDavid du Colombier error(Ebadarg);
17809a747e4fSDavid du Colombier fd = strtoul(p, 0, 0);
17819a747e4fSDavid du Colombier if(fd < 0)
17829a747e4fSDavid du Colombier error(Ebadarg);
17839a747e4fSDavid du Colombier c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
17849a747e4fSDavid du Colombier return c;
17859a747e4fSDavid du Colombier }
17869a747e4fSDavid du Colombier
17879a747e4fSDavid du Colombier static void
sendAlert(TlsRec * tr,int err)17889a747e4fSDavid du Colombier sendAlert(TlsRec *tr, int err)
17899a747e4fSDavid du Colombier {
17909a747e4fSDavid du Colombier Block *b;
17919a747e4fSDavid du Colombier int i, fatal;
17929a747e4fSDavid du Colombier char *msg;
17939a747e4fSDavid du Colombier
17943751babcSDavid du Colombier if(tr->debug)pprint("sendAlert %d\n", err);
17959a747e4fSDavid du Colombier fatal = 1;
17969a747e4fSDavid du Colombier msg = "tls unknown alert";
17979a747e4fSDavid du Colombier for(i=0; i < nelem(tlserrs); i++) {
17989a747e4fSDavid du Colombier if(tlserrs[i].err == err) {
17999a747e4fSDavid du Colombier msg = tlserrs[i].msg;
18009a747e4fSDavid du Colombier if(tr->version == SSL3Version)
18019a747e4fSDavid du Colombier err = tlserrs[i].sslerr;
18029a747e4fSDavid du Colombier else
18039a747e4fSDavid du Colombier err = tlserrs[i].tlserr;
18049a747e4fSDavid du Colombier fatal = tlserrs[i].fatal;
18059a747e4fSDavid du Colombier break;
18069a747e4fSDavid du Colombier }
18079a747e4fSDavid du Colombier }
18089a747e4fSDavid du Colombier
18099a747e4fSDavid du Colombier if(!waserror()){
18109a747e4fSDavid du Colombier b = allocb(2);
18119a747e4fSDavid du Colombier *b->wp++ = fatal + 1;
18129a747e4fSDavid du Colombier *b->wp++ = err;
18139a747e4fSDavid du Colombier if(fatal)
18149a747e4fSDavid du Colombier tlsSetState(tr, SAlert, SOpen|SHandshake|SRClose);
18159a747e4fSDavid du Colombier tlsrecwrite(tr, RAlert, b);
18169a747e4fSDavid du Colombier poperror();
18179a747e4fSDavid du Colombier }
18189a747e4fSDavid du Colombier if(fatal)
18199a747e4fSDavid du Colombier tlsError(tr, msg);
18209a747e4fSDavid du Colombier }
18219a747e4fSDavid du Colombier
18229a747e4fSDavid du Colombier static void
tlsError(TlsRec * tr,char * msg)18239a747e4fSDavid du Colombier tlsError(TlsRec *tr, char *msg)
18249a747e4fSDavid du Colombier {
18259a747e4fSDavid du Colombier int s;
18269a747e4fSDavid du Colombier
18273751babcSDavid du Colombier if(tr->debug)pprint("tleError %s\n", msg);
18289a747e4fSDavid du Colombier lock(&tr->statelk);
18299a747e4fSDavid du Colombier s = tr->state;
18309a747e4fSDavid du Colombier tr->state = SError;
18319a747e4fSDavid du Colombier if(s != SError){
18329a747e4fSDavid du Colombier strncpy(tr->err, msg, ERRMAX - 1);
18339a747e4fSDavid du Colombier tr->err[ERRMAX - 1] = '\0';
18349a747e4fSDavid du Colombier }
18359a747e4fSDavid du Colombier unlock(&tr->statelk);
18369a747e4fSDavid du Colombier if(s != SError)
18379a747e4fSDavid du Colombier alertHand(tr, msg);
18389a747e4fSDavid du Colombier }
18399a747e4fSDavid du Colombier
18409a747e4fSDavid du Colombier static void
tlsSetState(TlsRec * tr,int new,int old)18419a747e4fSDavid du Colombier tlsSetState(TlsRec *tr, int new, int old)
18429a747e4fSDavid du Colombier {
18439a747e4fSDavid du Colombier lock(&tr->statelk);
18449a747e4fSDavid du Colombier if(tr->state & old)
18459a747e4fSDavid du Colombier tr->state = new;
18469a747e4fSDavid du Colombier unlock(&tr->statelk);
18479a747e4fSDavid du Colombier }
18489a747e4fSDavid du Colombier
18499a747e4fSDavid du Colombier /* hand up a digest connection */
18509a747e4fSDavid du Colombier static void
tlshangup(TlsRec * tr)18519a747e4fSDavid du Colombier tlshangup(TlsRec *tr)
18529a747e4fSDavid du Colombier {
18539a747e4fSDavid du Colombier Block *b;
18549a747e4fSDavid du Colombier
18559a747e4fSDavid du Colombier qlock(&tr->in.io);
18569a747e4fSDavid du Colombier for(b = tr->processed; b; b = tr->processed){
18579a747e4fSDavid du Colombier tr->processed = b->next;
18589a747e4fSDavid du Colombier freeb(b);
18599a747e4fSDavid du Colombier }
18609a747e4fSDavid du Colombier if(tr->unprocessed != nil){
18619a747e4fSDavid du Colombier freeb(tr->unprocessed);
18629a747e4fSDavid du Colombier tr->unprocessed = nil;
18639a747e4fSDavid du Colombier }
18649a747e4fSDavid du Colombier qunlock(&tr->in.io);
18659a747e4fSDavid du Colombier
18669a747e4fSDavid du Colombier tlsSetState(tr, SClosed, ~0);
18679a747e4fSDavid du Colombier }
18689a747e4fSDavid du Colombier
18699a747e4fSDavid du Colombier static TlsRec*
newtls(Chan * ch)18709a747e4fSDavid du Colombier newtls(Chan *ch)
18719a747e4fSDavid du Colombier {
18729a747e4fSDavid du Colombier TlsRec **pp, **ep, **np;
18739a747e4fSDavid du Colombier char **nmp;
18749a747e4fSDavid du Colombier int t, newmax;
18759a747e4fSDavid du Colombier
18769a747e4fSDavid du Colombier if(waserror()) {
18779a747e4fSDavid du Colombier unlock(&tdlock);
18789a747e4fSDavid du Colombier nexterror();
18799a747e4fSDavid du Colombier }
18809a747e4fSDavid du Colombier lock(&tdlock);
18819a747e4fSDavid du Colombier ep = &tlsdevs[maxtlsdevs];
18829a747e4fSDavid du Colombier for(pp = tlsdevs; pp < ep; pp++)
18839a747e4fSDavid du Colombier if(*pp == nil)
18849a747e4fSDavid du Colombier break;
18859a747e4fSDavid du Colombier if(pp >= ep) {
18869a747e4fSDavid du Colombier if(maxtlsdevs >= MaxTlsDevs) {
18879a747e4fSDavid du Colombier unlock(&tdlock);
18889a747e4fSDavid du Colombier poperror();
18899a747e4fSDavid du Colombier return nil;
18909a747e4fSDavid du Colombier }
18919a747e4fSDavid du Colombier newmax = 2 * maxtlsdevs;
18929a747e4fSDavid du Colombier if(newmax > MaxTlsDevs)
18939a747e4fSDavid du Colombier newmax = MaxTlsDevs;
18949a747e4fSDavid du Colombier np = smalloc(sizeof(TlsRec*) * newmax);
18959a747e4fSDavid du Colombier memmove(np, tlsdevs, sizeof(TlsRec*) * maxtlsdevs);
18969a747e4fSDavid du Colombier tlsdevs = np;
18979a747e4fSDavid du Colombier pp = &tlsdevs[maxtlsdevs];
18989a747e4fSDavid du Colombier memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs));
18999a747e4fSDavid du Colombier
19009a747e4fSDavid du Colombier nmp = smalloc(sizeof *nmp * newmax);
19019a747e4fSDavid du Colombier memmove(nmp, trnames, sizeof *nmp * maxtlsdevs);
19029a747e4fSDavid du Colombier trnames = nmp;
19039a747e4fSDavid du Colombier
19049a747e4fSDavid du Colombier maxtlsdevs = newmax;
19059a747e4fSDavid du Colombier }
19069a747e4fSDavid du Colombier *pp = mktlsrec();
19079a747e4fSDavid du Colombier if(pp - tlsdevs >= tdhiwat)
19089a747e4fSDavid du Colombier tdhiwat++;
19099a747e4fSDavid du Colombier t = TYPE(ch->qid);
19109a747e4fSDavid du Colombier if(t == Qclonus)
19119a747e4fSDavid du Colombier t = Qctl;
19129a747e4fSDavid du Colombier ch->qid.path = QID(pp - tlsdevs, t);
19139a747e4fSDavid du Colombier ch->qid.vers = 0;
19149a747e4fSDavid du Colombier unlock(&tdlock);
19159a747e4fSDavid du Colombier poperror();
19169a747e4fSDavid du Colombier return *pp;
19179a747e4fSDavid du Colombier }
19189a747e4fSDavid du Colombier
19199a747e4fSDavid du Colombier static TlsRec *
mktlsrec(void)19209a747e4fSDavid du Colombier mktlsrec(void)
19219a747e4fSDavid du Colombier {
19229a747e4fSDavid du Colombier TlsRec *tr;
19239a747e4fSDavid du Colombier
19249a747e4fSDavid du Colombier tr = mallocz(sizeof(*tr), 1);
19259a747e4fSDavid du Colombier if(tr == nil)
19269a747e4fSDavid du Colombier error(Enomem);
19279a747e4fSDavid du Colombier tr->state = SClosed;
19289a747e4fSDavid du Colombier tr->ref = 1;
19299a747e4fSDavid du Colombier kstrdup(&tr->user, up->user);
19309a747e4fSDavid du Colombier tr->perm = 0660;
19319a747e4fSDavid du Colombier return tr;
19329a747e4fSDavid du Colombier }
19339a747e4fSDavid du Colombier
19349a747e4fSDavid du Colombier static char*
tlsstate(int s)19359a747e4fSDavid du Colombier tlsstate(int s)
19369a747e4fSDavid du Colombier {
19379a747e4fSDavid du Colombier switch(s){
19389a747e4fSDavid du Colombier case SHandshake:
19399a747e4fSDavid du Colombier return "Handshaking";
19409a747e4fSDavid du Colombier case SOpen:
19419a747e4fSDavid du Colombier return "Established";
19429a747e4fSDavid du Colombier case SRClose:
19439a747e4fSDavid du Colombier return "RemoteClosed";
19449a747e4fSDavid du Colombier case SLClose:
19459a747e4fSDavid du Colombier return "LocalClosed";
19469a747e4fSDavid du Colombier case SAlert:
19479a747e4fSDavid du Colombier return "Alerting";
19489a747e4fSDavid du Colombier case SError:
19499a747e4fSDavid du Colombier return "Errored";
19509a747e4fSDavid du Colombier case SClosed:
19519a747e4fSDavid du Colombier return "Closed";
19529a747e4fSDavid du Colombier }
19539a747e4fSDavid du Colombier return "Unknown";
19549a747e4fSDavid du Colombier }
19559a747e4fSDavid du Colombier
19569a747e4fSDavid du Colombier static void
freeSec(Secret * s)19579a747e4fSDavid du Colombier freeSec(Secret *s)
19589a747e4fSDavid du Colombier {
19599a747e4fSDavid du Colombier if(s != nil){
19609a747e4fSDavid du Colombier free(s->enckey);
19619a747e4fSDavid du Colombier free(s);
19629a747e4fSDavid du Colombier }
19639a747e4fSDavid du Colombier }
19649a747e4fSDavid du Colombier
19659a747e4fSDavid du Colombier static int
noenc(Secret *,uchar *,int n)19669a747e4fSDavid du Colombier noenc(Secret *, uchar *, int n)
19679a747e4fSDavid du Colombier {
19689a747e4fSDavid du Colombier return n;
19699a747e4fSDavid du Colombier }
19709a747e4fSDavid du Colombier
19719a747e4fSDavid du Colombier static int
rc4enc(Secret * sec,uchar * buf,int n)19729a747e4fSDavid du Colombier rc4enc(Secret *sec, uchar *buf, int n)
19739a747e4fSDavid du Colombier {
19749a747e4fSDavid du Colombier rc4(sec->enckey, buf, n);
19759a747e4fSDavid du Colombier return n;
19769a747e4fSDavid du Colombier }
19779a747e4fSDavid du Colombier
19789a747e4fSDavid du Colombier static int
tlsunpad(uchar * buf,int n,int block)19799a747e4fSDavid du Colombier tlsunpad(uchar *buf, int n, int block)
19809a747e4fSDavid du Colombier {
19819a747e4fSDavid du Colombier int pad, nn;
19829a747e4fSDavid du Colombier
19839a747e4fSDavid du Colombier pad = buf[n - 1];
19849a747e4fSDavid du Colombier nn = n - 1 - pad;
19859a747e4fSDavid du Colombier if(nn <= 0 || n % block)
19869a747e4fSDavid du Colombier return -1;
19879a747e4fSDavid du Colombier while(--n > nn)
19889a747e4fSDavid du Colombier if(pad != buf[n - 1])
19899a747e4fSDavid du Colombier return -1;
19909a747e4fSDavid du Colombier return nn;
19919a747e4fSDavid du Colombier }
19929a747e4fSDavid du Colombier
19939a747e4fSDavid du Colombier static int
sslunpad(uchar * buf,int n,int block)19949a747e4fSDavid du Colombier sslunpad(uchar *buf, int n, int block)
19959a747e4fSDavid du Colombier {
19969a747e4fSDavid du Colombier int pad, nn;
19979a747e4fSDavid du Colombier
19989a747e4fSDavid du Colombier pad = buf[n - 1];
19999a747e4fSDavid du Colombier nn = n - 1 - pad;
20009a747e4fSDavid du Colombier if(nn <= 0 || n % block)
20019a747e4fSDavid du Colombier return -1;
20029a747e4fSDavid du Colombier return nn;
20039a747e4fSDavid du Colombier }
20049a747e4fSDavid du Colombier
20059a747e4fSDavid du Colombier static int
blockpad(uchar * buf,int n,int block)20069a747e4fSDavid du Colombier blockpad(uchar *buf, int n, int block)
20079a747e4fSDavid du Colombier {
20089a747e4fSDavid du Colombier int pad, nn;
20099a747e4fSDavid du Colombier
20109a747e4fSDavid du Colombier nn = n + block;
20119a747e4fSDavid du Colombier nn -= nn % block;
20129a747e4fSDavid du Colombier pad = nn - (n + 1);
20139a747e4fSDavid du Colombier while(n < nn)
20149a747e4fSDavid du Colombier buf[n++] = pad;
20159a747e4fSDavid du Colombier return nn;
20169a747e4fSDavid du Colombier }
20179a747e4fSDavid du Colombier
20189a747e4fSDavid du Colombier static int
des3enc(Secret * sec,uchar * buf,int n)20199a747e4fSDavid du Colombier des3enc(Secret *sec, uchar *buf, int n)
20209a747e4fSDavid du Colombier {
20219a747e4fSDavid du Colombier n = blockpad(buf, n, 8);
20229a747e4fSDavid du Colombier des3CBCencrypt(buf, n, sec->enckey);
20239a747e4fSDavid du Colombier return n;
20249a747e4fSDavid du Colombier }
20259a747e4fSDavid du Colombier
20269a747e4fSDavid du Colombier static int
des3dec(Secret * sec,uchar * buf,int n)20279a747e4fSDavid du Colombier des3dec(Secret *sec, uchar *buf, int n)
20289a747e4fSDavid du Colombier {
20299a747e4fSDavid du Colombier des3CBCdecrypt(buf, n, sec->enckey);
20309a747e4fSDavid du Colombier return (*sec->unpad)(buf, n, 8);
20319a747e4fSDavid du Colombier }
2032ad6ca847SDavid du Colombier
2033ad6ca847SDavid du Colombier static int
aesenc(Secret * sec,uchar * buf,int n)2034ad6ca847SDavid du Colombier aesenc(Secret *sec, uchar *buf, int n)
2035ad6ca847SDavid du Colombier {
2036ad6ca847SDavid du Colombier n = blockpad(buf, n, 16);
2037ad6ca847SDavid du Colombier aesCBCencrypt(buf, n, sec->enckey);
2038ad6ca847SDavid du Colombier return n;
2039ad6ca847SDavid du Colombier }
2040ad6ca847SDavid du Colombier
2041ad6ca847SDavid du Colombier static int
aesdec(Secret * sec,uchar * buf,int n)2042ad6ca847SDavid du Colombier aesdec(Secret *sec, uchar *buf, int n)
2043ad6ca847SDavid du Colombier {
2044ad6ca847SDavid du Colombier aesCBCdecrypt(buf, n, sec->enckey);
2045ad6ca847SDavid du Colombier return (*sec->unpad)(buf, n, 16);
2046ad6ca847SDavid du Colombier }
2047ad6ca847SDavid du Colombier
20489a747e4fSDavid du Colombier static DigestState*
nomac(uchar *,ulong,uchar *,ulong,uchar *,DigestState *)20499a747e4fSDavid du Colombier nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *)
20509a747e4fSDavid du Colombier {
20519a747e4fSDavid du Colombier return nil;
20529a747e4fSDavid du Colombier }
20539a747e4fSDavid du Colombier
20549a747e4fSDavid du Colombier /*
20559a747e4fSDavid du Colombier * sslmac: mac calculations for ssl 3.0 only; tls 1.0 uses the standard hmac.
20569a747e4fSDavid du Colombier */
20579a747e4fSDavid du Colombier 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)20589a747e4fSDavid du Colombier sslmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s,
20599a747e4fSDavid du Colombier DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen, int padlen)
20609a747e4fSDavid du Colombier {
20619a747e4fSDavid du Colombier int i;
20629a747e4fSDavid du Colombier uchar pad[48], innerdigest[20];
20639a747e4fSDavid du Colombier
20649a747e4fSDavid du Colombier if(xlen > sizeof(innerdigest)
20659a747e4fSDavid du Colombier || padlen > sizeof(pad))
20669a747e4fSDavid du Colombier return nil;
20679a747e4fSDavid du Colombier
20689a747e4fSDavid du Colombier if(klen>64)
20699a747e4fSDavid du Colombier return nil;
20709a747e4fSDavid du Colombier
20719a747e4fSDavid du Colombier /* first time through */
20729a747e4fSDavid du Colombier if(s == nil){
20739a747e4fSDavid du Colombier for(i=0; i<padlen; i++)
20749a747e4fSDavid du Colombier pad[i] = 0x36;
20759a747e4fSDavid du Colombier s = (*x)(key, klen, nil, nil);
20769a747e4fSDavid du Colombier s = (*x)(pad, padlen, nil, s);
20779a747e4fSDavid du Colombier if(s == nil)
20789a747e4fSDavid du Colombier return nil;
20799a747e4fSDavid du Colombier }
20809a747e4fSDavid du Colombier
20819a747e4fSDavid du Colombier s = (*x)(p, len, nil, s);
20829a747e4fSDavid du Colombier if(digest == nil)
20839a747e4fSDavid du Colombier return s;
20849a747e4fSDavid du Colombier
20859a747e4fSDavid du Colombier /* last time through */
20869a747e4fSDavid du Colombier for(i=0; i<padlen; i++)
20879a747e4fSDavid du Colombier pad[i] = 0x5c;
20889a747e4fSDavid du Colombier (*x)(nil, 0, innerdigest, s);
20899a747e4fSDavid du Colombier s = (*x)(key, klen, nil, nil);
20909a747e4fSDavid du Colombier s = (*x)(pad, padlen, nil, s);
20919a747e4fSDavid du Colombier (*x)(innerdigest, xlen, digest, s);
20929a747e4fSDavid du Colombier return nil;
20939a747e4fSDavid du Colombier }
20949a747e4fSDavid du Colombier
20959a747e4fSDavid du Colombier static DigestState*
sslmac_sha1(uchar * p,ulong len,uchar * key,ulong klen,uchar * digest,DigestState * s)20969a747e4fSDavid du Colombier sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
20979a747e4fSDavid du Colombier {
20989a747e4fSDavid du Colombier return sslmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen, 40);
20999a747e4fSDavid du Colombier }
21009a747e4fSDavid du Colombier
21019a747e4fSDavid du Colombier static DigestState*
sslmac_md5(uchar * p,ulong len,uchar * key,ulong klen,uchar * digest,DigestState * s)21029a747e4fSDavid du Colombier sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
21039a747e4fSDavid du Colombier {
21049a747e4fSDavid du Colombier return sslmac_x(p, len, key, klen, digest, s, md5, MD5dlen, 48);
21059a747e4fSDavid du Colombier }
21069a747e4fSDavid du Colombier
21079a747e4fSDavid du Colombier static void
sslPackMac(Secret * sec,uchar * mackey,uchar * seq,uchar * header,uchar * body,int len,uchar * mac)21089a747e4fSDavid du Colombier sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
21099a747e4fSDavid du Colombier {
21109a747e4fSDavid du Colombier DigestState *s;
21119a747e4fSDavid du Colombier uchar buf[11];
21129a747e4fSDavid du Colombier
21139a747e4fSDavid du Colombier memmove(buf, seq, 8);
21149a747e4fSDavid du Colombier buf[8] = header[0];
21159a747e4fSDavid du Colombier buf[9] = header[3];
21169a747e4fSDavid du Colombier buf[10] = header[4];
21179a747e4fSDavid du Colombier
21189a747e4fSDavid du Colombier s = (*sec->mac)(buf, 11, mackey, sec->maclen, 0, 0);
21199a747e4fSDavid du Colombier (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
21209a747e4fSDavid du Colombier }
21219a747e4fSDavid du Colombier
21229a747e4fSDavid du Colombier static void
tlsPackMac(Secret * sec,uchar * mackey,uchar * seq,uchar * header,uchar * body,int len,uchar * mac)21239a747e4fSDavid du Colombier tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
21249a747e4fSDavid du Colombier {
21259a747e4fSDavid du Colombier DigestState *s;
21269a747e4fSDavid du Colombier uchar buf[13];
21279a747e4fSDavid du Colombier
21289a747e4fSDavid du Colombier memmove(buf, seq, 8);
21299a747e4fSDavid du Colombier memmove(&buf[8], header, 5);
21309a747e4fSDavid du Colombier
21319a747e4fSDavid du Colombier s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0);
21329a747e4fSDavid du Colombier (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
21339a747e4fSDavid du Colombier }
21349a747e4fSDavid du Colombier
21359a747e4fSDavid du Colombier static void
put32(uchar * p,u32int x)21369a747e4fSDavid du Colombier put32(uchar *p, u32int x)
21379a747e4fSDavid du Colombier {
21389a747e4fSDavid du Colombier p[0] = x>>24;
21399a747e4fSDavid du Colombier p[1] = x>>16;
21409a747e4fSDavid du Colombier p[2] = x>>8;
21419a747e4fSDavid du Colombier p[3] = x;
21429a747e4fSDavid du Colombier }
21439a747e4fSDavid du Colombier
21449a747e4fSDavid du Colombier static void
put64(uchar * p,vlong x)21459a747e4fSDavid du Colombier put64(uchar *p, vlong x)
21469a747e4fSDavid du Colombier {
21479a747e4fSDavid du Colombier put32(p, (u32int)(x >> 32));
21489a747e4fSDavid du Colombier put32(p+4, (u32int)x);
21499a747e4fSDavid du Colombier }
21509a747e4fSDavid du Colombier
21519a747e4fSDavid du Colombier static void
put24(uchar * p,int x)21529a747e4fSDavid du Colombier put24(uchar *p, int x)
21539a747e4fSDavid du Colombier {
21549a747e4fSDavid du Colombier p[0] = x>>16;
21559a747e4fSDavid du Colombier p[1] = x>>8;
21569a747e4fSDavid du Colombier p[2] = x;
21579a747e4fSDavid du Colombier }
21589a747e4fSDavid du Colombier
21599a747e4fSDavid du Colombier static void
put16(uchar * p,int x)21609a747e4fSDavid du Colombier put16(uchar *p, int x)
21619a747e4fSDavid du Colombier {
21629a747e4fSDavid du Colombier p[0] = x>>8;
21639a747e4fSDavid du Colombier p[1] = x;
21649a747e4fSDavid du Colombier }
21659a747e4fSDavid du Colombier
21669a747e4fSDavid du Colombier static u32int
get32(uchar * p)21679a747e4fSDavid du Colombier get32(uchar *p)
21689a747e4fSDavid du Colombier {
21699a747e4fSDavid du Colombier return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
21709a747e4fSDavid du Colombier }
21719a747e4fSDavid du Colombier
21729a747e4fSDavid du Colombier static int
get16(uchar * p)21739a747e4fSDavid du Colombier get16(uchar *p)
21749a747e4fSDavid du Colombier {
21759a747e4fSDavid du Colombier return (p[0]<<8)|p[1];
21769a747e4fSDavid du Colombier }
21773751babcSDavid du Colombier
21783751babcSDavid du Colombier static char *charmap = "0123456789abcdef";
21793751babcSDavid du Colombier
21803751babcSDavid du Colombier static void
pdump(int len,void * a,char * tag)21813751babcSDavid du Colombier pdump(int len, void *a, char *tag)
21823751babcSDavid du Colombier {
21833751babcSDavid du Colombier uchar *p;
21843751babcSDavid du Colombier int i;
21853751babcSDavid du Colombier char buf[65+32];
21863751babcSDavid du Colombier char *q;
21873751babcSDavid du Colombier
21883751babcSDavid du Colombier p = a;
21893751babcSDavid du Colombier strcpy(buf, tag);
21903751babcSDavid du Colombier while(len > 0){
21913751babcSDavid du Colombier q = buf + strlen(tag);
21923751babcSDavid du Colombier for(i = 0; len > 0 && i < 32; i++){
21933751babcSDavid du Colombier if(*p >= ' ' && *p < 0x7f){
21943751babcSDavid du Colombier *q++ = ' ';
21953751babcSDavid du Colombier *q++ = *p;
21963751babcSDavid du Colombier } else {
21973751babcSDavid du Colombier *q++ = charmap[*p>>4];
21983751babcSDavid du Colombier *q++ = charmap[*p & 0xf];
21993751babcSDavid du Colombier }
22003751babcSDavid du Colombier len--;
22013751babcSDavid du Colombier p++;
22023751babcSDavid du Colombier }
22033751babcSDavid du Colombier *q = 0;
22043751babcSDavid du Colombier
22053751babcSDavid du Colombier if(len > 0)
22063751babcSDavid du Colombier pprint("%s...\n", buf);
22073751babcSDavid du Colombier else
22083751babcSDavid du Colombier pprint("%s\n", buf);
22093751babcSDavid du Colombier }
22103751babcSDavid du Colombier }
2211