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