1*1a4050f5SDavid du Colombier /* 2*1a4050f5SDavid du Colombier * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 3*1a4050f5SDavid du Colombier */ 4*1a4050f5SDavid du Colombier #include "u.h" 5*1a4050f5SDavid du Colombier #include "lib.h" 6*1a4050f5SDavid du Colombier #include "dat.h" 7*1a4050f5SDavid du Colombier #include "fns.h" 8*1a4050f5SDavid du Colombier #include "error.h" 9*1a4050f5SDavid du Colombier 10*1a4050f5SDavid du Colombier #include "libsec.h" 11*1a4050f5SDavid du Colombier 12*1a4050f5SDavid du Colombier typedef struct OneWay OneWay; 13*1a4050f5SDavid du Colombier typedef struct Secret Secret; 14*1a4050f5SDavid du Colombier typedef struct TlsRec TlsRec; 15*1a4050f5SDavid du Colombier typedef struct TlsErrs TlsErrs; 16*1a4050f5SDavid du Colombier 17*1a4050f5SDavid du Colombier enum { 18*1a4050f5SDavid du Colombier Statlen= 1024, /* max. length of status or stats message */ 19*1a4050f5SDavid du Colombier /* buffer limits */ 20*1a4050f5SDavid du Colombier MaxRecLen = 1<<14, /* max payload length of a record layer message */ 21*1a4050f5SDavid du Colombier MaxCipherRecLen = MaxRecLen + 2048, 22*1a4050f5SDavid du Colombier RecHdrLen = 5, 23*1a4050f5SDavid du Colombier MaxMacLen = SHA1dlen, 24*1a4050f5SDavid du Colombier 25*1a4050f5SDavid du Colombier /* protocol versions we can accept */ 26*1a4050f5SDavid du Colombier TLSVersion = 0x0301, 27*1a4050f5SDavid du Colombier SSL3Version = 0x0300, 28*1a4050f5SDavid du Colombier ProtocolVersion = 0x0301, /* maximum version we speak */ 29*1a4050f5SDavid du Colombier MinProtoVersion = 0x0300, /* limits on version we accept */ 30*1a4050f5SDavid du Colombier MaxProtoVersion = 0x03ff, 31*1a4050f5SDavid du Colombier 32*1a4050f5SDavid du Colombier /* connection states */ 33*1a4050f5SDavid du Colombier SHandshake = 1 << 0, /* doing handshake */ 34*1a4050f5SDavid du Colombier SOpen = 1 << 1, /* application data can be sent */ 35*1a4050f5SDavid du Colombier SRClose = 1 << 2, /* remote side has closed down */ 36*1a4050f5SDavid du Colombier SLClose = 1 << 3, /* sent a close notify alert */ 37*1a4050f5SDavid du Colombier SAlert = 1 << 5, /* sending or sent a fatal alert */ 38*1a4050f5SDavid du Colombier SError = 1 << 6, /* some sort of error has occured */ 39*1a4050f5SDavid du Colombier SClosed = 1 << 7, /* it is all over */ 40*1a4050f5SDavid du Colombier 41*1a4050f5SDavid du Colombier /* record types */ 42*1a4050f5SDavid du Colombier RChangeCipherSpec = 20, 43*1a4050f5SDavid du Colombier RAlert, 44*1a4050f5SDavid du Colombier RHandshake, 45*1a4050f5SDavid du Colombier RApplication, 46*1a4050f5SDavid du Colombier 47*1a4050f5SDavid du Colombier SSL2ClientHello = 1, 48*1a4050f5SDavid du Colombier HSSL2ClientHello = 9, /* local convention; see tlshand.c */ 49*1a4050f5SDavid du Colombier 50*1a4050f5SDavid du Colombier /* alerts */ 51*1a4050f5SDavid du Colombier ECloseNotify = 0, 52*1a4050f5SDavid du Colombier EUnexpectedMessage = 10, 53*1a4050f5SDavid du Colombier EBadRecordMac = 20, 54*1a4050f5SDavid du Colombier EDecryptionFailed = 21, 55*1a4050f5SDavid du Colombier ERecordOverflow = 22, 56*1a4050f5SDavid du Colombier EDecompressionFailure = 30, 57*1a4050f5SDavid du Colombier EHandshakeFailure = 40, 58*1a4050f5SDavid du Colombier ENoCertificate = 41, 59*1a4050f5SDavid du Colombier EBadCertificate = 42, 60*1a4050f5SDavid du Colombier EUnsupportedCertificate = 43, 61*1a4050f5SDavid du Colombier ECertificateRevoked = 44, 62*1a4050f5SDavid du Colombier ECertificateExpired = 45, 63*1a4050f5SDavid du Colombier ECertificateUnknown = 46, 64*1a4050f5SDavid du Colombier EIllegalParameter = 47, 65*1a4050f5SDavid du Colombier EUnknownCa = 48, 66*1a4050f5SDavid du Colombier EAccessDenied = 49, 67*1a4050f5SDavid du Colombier EDecodeError = 50, 68*1a4050f5SDavid du Colombier EDecryptError = 51, 69*1a4050f5SDavid du Colombier EExportRestriction = 60, 70*1a4050f5SDavid du Colombier EProtocolVersion = 70, 71*1a4050f5SDavid du Colombier EInsufficientSecurity = 71, 72*1a4050f5SDavid du Colombier EInternalError = 80, 73*1a4050f5SDavid du Colombier EUserCanceled = 90, 74*1a4050f5SDavid du Colombier ENoRenegotiation = 100, 75*1a4050f5SDavid du Colombier 76*1a4050f5SDavid du Colombier EMAX = 256 77*1a4050f5SDavid du Colombier }; 78*1a4050f5SDavid du Colombier 79*1a4050f5SDavid du Colombier struct Secret 80*1a4050f5SDavid du Colombier { 81*1a4050f5SDavid du Colombier char *encalg; /* name of encryption alg */ 82*1a4050f5SDavid du Colombier char *hashalg; /* name of hash alg */ 83*1a4050f5SDavid du Colombier int (*enc)(Secret*, uchar*, int); 84*1a4050f5SDavid du Colombier int (*dec)(Secret*, uchar*, int); 85*1a4050f5SDavid du Colombier int (*unpad)(uchar*, int, int); 86*1a4050f5SDavid du Colombier DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); 87*1a4050f5SDavid du Colombier int block; /* encryption block len, 0 if none */ 88*1a4050f5SDavid du Colombier int maclen; 89*1a4050f5SDavid du Colombier void *enckey; 90*1a4050f5SDavid du Colombier uchar mackey[MaxMacLen]; 91*1a4050f5SDavid du Colombier }; 92*1a4050f5SDavid du Colombier 93*1a4050f5SDavid du Colombier struct OneWay 94*1a4050f5SDavid du Colombier { 95*1a4050f5SDavid du Colombier QLock io; /* locks io access */ 96*1a4050f5SDavid du Colombier QLock seclock; /* locks secret paramaters */ 97*1a4050f5SDavid du Colombier ulong seq; 98*1a4050f5SDavid du Colombier Secret *sec; /* cipher in use */ 99*1a4050f5SDavid du Colombier Secret *new; /* cipher waiting for enable */ 100*1a4050f5SDavid du Colombier }; 101*1a4050f5SDavid du Colombier 102*1a4050f5SDavid du Colombier struct TlsRec 103*1a4050f5SDavid du Colombier { 104*1a4050f5SDavid du Colombier Chan *c; /* io channel */ 105*1a4050f5SDavid du Colombier int ref; /* serialized by tdlock for atomic destroy */ 106*1a4050f5SDavid du Colombier int version; /* version of the protocol we are speaking */ 107*1a4050f5SDavid du Colombier char verset; /* version has been set */ 108*1a4050f5SDavid du Colombier char opened; /* opened command every issued? */ 109*1a4050f5SDavid du Colombier char err[ERRMAX]; /* error message to return to handshake requests */ 110*1a4050f5SDavid du Colombier vlong handin; /* bytes communicated by the record layer */ 111*1a4050f5SDavid du Colombier vlong handout; 112*1a4050f5SDavid du Colombier vlong datain; 113*1a4050f5SDavid du Colombier vlong dataout; 114*1a4050f5SDavid du Colombier 115*1a4050f5SDavid du Colombier Lock statelk; 116*1a4050f5SDavid du Colombier int state; 117*1a4050f5SDavid du Colombier int debug; 118*1a4050f5SDavid du Colombier 119*1a4050f5SDavid du Colombier /* record layer mac functions for different protocol versions */ 120*1a4050f5SDavid du Colombier void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*); 121*1a4050f5SDavid du Colombier 122*1a4050f5SDavid du Colombier /* input side -- protected by in.io */ 123*1a4050f5SDavid du Colombier OneWay in; 124*1a4050f5SDavid du Colombier Block *processed; /* next bunch of application data */ 125*1a4050f5SDavid du Colombier Block *unprocessed; /* data read from c but not parsed into records */ 126*1a4050f5SDavid du Colombier 127*1a4050f5SDavid du Colombier /* handshake queue */ 128*1a4050f5SDavid du Colombier Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */ 129*1a4050f5SDavid du Colombier int hqref; 130*1a4050f5SDavid du Colombier Queue *handq; /* queue of handshake messages */ 131*1a4050f5SDavid du Colombier Block *hprocessed; /* remainder of last block read from handq */ 132*1a4050f5SDavid du Colombier QLock hqread; /* protects reads for hprocessed, handq */ 133*1a4050f5SDavid du Colombier 134*1a4050f5SDavid du Colombier /* output side */ 135*1a4050f5SDavid du Colombier OneWay out; 136*1a4050f5SDavid du Colombier 137*1a4050f5SDavid du Colombier /* protections */ 138*1a4050f5SDavid du Colombier char *user; 139*1a4050f5SDavid du Colombier int perm; 140*1a4050f5SDavid du Colombier }; 141*1a4050f5SDavid du Colombier 142*1a4050f5SDavid du Colombier struct TlsErrs{ 143*1a4050f5SDavid du Colombier int err; 144*1a4050f5SDavid du Colombier int sslerr; 145*1a4050f5SDavid du Colombier int tlserr; 146*1a4050f5SDavid du Colombier int fatal; 147*1a4050f5SDavid du Colombier char *msg; 148*1a4050f5SDavid du Colombier }; 149*1a4050f5SDavid du Colombier 150*1a4050f5SDavid du Colombier static TlsErrs tlserrs[] = { 151*1a4050f5SDavid du Colombier {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"}, 152*1a4050f5SDavid du Colombier {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"}, 153*1a4050f5SDavid du Colombier {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"}, 154*1a4050f5SDavid du Colombier {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"}, 155*1a4050f5SDavid du Colombier {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"}, 156*1a4050f5SDavid du Colombier {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"}, 157*1a4050f5SDavid du Colombier {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security parameters"}, 158*1a4050f5SDavid du Colombier {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"}, 159*1a4050f5SDavid du Colombier {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"}, 160*1a4050f5SDavid du Colombier {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"}, 161*1a4050f5SDavid du Colombier {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"}, 162*1a4050f5SDavid du Colombier {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"}, 163*1a4050f5SDavid du Colombier {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"}, 164*1a4050f5SDavid du Colombier {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"}, 165*1a4050f5SDavid du Colombier {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"}, 166*1a4050f5SDavid du Colombier {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"}, 167*1a4050f5SDavid du Colombier {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"}, 168*1a4050f5SDavid du Colombier {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"}, 169*1a4050f5SDavid du Colombier {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"}, 170*1a4050f5SDavid du Colombier {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"}, 171*1a4050f5SDavid du Colombier {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"}, 172*1a4050f5SDavid du Colombier {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"}, 173*1a4050f5SDavid du Colombier {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"}, 174*1a4050f5SDavid du Colombier {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"}, 175*1a4050f5SDavid du Colombier }; 176*1a4050f5SDavid du Colombier 177*1a4050f5SDavid du Colombier enum 178*1a4050f5SDavid du Colombier { 179*1a4050f5SDavid du Colombier /* max. open tls connections */ 180*1a4050f5SDavid du Colombier MaxTlsDevs = 1024 181*1a4050f5SDavid du Colombier }; 182*1a4050f5SDavid du Colombier 183*1a4050f5SDavid du Colombier static Lock tdlock; 184*1a4050f5SDavid du Colombier static int tdhiwat; 185*1a4050f5SDavid du Colombier static int maxtlsdevs = 128; 186*1a4050f5SDavid du Colombier static TlsRec **tlsdevs; 187*1a4050f5SDavid du Colombier static char **trnames; 188*1a4050f5SDavid du Colombier static char *encalgs; 189*1a4050f5SDavid du Colombier static char *hashalgs; 190*1a4050f5SDavid du Colombier 191*1a4050f5SDavid du Colombier enum{ 192*1a4050f5SDavid du Colombier Qtopdir = 1, /* top level directory */ 193*1a4050f5SDavid du Colombier Qprotodir, 194*1a4050f5SDavid du Colombier Qclonus, 195*1a4050f5SDavid du Colombier Qencalgs, 196*1a4050f5SDavid du Colombier Qhashalgs, 197*1a4050f5SDavid du Colombier Qconvdir, /* directory for a conversation */ 198*1a4050f5SDavid du Colombier Qdata, 199*1a4050f5SDavid du Colombier Qctl, 200*1a4050f5SDavid du Colombier Qhand, 201*1a4050f5SDavid du Colombier Qstatus, 202*1a4050f5SDavid du Colombier Qstats, 203*1a4050f5SDavid du Colombier }; 204*1a4050f5SDavid du Colombier 205*1a4050f5SDavid du Colombier #define TYPE(x) ((x).path & 0xf) 206*1a4050f5SDavid du Colombier #define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1)) 207*1a4050f5SDavid du Colombier #define QID(c, y) (((c)<<5) | (y)) 208*1a4050f5SDavid du Colombier 209*1a4050f5SDavid du Colombier static void checkstate(TlsRec *, int, int); 210*1a4050f5SDavid du Colombier static void ensure(TlsRec*, Block**, int); 211*1a4050f5SDavid du Colombier static void consume(Block**, uchar*, int); 212*1a4050f5SDavid du Colombier static Chan* buftochan(char*); 213*1a4050f5SDavid du Colombier static void tlshangup(TlsRec*); 214*1a4050f5SDavid du Colombier static void tlsError(TlsRec*, char *); 215*1a4050f5SDavid du Colombier static void alertHand(TlsRec*, char *); 216*1a4050f5SDavid du Colombier static TlsRec *newtls(Chan *c); 217*1a4050f5SDavid du Colombier static TlsRec *mktlsrec(void); 218*1a4050f5SDavid du Colombier static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); 219*1a4050f5SDavid du Colombier static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); 220*1a4050f5SDavid du Colombier static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); 221*1a4050f5SDavid du Colombier static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); 222*1a4050f5SDavid du Colombier static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); 223*1a4050f5SDavid du Colombier static void put64(uchar *p, vlong x); 224*1a4050f5SDavid du Colombier static void put32(uchar *p, u32int); 225*1a4050f5SDavid du Colombier static void put24(uchar *p, int); 226*1a4050f5SDavid du Colombier static void put16(uchar *p, int); 227*1a4050f5SDavid du Colombier static u32int get32(uchar *p); 228*1a4050f5SDavid du Colombier static int get16(uchar *p); 229*1a4050f5SDavid du Colombier static void tlsSetState(TlsRec *tr, int new, int old); 230*1a4050f5SDavid du Colombier static void rcvAlert(TlsRec *tr, int err); 231*1a4050f5SDavid du Colombier static void sendAlert(TlsRec *tr, int err); 232*1a4050f5SDavid du Colombier static void rcvError(TlsRec *tr, int err, char *msg, ...); 233*1a4050f5SDavid du Colombier static int rc4enc(Secret *sec, uchar *buf, int n); 234*1a4050f5SDavid du Colombier static int des3enc(Secret *sec, uchar *buf, int n); 235*1a4050f5SDavid du Colombier static int des3dec(Secret *sec, uchar *buf, int n); 236*1a4050f5SDavid du Colombier static int noenc(Secret *sec, uchar *buf, int n); 237*1a4050f5SDavid du Colombier static int sslunpad(uchar *buf, int n, int block); 238*1a4050f5SDavid du Colombier static int tlsunpad(uchar *buf, int n, int block); 239*1a4050f5SDavid du Colombier static void freeSec(Secret *sec); 240*1a4050f5SDavid du Colombier static char *tlsstate(int s); 241*1a4050f5SDavid du Colombier static void pdump(int, void*, char*); 242*1a4050f5SDavid du Colombier 243*1a4050f5SDavid du Colombier static char *tlsnames[] = { 244*1a4050f5SDavid du Colombier [Qclonus] "clone", 245*1a4050f5SDavid du Colombier [Qencalgs] "encalgs", 246*1a4050f5SDavid du Colombier [Qhashalgs] "hashalgs", 247*1a4050f5SDavid du Colombier [Qdata] "data", 248*1a4050f5SDavid du Colombier [Qctl] "ctl", 249*1a4050f5SDavid du Colombier [Qhand] "hand", 250*1a4050f5SDavid du Colombier [Qstatus] "status", 251*1a4050f5SDavid du Colombier [Qstats] "stats", 252*1a4050f5SDavid du Colombier }; 253*1a4050f5SDavid du Colombier 254*1a4050f5SDavid du Colombier static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats }; 255*1a4050f5SDavid du Colombier 256*1a4050f5SDavid du Colombier static int 257*1a4050f5SDavid du Colombier tlsgen(Chan *c, char*unused1, Dirtab *unused2, int unused3, int s, Dir *dp) 258*1a4050f5SDavid du Colombier { 259*1a4050f5SDavid du Colombier Qid q; 260*1a4050f5SDavid du Colombier TlsRec *tr; 261*1a4050f5SDavid du Colombier char *name, *nm; 262*1a4050f5SDavid du Colombier int perm, t; 263*1a4050f5SDavid du Colombier 264*1a4050f5SDavid du Colombier q.vers = 0; 265*1a4050f5SDavid du Colombier q.type = QTFILE; 266*1a4050f5SDavid du Colombier 267*1a4050f5SDavid du Colombier t = TYPE(c->qid); 268*1a4050f5SDavid du Colombier switch(t) { 269*1a4050f5SDavid du Colombier case Qtopdir: 270*1a4050f5SDavid du Colombier if(s == DEVDOTDOT){ 271*1a4050f5SDavid du Colombier q.path = QID(0, Qtopdir); 272*1a4050f5SDavid du Colombier q.type = QTDIR; 273*1a4050f5SDavid du Colombier devdir(c, q, "#a", 0, eve, 0555, dp); 274*1a4050f5SDavid du Colombier return 1; 275*1a4050f5SDavid du Colombier } 276*1a4050f5SDavid du Colombier if(s > 0) 277*1a4050f5SDavid du Colombier return -1; 278*1a4050f5SDavid du Colombier q.path = QID(0, Qprotodir); 279*1a4050f5SDavid du Colombier q.type = QTDIR; 280*1a4050f5SDavid du Colombier devdir(c, q, "tls", 0, eve, 0555, dp); 281*1a4050f5SDavid du Colombier return 1; 282*1a4050f5SDavid du Colombier case Qprotodir: 283*1a4050f5SDavid du Colombier if(s == DEVDOTDOT){ 284*1a4050f5SDavid du Colombier q.path = QID(0, Qtopdir); 285*1a4050f5SDavid du Colombier q.type = QTDIR; 286*1a4050f5SDavid du Colombier devdir(c, q, ".", 0, eve, 0555, dp); 287*1a4050f5SDavid du Colombier return 1; 288*1a4050f5SDavid du Colombier } 289*1a4050f5SDavid du Colombier if(s < 3){ 290*1a4050f5SDavid du Colombier switch(s) { 291*1a4050f5SDavid du Colombier default: 292*1a4050f5SDavid du Colombier return -1; 293*1a4050f5SDavid du Colombier case 0: 294*1a4050f5SDavid du Colombier q.path = QID(0, Qclonus); 295*1a4050f5SDavid du Colombier break; 296*1a4050f5SDavid du Colombier case 1: 297*1a4050f5SDavid du Colombier q.path = QID(0, Qencalgs); 298*1a4050f5SDavid du Colombier break; 299*1a4050f5SDavid du Colombier case 2: 300*1a4050f5SDavid du Colombier q.path = QID(0, Qhashalgs); 301*1a4050f5SDavid du Colombier break; 302*1a4050f5SDavid du Colombier } 303*1a4050f5SDavid du Colombier perm = 0444; 304*1a4050f5SDavid du Colombier if(TYPE(q) == Qclonus) 305*1a4050f5SDavid du Colombier perm = 0555; 306*1a4050f5SDavid du Colombier devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp); 307*1a4050f5SDavid du Colombier return 1; 308*1a4050f5SDavid du Colombier } 309*1a4050f5SDavid du Colombier s -= 3; 310*1a4050f5SDavid du Colombier if(s >= tdhiwat) 311*1a4050f5SDavid du Colombier return -1; 312*1a4050f5SDavid du Colombier q.path = QID(s, Qconvdir); 313*1a4050f5SDavid du Colombier q.type = QTDIR; 314*1a4050f5SDavid du Colombier lock(&tdlock); 315*1a4050f5SDavid du Colombier tr = tlsdevs[s]; 316*1a4050f5SDavid du Colombier if(tr != nil) 317*1a4050f5SDavid du Colombier nm = tr->user; 318*1a4050f5SDavid du Colombier else 319*1a4050f5SDavid du Colombier nm = eve; 320*1a4050f5SDavid du Colombier if((name = trnames[s]) == nil){ 321*1a4050f5SDavid du Colombier name = trnames[s] = smalloc(16); 322*1a4050f5SDavid du Colombier sprint(name, "%d", s); 323*1a4050f5SDavid du Colombier } 324*1a4050f5SDavid du Colombier devdir(c, q, name, 0, nm, 0555, dp); 325*1a4050f5SDavid du Colombier unlock(&tdlock); 326*1a4050f5SDavid du Colombier return 1; 327*1a4050f5SDavid du Colombier case Qconvdir: 328*1a4050f5SDavid du Colombier if(s == DEVDOTDOT){ 329*1a4050f5SDavid du Colombier q.path = QID(0, Qprotodir); 330*1a4050f5SDavid du Colombier q.type = QTDIR; 331*1a4050f5SDavid du Colombier devdir(c, q, "tls", 0, eve, 0555, dp); 332*1a4050f5SDavid du Colombier return 1; 333*1a4050f5SDavid du Colombier } 334*1a4050f5SDavid du Colombier if(s < 0 || s >= nelem(convdir)) 335*1a4050f5SDavid du Colombier return -1; 336*1a4050f5SDavid du Colombier lock(&tdlock); 337*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 338*1a4050f5SDavid du Colombier if(tr != nil){ 339*1a4050f5SDavid du Colombier nm = tr->user; 340*1a4050f5SDavid du Colombier perm = tr->perm; 341*1a4050f5SDavid du Colombier }else{ 342*1a4050f5SDavid du Colombier perm = 0; 343*1a4050f5SDavid du Colombier nm = eve; 344*1a4050f5SDavid du Colombier } 345*1a4050f5SDavid du Colombier t = convdir[s]; 346*1a4050f5SDavid du Colombier if(t == Qstatus || t == Qstats) 347*1a4050f5SDavid du Colombier perm &= 0444; 348*1a4050f5SDavid du Colombier q.path = QID(CONV(c->qid), t); 349*1a4050f5SDavid du Colombier devdir(c, q, tlsnames[t], 0, nm, perm, dp); 350*1a4050f5SDavid du Colombier unlock(&tdlock); 351*1a4050f5SDavid du Colombier return 1; 352*1a4050f5SDavid du Colombier case Qclonus: 353*1a4050f5SDavid du Colombier case Qencalgs: 354*1a4050f5SDavid du Colombier case Qhashalgs: 355*1a4050f5SDavid du Colombier perm = 0444; 356*1a4050f5SDavid du Colombier if(t == Qclonus) 357*1a4050f5SDavid du Colombier perm = 0555; 358*1a4050f5SDavid du Colombier devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp); 359*1a4050f5SDavid du Colombier return 1; 360*1a4050f5SDavid du Colombier default: 361*1a4050f5SDavid du Colombier lock(&tdlock); 362*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 363*1a4050f5SDavid du Colombier if(tr != nil){ 364*1a4050f5SDavid du Colombier nm = tr->user; 365*1a4050f5SDavid du Colombier perm = tr->perm; 366*1a4050f5SDavid du Colombier }else{ 367*1a4050f5SDavid du Colombier perm = 0; 368*1a4050f5SDavid du Colombier nm = eve; 369*1a4050f5SDavid du Colombier } 370*1a4050f5SDavid du Colombier if(t == Qstatus || t == Qstats) 371*1a4050f5SDavid du Colombier perm &= 0444; 372*1a4050f5SDavid du Colombier devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp); 373*1a4050f5SDavid du Colombier unlock(&tdlock); 374*1a4050f5SDavid du Colombier return 1; 375*1a4050f5SDavid du Colombier } 376*1a4050f5SDavid du Colombier return -1; 377*1a4050f5SDavid du Colombier } 378*1a4050f5SDavid du Colombier 379*1a4050f5SDavid du Colombier static Chan* 380*1a4050f5SDavid du Colombier tlsattach(char *spec) 381*1a4050f5SDavid du Colombier { 382*1a4050f5SDavid du Colombier Chan *c; 383*1a4050f5SDavid du Colombier 384*1a4050f5SDavid du Colombier c = devattach('a', spec); 385*1a4050f5SDavid du Colombier c->qid.path = QID(0, Qtopdir); 386*1a4050f5SDavid du Colombier c->qid.type = QTDIR; 387*1a4050f5SDavid du Colombier c->qid.vers = 0; 388*1a4050f5SDavid du Colombier return c; 389*1a4050f5SDavid du Colombier } 390*1a4050f5SDavid du Colombier 391*1a4050f5SDavid du Colombier static Walkqid* 392*1a4050f5SDavid du Colombier tlswalk(Chan *c, Chan *nc, char **name, int nname) 393*1a4050f5SDavid du Colombier { 394*1a4050f5SDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, tlsgen); 395*1a4050f5SDavid du Colombier } 396*1a4050f5SDavid du Colombier 397*1a4050f5SDavid du Colombier static int 398*1a4050f5SDavid du Colombier tlsstat(Chan *c, uchar *db, int n) 399*1a4050f5SDavid du Colombier { 400*1a4050f5SDavid du Colombier return devstat(c, db, n, nil, 0, tlsgen); 401*1a4050f5SDavid du Colombier } 402*1a4050f5SDavid du Colombier 403*1a4050f5SDavid du Colombier static Chan* 404*1a4050f5SDavid du Colombier tlsopen(Chan *c, int omode) 405*1a4050f5SDavid du Colombier { 406*1a4050f5SDavid du Colombier TlsRec *tr, **pp; 407*1a4050f5SDavid du Colombier int t, perm; 408*1a4050f5SDavid du Colombier 409*1a4050f5SDavid du Colombier perm = 0; 410*1a4050f5SDavid du Colombier omode &= 3; 411*1a4050f5SDavid du Colombier switch(omode) { 412*1a4050f5SDavid du Colombier case OREAD: 413*1a4050f5SDavid du Colombier perm = 4; 414*1a4050f5SDavid du Colombier break; 415*1a4050f5SDavid du Colombier case OWRITE: 416*1a4050f5SDavid du Colombier perm = 2; 417*1a4050f5SDavid du Colombier break; 418*1a4050f5SDavid du Colombier case ORDWR: 419*1a4050f5SDavid du Colombier perm = 6; 420*1a4050f5SDavid du Colombier break; 421*1a4050f5SDavid du Colombier } 422*1a4050f5SDavid du Colombier 423*1a4050f5SDavid du Colombier t = TYPE(c->qid); 424*1a4050f5SDavid du Colombier switch(t) { 425*1a4050f5SDavid du Colombier default: 426*1a4050f5SDavid du Colombier panic("tlsopen"); 427*1a4050f5SDavid du Colombier case Qtopdir: 428*1a4050f5SDavid du Colombier case Qprotodir: 429*1a4050f5SDavid du Colombier case Qconvdir: 430*1a4050f5SDavid du Colombier if(omode != OREAD) 431*1a4050f5SDavid du Colombier error(Eperm); 432*1a4050f5SDavid du Colombier break; 433*1a4050f5SDavid du Colombier case Qclonus: 434*1a4050f5SDavid du Colombier tr = newtls(c); 435*1a4050f5SDavid du Colombier if(tr == nil) 436*1a4050f5SDavid du Colombier error(Enodev); 437*1a4050f5SDavid du Colombier break; 438*1a4050f5SDavid du Colombier case Qctl: 439*1a4050f5SDavid du Colombier case Qdata: 440*1a4050f5SDavid du Colombier case Qhand: 441*1a4050f5SDavid du Colombier case Qstatus: 442*1a4050f5SDavid du Colombier case Qstats: 443*1a4050f5SDavid du Colombier if((t == Qstatus || t == Qstats) && omode != OREAD) 444*1a4050f5SDavid du Colombier error(Eperm); 445*1a4050f5SDavid du Colombier if(waserror()) { 446*1a4050f5SDavid du Colombier unlock(&tdlock); 447*1a4050f5SDavid du Colombier nexterror(); 448*1a4050f5SDavid du Colombier } 449*1a4050f5SDavid du Colombier lock(&tdlock); 450*1a4050f5SDavid du Colombier pp = &tlsdevs[CONV(c->qid)]; 451*1a4050f5SDavid du Colombier tr = *pp; 452*1a4050f5SDavid du Colombier if(tr == nil) 453*1a4050f5SDavid du Colombier error("must open connection using clone"); 454*1a4050f5SDavid du Colombier if((perm & (tr->perm>>6)) != perm 455*1a4050f5SDavid du Colombier && (strcmp(up->user, tr->user) != 0 456*1a4050f5SDavid du Colombier || (perm & tr->perm) != perm)) 457*1a4050f5SDavid du Colombier error(Eperm); 458*1a4050f5SDavid du Colombier if(t == Qhand){ 459*1a4050f5SDavid du Colombier if(waserror()){ 460*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 461*1a4050f5SDavid du Colombier nexterror(); 462*1a4050f5SDavid du Colombier } 463*1a4050f5SDavid du Colombier lock(&tr->hqlock); 464*1a4050f5SDavid du Colombier if(tr->handq != nil) 465*1a4050f5SDavid du Colombier error(Einuse); 466*1a4050f5SDavid du Colombier tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil); 467*1a4050f5SDavid du Colombier if(tr->handq == nil) 468*1a4050f5SDavid du Colombier error("cannot allocate handshake queue"); 469*1a4050f5SDavid du Colombier tr->hqref = 1; 470*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 471*1a4050f5SDavid du Colombier poperror(); 472*1a4050f5SDavid du Colombier } 473*1a4050f5SDavid du Colombier tr->ref++; 474*1a4050f5SDavid du Colombier unlock(&tdlock); 475*1a4050f5SDavid du Colombier poperror(); 476*1a4050f5SDavid du Colombier break; 477*1a4050f5SDavid du Colombier case Qencalgs: 478*1a4050f5SDavid du Colombier case Qhashalgs: 479*1a4050f5SDavid du Colombier if(omode != OREAD) 480*1a4050f5SDavid du Colombier error(Eperm); 481*1a4050f5SDavid du Colombier break; 482*1a4050f5SDavid du Colombier } 483*1a4050f5SDavid du Colombier c->mode = openmode(omode); 484*1a4050f5SDavid du Colombier c->flag |= COPEN; 485*1a4050f5SDavid du Colombier c->offset = 0; 486*1a4050f5SDavid du Colombier c->iounit = qiomaxatomic; 487*1a4050f5SDavid du Colombier return c; 488*1a4050f5SDavid du Colombier } 489*1a4050f5SDavid du Colombier 490*1a4050f5SDavid du Colombier static int 491*1a4050f5SDavid du Colombier tlswstat(Chan *c, uchar *dp, int n) 492*1a4050f5SDavid du Colombier { 493*1a4050f5SDavid du Colombier Dir *d; 494*1a4050f5SDavid du Colombier TlsRec *tr; 495*1a4050f5SDavid du Colombier int rv; 496*1a4050f5SDavid du Colombier 497*1a4050f5SDavid du Colombier d = nil; 498*1a4050f5SDavid du Colombier if(waserror()){ 499*1a4050f5SDavid du Colombier free(d); 500*1a4050f5SDavid du Colombier unlock(&tdlock); 501*1a4050f5SDavid du Colombier nexterror(); 502*1a4050f5SDavid du Colombier } 503*1a4050f5SDavid du Colombier 504*1a4050f5SDavid du Colombier lock(&tdlock); 505*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 506*1a4050f5SDavid du Colombier if(tr == nil) 507*1a4050f5SDavid du Colombier error(Ebadusefd); 508*1a4050f5SDavid du Colombier if(strcmp(tr->user, up->user) != 0) 509*1a4050f5SDavid du Colombier error(Eperm); 510*1a4050f5SDavid du Colombier 511*1a4050f5SDavid du Colombier d = smalloc(n + sizeof *d); 512*1a4050f5SDavid du Colombier rv = convM2D(dp, n, &d[0], (char*) &d[1]); 513*1a4050f5SDavid du Colombier if(rv == 0) 514*1a4050f5SDavid du Colombier error(Eshortstat); 515*1a4050f5SDavid du Colombier if(!emptystr(d->uid)) 516*1a4050f5SDavid du Colombier kstrdup(&tr->user, d->uid); 517*1a4050f5SDavid du Colombier if(d->mode != ~0UL) 518*1a4050f5SDavid du Colombier tr->perm = d->mode; 519*1a4050f5SDavid du Colombier 520*1a4050f5SDavid du Colombier free(d); 521*1a4050f5SDavid du Colombier poperror(); 522*1a4050f5SDavid du Colombier unlock(&tdlock); 523*1a4050f5SDavid du Colombier 524*1a4050f5SDavid du Colombier return rv; 525*1a4050f5SDavid du Colombier } 526*1a4050f5SDavid du Colombier 527*1a4050f5SDavid du Colombier static void 528*1a4050f5SDavid du Colombier dechandq(TlsRec *tr) 529*1a4050f5SDavid du Colombier { 530*1a4050f5SDavid du Colombier lock(&tr->hqlock); 531*1a4050f5SDavid du Colombier if(--tr->hqref == 0){ 532*1a4050f5SDavid du Colombier if(tr->handq != nil){ 533*1a4050f5SDavid du Colombier qfree(tr->handq); 534*1a4050f5SDavid du Colombier tr->handq = nil; 535*1a4050f5SDavid du Colombier } 536*1a4050f5SDavid du Colombier if(tr->hprocessed != nil){ 537*1a4050f5SDavid du Colombier freeb(tr->hprocessed); 538*1a4050f5SDavid du Colombier tr->hprocessed = nil; 539*1a4050f5SDavid du Colombier } 540*1a4050f5SDavid du Colombier } 541*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 542*1a4050f5SDavid du Colombier } 543*1a4050f5SDavid du Colombier 544*1a4050f5SDavid du Colombier static void 545*1a4050f5SDavid du Colombier tlsclose(Chan *c) 546*1a4050f5SDavid du Colombier { 547*1a4050f5SDavid du Colombier TlsRec *tr; 548*1a4050f5SDavid du Colombier int t; 549*1a4050f5SDavid du Colombier 550*1a4050f5SDavid du Colombier t = TYPE(c->qid); 551*1a4050f5SDavid du Colombier switch(t) { 552*1a4050f5SDavid du Colombier case Qctl: 553*1a4050f5SDavid du Colombier case Qdata: 554*1a4050f5SDavid du Colombier case Qhand: 555*1a4050f5SDavid du Colombier case Qstatus: 556*1a4050f5SDavid du Colombier case Qstats: 557*1a4050f5SDavid du Colombier if((c->flag & COPEN) == 0) 558*1a4050f5SDavid du Colombier break; 559*1a4050f5SDavid du Colombier 560*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 561*1a4050f5SDavid du Colombier if(tr == nil) 562*1a4050f5SDavid du Colombier break; 563*1a4050f5SDavid du Colombier 564*1a4050f5SDavid du Colombier if(t == Qhand) 565*1a4050f5SDavid du Colombier dechandq(tr); 566*1a4050f5SDavid du Colombier 567*1a4050f5SDavid du Colombier lock(&tdlock); 568*1a4050f5SDavid du Colombier if(--tr->ref > 0) { 569*1a4050f5SDavid du Colombier unlock(&tdlock); 570*1a4050f5SDavid du Colombier return; 571*1a4050f5SDavid du Colombier } 572*1a4050f5SDavid du Colombier tlsdevs[CONV(c->qid)] = nil; 573*1a4050f5SDavid du Colombier unlock(&tdlock); 574*1a4050f5SDavid du Colombier 575*1a4050f5SDavid du Colombier if(tr->c != nil && !waserror()){ 576*1a4050f5SDavid du Colombier checkstate(tr, 0, SOpen|SHandshake|SRClose); 577*1a4050f5SDavid du Colombier sendAlert(tr, ECloseNotify); 578*1a4050f5SDavid du Colombier poperror(); 579*1a4050f5SDavid du Colombier } 580*1a4050f5SDavid du Colombier tlshangup(tr); 581*1a4050f5SDavid du Colombier if(tr->c != nil) 582*1a4050f5SDavid du Colombier cclose(tr->c); 583*1a4050f5SDavid du Colombier freeSec(tr->in.sec); 584*1a4050f5SDavid du Colombier freeSec(tr->in.new); 585*1a4050f5SDavid du Colombier freeSec(tr->out.sec); 586*1a4050f5SDavid du Colombier freeSec(tr->out.new); 587*1a4050f5SDavid du Colombier free(tr->user); 588*1a4050f5SDavid du Colombier free(tr); 589*1a4050f5SDavid du Colombier break; 590*1a4050f5SDavid du Colombier } 591*1a4050f5SDavid du Colombier } 592*1a4050f5SDavid du Colombier 593*1a4050f5SDavid du Colombier /* 594*1a4050f5SDavid du Colombier * make sure we have at least 'n' bytes in list 'l' 595*1a4050f5SDavid du Colombier */ 596*1a4050f5SDavid du Colombier static void 597*1a4050f5SDavid du Colombier ensure(TlsRec *s, Block **l, int n) 598*1a4050f5SDavid du Colombier { 599*1a4050f5SDavid du Colombier int sofar, i; 600*1a4050f5SDavid du Colombier Block *b, *bl; 601*1a4050f5SDavid du Colombier 602*1a4050f5SDavid du Colombier sofar = 0; 603*1a4050f5SDavid du Colombier for(b = *l; b; b = b->next){ 604*1a4050f5SDavid du Colombier sofar += BLEN(b); 605*1a4050f5SDavid du Colombier if(sofar >= n) 606*1a4050f5SDavid du Colombier return; 607*1a4050f5SDavid du Colombier l = &b->next; 608*1a4050f5SDavid du Colombier } 609*1a4050f5SDavid du Colombier 610*1a4050f5SDavid du Colombier while(sofar < n){ 611*1a4050f5SDavid du Colombier bl = devtab[s->c->type]->bread(s->c, MaxCipherRecLen + RecHdrLen, 0); 612*1a4050f5SDavid du Colombier if(bl == 0) 613*1a4050f5SDavid du Colombier error(Ehungup); 614*1a4050f5SDavid du Colombier *l = bl; 615*1a4050f5SDavid du Colombier i = 0; 616*1a4050f5SDavid du Colombier for(b = bl; b; b = b->next){ 617*1a4050f5SDavid du Colombier i += BLEN(b); 618*1a4050f5SDavid du Colombier l = &b->next; 619*1a4050f5SDavid du Colombier } 620*1a4050f5SDavid du Colombier if(i == 0) 621*1a4050f5SDavid du Colombier error(Ehungup); 622*1a4050f5SDavid du Colombier sofar += i; 623*1a4050f5SDavid du Colombier } 624*1a4050f5SDavid du Colombier if(s->debug) pprint("ensure read %d\n", sofar); 625*1a4050f5SDavid du Colombier } 626*1a4050f5SDavid du Colombier 627*1a4050f5SDavid du Colombier /* 628*1a4050f5SDavid du Colombier * copy 'n' bytes from 'l' into 'p' and free 629*1a4050f5SDavid du Colombier * the bytes in 'l' 630*1a4050f5SDavid du Colombier */ 631*1a4050f5SDavid du Colombier static void 632*1a4050f5SDavid du Colombier consume(Block **l, uchar *p, int n) 633*1a4050f5SDavid du Colombier { 634*1a4050f5SDavid du Colombier Block *b; 635*1a4050f5SDavid du Colombier int i; 636*1a4050f5SDavid du Colombier 637*1a4050f5SDavid du Colombier for(; *l && n > 0; n -= i){ 638*1a4050f5SDavid du Colombier b = *l; 639*1a4050f5SDavid du Colombier i = BLEN(b); 640*1a4050f5SDavid du Colombier if(i > n) 641*1a4050f5SDavid du Colombier i = n; 642*1a4050f5SDavid du Colombier memmove(p, b->rp, i); 643*1a4050f5SDavid du Colombier b->rp += i; 644*1a4050f5SDavid du Colombier p += i; 645*1a4050f5SDavid du Colombier if(BLEN(b) < 0) 646*1a4050f5SDavid du Colombier panic("consume"); 647*1a4050f5SDavid du Colombier if(BLEN(b)) 648*1a4050f5SDavid du Colombier break; 649*1a4050f5SDavid du Colombier *l = b->next; 650*1a4050f5SDavid du Colombier freeb(b); 651*1a4050f5SDavid du Colombier } 652*1a4050f5SDavid du Colombier } 653*1a4050f5SDavid du Colombier 654*1a4050f5SDavid du Colombier /* 655*1a4050f5SDavid du Colombier * give back n bytes 656*1a4050f5SDavid du Colombier */ 657*1a4050f5SDavid du Colombier static void 658*1a4050f5SDavid du Colombier regurgitate(TlsRec *s, uchar *p, int n) 659*1a4050f5SDavid du Colombier { 660*1a4050f5SDavid du Colombier Block *b; 661*1a4050f5SDavid du Colombier 662*1a4050f5SDavid du Colombier if(n <= 0) 663*1a4050f5SDavid du Colombier return; 664*1a4050f5SDavid du Colombier b = s->unprocessed; 665*1a4050f5SDavid du Colombier if(s->unprocessed == nil || b->rp - b->base < n) { 666*1a4050f5SDavid du Colombier b = allocb(n); 667*1a4050f5SDavid du Colombier memmove(b->wp, p, n); 668*1a4050f5SDavid du Colombier b->wp += n; 669*1a4050f5SDavid du Colombier b->next = s->unprocessed; 670*1a4050f5SDavid du Colombier s->unprocessed = b; 671*1a4050f5SDavid du Colombier } else { 672*1a4050f5SDavid du Colombier b->rp -= n; 673*1a4050f5SDavid du Colombier memmove(b->rp, p, n); 674*1a4050f5SDavid du Colombier } 675*1a4050f5SDavid du Colombier } 676*1a4050f5SDavid du Colombier 677*1a4050f5SDavid du Colombier /* 678*1a4050f5SDavid du Colombier * remove at most n bytes from the queue 679*1a4050f5SDavid du Colombier */ 680*1a4050f5SDavid du Colombier static Block* 681*1a4050f5SDavid du Colombier qgrab(Block **l, int n) 682*1a4050f5SDavid du Colombier { 683*1a4050f5SDavid du Colombier Block *bb, *b; 684*1a4050f5SDavid du Colombier int i; 685*1a4050f5SDavid du Colombier 686*1a4050f5SDavid du Colombier b = *l; 687*1a4050f5SDavid du Colombier if(BLEN(b) == n){ 688*1a4050f5SDavid du Colombier *l = b->next; 689*1a4050f5SDavid du Colombier b->next = nil; 690*1a4050f5SDavid du Colombier return b; 691*1a4050f5SDavid du Colombier } 692*1a4050f5SDavid du Colombier 693*1a4050f5SDavid du Colombier i = 0; 694*1a4050f5SDavid du Colombier for(bb = b; bb != nil && i < n; bb = bb->next) 695*1a4050f5SDavid du Colombier i += BLEN(bb); 696*1a4050f5SDavid du Colombier if(i > n) 697*1a4050f5SDavid du Colombier i = n; 698*1a4050f5SDavid du Colombier 699*1a4050f5SDavid du Colombier bb = allocb(i); 700*1a4050f5SDavid du Colombier consume(l, bb->wp, i); 701*1a4050f5SDavid du Colombier bb->wp += i; 702*1a4050f5SDavid du Colombier return bb; 703*1a4050f5SDavid du Colombier } 704*1a4050f5SDavid du Colombier 705*1a4050f5SDavid du Colombier static void 706*1a4050f5SDavid du Colombier tlsclosed(TlsRec *tr, int new) 707*1a4050f5SDavid du Colombier { 708*1a4050f5SDavid du Colombier lock(&tr->statelk); 709*1a4050f5SDavid du Colombier if(tr->state == SOpen || tr->state == SHandshake) 710*1a4050f5SDavid du Colombier tr->state = new; 711*1a4050f5SDavid du Colombier else if((new | tr->state) == (SRClose|SLClose)) 712*1a4050f5SDavid du Colombier tr->state = SClosed; 713*1a4050f5SDavid du Colombier unlock(&tr->statelk); 714*1a4050f5SDavid du Colombier alertHand(tr, "close notify"); 715*1a4050f5SDavid du Colombier } 716*1a4050f5SDavid du Colombier 717*1a4050f5SDavid du Colombier /* 718*1a4050f5SDavid du Colombier * read and process one tls record layer message 719*1a4050f5SDavid du Colombier * must be called with tr->in.io held 720*1a4050f5SDavid du Colombier * We can't let Eintrs lose data, since doing so will get 721*1a4050f5SDavid du Colombier * us out of sync with the sender and break the reliablity 722*1a4050f5SDavid du Colombier * of the channel. Eintr only happens during the reads in 723*1a4050f5SDavid du Colombier * consume. Therefore we put back any bytes consumed before 724*1a4050f5SDavid du Colombier * the last call to ensure. 725*1a4050f5SDavid du Colombier */ 726*1a4050f5SDavid du Colombier static void 727*1a4050f5SDavid du Colombier tlsrecread(TlsRec *tr) 728*1a4050f5SDavid du Colombier { 729*1a4050f5SDavid du Colombier OneWay *volatile in; 730*1a4050f5SDavid du Colombier Block *volatile b; 731*1a4050f5SDavid du Colombier uchar *p, seq[8], header[RecHdrLen], hmac[MD5dlen]; 732*1a4050f5SDavid du Colombier int volatile nconsumed; 733*1a4050f5SDavid du Colombier int len, type, ver, unpad_len; 734*1a4050f5SDavid du Colombier 735*1a4050f5SDavid du Colombier nconsumed = 0; 736*1a4050f5SDavid du Colombier if(waserror()){ 737*1a4050f5SDavid du Colombier if(strcmp(up->errstr, Eintr) == 0 && !waserror()){ 738*1a4050f5SDavid du Colombier regurgitate(tr, header, nconsumed); 739*1a4050f5SDavid du Colombier poperror(); 740*1a4050f5SDavid du Colombier }else 741*1a4050f5SDavid du Colombier tlsError(tr, "channel error"); 742*1a4050f5SDavid du Colombier nexterror(); 743*1a4050f5SDavid du Colombier } 744*1a4050f5SDavid du Colombier ensure(tr, &tr->unprocessed, RecHdrLen); 745*1a4050f5SDavid du Colombier consume(&tr->unprocessed, header, RecHdrLen); 746*1a4050f5SDavid du Colombier if(tr->debug)pprint("consumed %d header\n", RecHdrLen); 747*1a4050f5SDavid du Colombier nconsumed = RecHdrLen; 748*1a4050f5SDavid du Colombier 749*1a4050f5SDavid du Colombier if((tr->handin == 0) && (header[0] & 0x80)){ 750*1a4050f5SDavid du Colombier /* Cope with an SSL3 ClientHello expressed in SSL2 record format. 751*1a4050f5SDavid du Colombier This is sent by some clients that we must interoperate 752*1a4050f5SDavid du Colombier with, such as Java's JSSE and Microsoft's Internet Explorer. */ 753*1a4050f5SDavid du Colombier len = (get16(header) & ~0x8000) - 3; 754*1a4050f5SDavid du Colombier type = header[2]; 755*1a4050f5SDavid du Colombier ver = get16(header + 3); 756*1a4050f5SDavid du Colombier if(type != SSL2ClientHello || len < 22) 757*1a4050f5SDavid du Colombier rcvError(tr, EProtocolVersion, "invalid initial SSL2-like message"); 758*1a4050f5SDavid du Colombier }else{ /* normal SSL3 record format */ 759*1a4050f5SDavid du Colombier type = header[0]; 760*1a4050f5SDavid du Colombier ver = get16(header+1); 761*1a4050f5SDavid du Colombier len = get16(header+3); 762*1a4050f5SDavid du Colombier } 763*1a4050f5SDavid du Colombier if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion)) 764*1a4050f5SDavid du Colombier rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'", 765*1a4050f5SDavid du Colombier tr->version, tr->verset?"/set":"", len, type, ver, (char*)header); 766*1a4050f5SDavid du Colombier if(len > MaxCipherRecLen || len < 0) 767*1a4050f5SDavid du Colombier rcvError(tr, ERecordOverflow, "record message too long %d", len); 768*1a4050f5SDavid du Colombier ensure(tr, &tr->unprocessed, len); 769*1a4050f5SDavid du Colombier nconsumed = 0; 770*1a4050f5SDavid du Colombier poperror(); 771*1a4050f5SDavid du Colombier 772*1a4050f5SDavid du Colombier /* 773*1a4050f5SDavid du Colombier * If an Eintr happens after this, we'll get out of sync. 774*1a4050f5SDavid du Colombier * Make sure nothing we call can sleep. 775*1a4050f5SDavid du Colombier * Errors are ok, as they kill the connection. 776*1a4050f5SDavid du Colombier * Luckily, allocb won't sleep, it'll just error out. 777*1a4050f5SDavid du Colombier */ 778*1a4050f5SDavid du Colombier b = nil; 779*1a4050f5SDavid du Colombier if(waserror()){ 780*1a4050f5SDavid du Colombier if(b != nil) 781*1a4050f5SDavid du Colombier freeb(b); 782*1a4050f5SDavid du Colombier tlsError(tr, "channel error"); 783*1a4050f5SDavid du Colombier nexterror(); 784*1a4050f5SDavid du Colombier } 785*1a4050f5SDavid du Colombier b = qgrab(&tr->unprocessed, len); 786*1a4050f5SDavid du Colombier if(tr->debug) pprint("consumed unprocessed %d\n", len); 787*1a4050f5SDavid du Colombier 788*1a4050f5SDavid du Colombier in = &tr->in; 789*1a4050f5SDavid du Colombier if(waserror()){ 790*1a4050f5SDavid du Colombier qunlock(&in->seclock); 791*1a4050f5SDavid du Colombier nexterror(); 792*1a4050f5SDavid du Colombier } 793*1a4050f5SDavid du Colombier qlock(&in->seclock); 794*1a4050f5SDavid du Colombier p = b->rp; 795*1a4050f5SDavid du Colombier if(in->sec != nil) { 796*1a4050f5SDavid du Colombier /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here 797*1a4050f5SDavid du Colombier should look alike, including timing of the response. */ 798*1a4050f5SDavid du Colombier unpad_len = (*in->sec->dec)(in->sec, p, len); 799*1a4050f5SDavid du Colombier if(unpad_len >= in->sec->maclen) 800*1a4050f5SDavid du Colombier len = unpad_len - in->sec->maclen; 801*1a4050f5SDavid du Colombier if(tr->debug) pprint("decrypted %d\n", unpad_len); 802*1a4050f5SDavid du Colombier if(tr->debug) pdump(unpad_len, p, "decrypted:"); 803*1a4050f5SDavid du Colombier 804*1a4050f5SDavid du Colombier /* update length */ 805*1a4050f5SDavid du Colombier put16(header+3, len); 806*1a4050f5SDavid du Colombier put64(seq, in->seq); 807*1a4050f5SDavid du Colombier in->seq++; 808*1a4050f5SDavid du Colombier (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac); 809*1a4050f5SDavid du Colombier if(unpad_len < in->sec->maclen) 810*1a4050f5SDavid du Colombier rcvError(tr, EBadRecordMac, "short record mac"); 811*1a4050f5SDavid du Colombier if(memcmp(hmac, p+len, in->sec->maclen) != 0) 812*1a4050f5SDavid du Colombier rcvError(tr, EBadRecordMac, "record mac mismatch"); 813*1a4050f5SDavid du Colombier b->wp = b->rp + len; 814*1a4050f5SDavid du Colombier } 815*1a4050f5SDavid du Colombier qunlock(&in->seclock); 816*1a4050f5SDavid du Colombier poperror(); 817*1a4050f5SDavid du Colombier if(len < 0) 818*1a4050f5SDavid du Colombier rcvError(tr, EDecodeError, "runt record message"); 819*1a4050f5SDavid du Colombier 820*1a4050f5SDavid du Colombier switch(type) { 821*1a4050f5SDavid du Colombier default: 822*1a4050f5SDavid du Colombier rcvError(tr, EIllegalParameter, "invalid record message 0x%x", type); 823*1a4050f5SDavid du Colombier break; 824*1a4050f5SDavid du Colombier case RChangeCipherSpec: 825*1a4050f5SDavid du Colombier if(len != 1 || p[0] != 1) 826*1a4050f5SDavid du Colombier rcvError(tr, EDecodeError, "invalid change cipher spec"); 827*1a4050f5SDavid du Colombier qlock(&in->seclock); 828*1a4050f5SDavid du Colombier if(in->new == nil){ 829*1a4050f5SDavid du Colombier qunlock(&in->seclock); 830*1a4050f5SDavid du Colombier rcvError(tr, EUnexpectedMessage, "unexpected change cipher spec"); 831*1a4050f5SDavid du Colombier } 832*1a4050f5SDavid du Colombier freeSec(in->sec); 833*1a4050f5SDavid du Colombier in->sec = in->new; 834*1a4050f5SDavid du Colombier in->new = nil; 835*1a4050f5SDavid du Colombier in->seq = 0; 836*1a4050f5SDavid du Colombier qunlock(&in->seclock); 837*1a4050f5SDavid du Colombier break; 838*1a4050f5SDavid du Colombier case RAlert: 839*1a4050f5SDavid du Colombier if(len != 2) 840*1a4050f5SDavid du Colombier rcvError(tr, EDecodeError, "invalid alert"); 841*1a4050f5SDavid du Colombier if(p[0] == 2) 842*1a4050f5SDavid du Colombier rcvAlert(tr, p[1]); 843*1a4050f5SDavid du Colombier if(p[0] != 1) 844*1a4050f5SDavid du Colombier rcvError(tr, EIllegalParameter, "invalid alert fatal code"); 845*1a4050f5SDavid du Colombier 846*1a4050f5SDavid du Colombier /* 847*1a4050f5SDavid du Colombier * propate non-fatal alerts to handshaker 848*1a4050f5SDavid du Colombier */ 849*1a4050f5SDavid du Colombier if(p[1] == ECloseNotify) { 850*1a4050f5SDavid du Colombier tlsclosed(tr, SRClose); 851*1a4050f5SDavid du Colombier if(tr->opened) 852*1a4050f5SDavid du Colombier error("tls hungup"); 853*1a4050f5SDavid du Colombier error("close notify"); 854*1a4050f5SDavid du Colombier } 855*1a4050f5SDavid du Colombier if(p[1] == ENoRenegotiation) 856*1a4050f5SDavid du Colombier alertHand(tr, "no renegotiation"); 857*1a4050f5SDavid du Colombier else if(p[1] == EUserCanceled) 858*1a4050f5SDavid du Colombier alertHand(tr, "handshake canceled by user"); 859*1a4050f5SDavid du Colombier else 860*1a4050f5SDavid du Colombier rcvError(tr, EIllegalParameter, "invalid alert code"); 861*1a4050f5SDavid du Colombier break; 862*1a4050f5SDavid du Colombier case RHandshake: 863*1a4050f5SDavid du Colombier /* 864*1a4050f5SDavid du Colombier * don't worry about dropping the block 865*1a4050f5SDavid du Colombier * qbwrite always queues even if flow controlled and interrupted. 866*1a4050f5SDavid du Colombier * 867*1a4050f5SDavid du Colombier * if there isn't any handshaker, ignore the request, 868*1a4050f5SDavid du Colombier * but notify the other side we are doing so. 869*1a4050f5SDavid du Colombier */ 870*1a4050f5SDavid du Colombier lock(&tr->hqlock); 871*1a4050f5SDavid du Colombier if(tr->handq != nil){ 872*1a4050f5SDavid du Colombier tr->hqref++; 873*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 874*1a4050f5SDavid du Colombier if(waserror()){ 875*1a4050f5SDavid du Colombier dechandq(tr); 876*1a4050f5SDavid du Colombier nexterror(); 877*1a4050f5SDavid du Colombier } 878*1a4050f5SDavid du Colombier b = padblock(b, 1); 879*1a4050f5SDavid du Colombier *b->rp = RHandshake; 880*1a4050f5SDavid du Colombier qbwrite(tr->handq, b); 881*1a4050f5SDavid du Colombier b = nil; 882*1a4050f5SDavid du Colombier poperror(); 883*1a4050f5SDavid du Colombier dechandq(tr); 884*1a4050f5SDavid du Colombier }else{ 885*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 886*1a4050f5SDavid du Colombier if(tr->verset && tr->version != SSL3Version && !waserror()){ 887*1a4050f5SDavid du Colombier sendAlert(tr, ENoRenegotiation); 888*1a4050f5SDavid du Colombier poperror(); 889*1a4050f5SDavid du Colombier } 890*1a4050f5SDavid du Colombier } 891*1a4050f5SDavid du Colombier break; 892*1a4050f5SDavid du Colombier case SSL2ClientHello: 893*1a4050f5SDavid du Colombier lock(&tr->hqlock); 894*1a4050f5SDavid du Colombier if(tr->handq != nil){ 895*1a4050f5SDavid du Colombier tr->hqref++; 896*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 897*1a4050f5SDavid du Colombier if(waserror()){ 898*1a4050f5SDavid du Colombier dechandq(tr); 899*1a4050f5SDavid du Colombier nexterror(); 900*1a4050f5SDavid du Colombier } 901*1a4050f5SDavid du Colombier /* Pass the SSL2 format data, so that the handshake code can compute 902*1a4050f5SDavid du Colombier the correct checksums. HSSL2ClientHello = HandshakeType 9 is 903*1a4050f5SDavid du Colombier unused in RFC2246. */ 904*1a4050f5SDavid du Colombier b = padblock(b, 8); 905*1a4050f5SDavid du Colombier b->rp[0] = RHandshake; 906*1a4050f5SDavid du Colombier b->rp[1] = HSSL2ClientHello; 907*1a4050f5SDavid du Colombier put24(&b->rp[2], len+3); 908*1a4050f5SDavid du Colombier b->rp[5] = SSL2ClientHello; 909*1a4050f5SDavid du Colombier put16(&b->rp[6], ver); 910*1a4050f5SDavid du Colombier qbwrite(tr->handq, b); 911*1a4050f5SDavid du Colombier b = nil; 912*1a4050f5SDavid du Colombier poperror(); 913*1a4050f5SDavid du Colombier dechandq(tr); 914*1a4050f5SDavid du Colombier }else{ 915*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 916*1a4050f5SDavid du Colombier if(tr->verset && tr->version != SSL3Version && !waserror()){ 917*1a4050f5SDavid du Colombier sendAlert(tr, ENoRenegotiation); 918*1a4050f5SDavid du Colombier poperror(); 919*1a4050f5SDavid du Colombier } 920*1a4050f5SDavid du Colombier } 921*1a4050f5SDavid du Colombier break; 922*1a4050f5SDavid du Colombier case RApplication: 923*1a4050f5SDavid du Colombier if(!tr->opened) 924*1a4050f5SDavid du Colombier rcvError(tr, EUnexpectedMessage, "application message received before handshake completed"); 925*1a4050f5SDavid du Colombier if(BLEN(b) > 0){ 926*1a4050f5SDavid du Colombier tr->processed = b; 927*1a4050f5SDavid du Colombier b = nil; 928*1a4050f5SDavid du Colombier } 929*1a4050f5SDavid du Colombier break; 930*1a4050f5SDavid du Colombier } 931*1a4050f5SDavid du Colombier if(b != nil) 932*1a4050f5SDavid du Colombier freeb(b); 933*1a4050f5SDavid du Colombier poperror(); 934*1a4050f5SDavid du Colombier } 935*1a4050f5SDavid du Colombier 936*1a4050f5SDavid du Colombier /* 937*1a4050f5SDavid du Colombier * got a fatal alert message 938*1a4050f5SDavid du Colombier */ 939*1a4050f5SDavid du Colombier static void 940*1a4050f5SDavid du Colombier rcvAlert(TlsRec *tr, int err) 941*1a4050f5SDavid du Colombier { 942*1a4050f5SDavid du Colombier char *s; 943*1a4050f5SDavid du Colombier int i; 944*1a4050f5SDavid du Colombier 945*1a4050f5SDavid du Colombier s = "unknown error"; 946*1a4050f5SDavid du Colombier for(i=0; i < nelem(tlserrs); i++){ 947*1a4050f5SDavid du Colombier if(tlserrs[i].err == err){ 948*1a4050f5SDavid du Colombier s = tlserrs[i].msg; 949*1a4050f5SDavid du Colombier break; 950*1a4050f5SDavid du Colombier } 951*1a4050f5SDavid du Colombier } 952*1a4050f5SDavid du Colombier if(tr->debug) pprint("rcvAlert: %s\n", s); 953*1a4050f5SDavid du Colombier 954*1a4050f5SDavid du Colombier tlsError(tr, s); 955*1a4050f5SDavid du Colombier if(!tr->opened) 956*1a4050f5SDavid du Colombier error(s); 957*1a4050f5SDavid du Colombier error("tls error"); 958*1a4050f5SDavid du Colombier } 959*1a4050f5SDavid du Colombier 960*1a4050f5SDavid du Colombier /* 961*1a4050f5SDavid du Colombier * found an error while decoding the input stream 962*1a4050f5SDavid du Colombier */ 963*1a4050f5SDavid du Colombier static void 964*1a4050f5SDavid du Colombier rcvError(TlsRec *tr, int err, char *fmt, ...) 965*1a4050f5SDavid du Colombier { 966*1a4050f5SDavid du Colombier char msg[ERRMAX]; 967*1a4050f5SDavid du Colombier va_list arg; 968*1a4050f5SDavid du Colombier 969*1a4050f5SDavid du Colombier va_start(arg, fmt); 970*1a4050f5SDavid du Colombier vseprint(msg, msg+sizeof(msg), fmt, arg); 971*1a4050f5SDavid du Colombier va_end(arg); 972*1a4050f5SDavid du Colombier if(tr->debug) pprint("rcvError: %s\n", msg); 973*1a4050f5SDavid du Colombier 974*1a4050f5SDavid du Colombier sendAlert(tr, err); 975*1a4050f5SDavid du Colombier 976*1a4050f5SDavid du Colombier if(!tr->opened) 977*1a4050f5SDavid du Colombier error(msg); 978*1a4050f5SDavid du Colombier error("tls error"); 979*1a4050f5SDavid du Colombier } 980*1a4050f5SDavid du Colombier 981*1a4050f5SDavid du Colombier /* 982*1a4050f5SDavid du Colombier * make sure the next hand operation returns with a 'msg' error 983*1a4050f5SDavid du Colombier */ 984*1a4050f5SDavid du Colombier static void 985*1a4050f5SDavid du Colombier alertHand(TlsRec *tr, char *msg) 986*1a4050f5SDavid du Colombier { 987*1a4050f5SDavid du Colombier Block *b; 988*1a4050f5SDavid du Colombier int n; 989*1a4050f5SDavid du Colombier 990*1a4050f5SDavid du Colombier lock(&tr->hqlock); 991*1a4050f5SDavid du Colombier if(tr->handq == nil){ 992*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 993*1a4050f5SDavid du Colombier return; 994*1a4050f5SDavid du Colombier } 995*1a4050f5SDavid du Colombier tr->hqref++; 996*1a4050f5SDavid du Colombier unlock(&tr->hqlock); 997*1a4050f5SDavid du Colombier 998*1a4050f5SDavid du Colombier n = strlen(msg); 999*1a4050f5SDavid du Colombier if(waserror()){ 1000*1a4050f5SDavid du Colombier dechandq(tr); 1001*1a4050f5SDavid du Colombier nexterror(); 1002*1a4050f5SDavid du Colombier } 1003*1a4050f5SDavid du Colombier b = allocb(n + 2); 1004*1a4050f5SDavid du Colombier *b->wp++ = RAlert; 1005*1a4050f5SDavid du Colombier memmove(b->wp, msg, n + 1); 1006*1a4050f5SDavid du Colombier b->wp += n + 1; 1007*1a4050f5SDavid du Colombier 1008*1a4050f5SDavid du Colombier qbwrite(tr->handq, b); 1009*1a4050f5SDavid du Colombier 1010*1a4050f5SDavid du Colombier poperror(); 1011*1a4050f5SDavid du Colombier dechandq(tr); 1012*1a4050f5SDavid du Colombier } 1013*1a4050f5SDavid du Colombier 1014*1a4050f5SDavid du Colombier static void 1015*1a4050f5SDavid du Colombier checkstate(TlsRec *tr, int ishand, int ok) 1016*1a4050f5SDavid du Colombier { 1017*1a4050f5SDavid du Colombier int state; 1018*1a4050f5SDavid du Colombier 1019*1a4050f5SDavid du Colombier lock(&tr->statelk); 1020*1a4050f5SDavid du Colombier state = tr->state; 1021*1a4050f5SDavid du Colombier unlock(&tr->statelk); 1022*1a4050f5SDavid du Colombier if(state & ok) 1023*1a4050f5SDavid du Colombier return; 1024*1a4050f5SDavid du Colombier switch(state){ 1025*1a4050f5SDavid du Colombier case SHandshake: 1026*1a4050f5SDavid du Colombier case SOpen: 1027*1a4050f5SDavid du Colombier break; 1028*1a4050f5SDavid du Colombier case SError: 1029*1a4050f5SDavid du Colombier case SAlert: 1030*1a4050f5SDavid du Colombier if(ishand) 1031*1a4050f5SDavid du Colombier error(tr->err); 1032*1a4050f5SDavid du Colombier error("tls error"); 1033*1a4050f5SDavid du Colombier case SRClose: 1034*1a4050f5SDavid du Colombier case SLClose: 1035*1a4050f5SDavid du Colombier case SClosed: 1036*1a4050f5SDavid du Colombier error("tls hungup"); 1037*1a4050f5SDavid du Colombier } 1038*1a4050f5SDavid du Colombier error("tls improperly configured"); 1039*1a4050f5SDavid du Colombier } 1040*1a4050f5SDavid du Colombier 1041*1a4050f5SDavid du Colombier static Block* 1042*1a4050f5SDavid du Colombier tlsbread(Chan *c, long n, ulong offset) 1043*1a4050f5SDavid du Colombier { 1044*1a4050f5SDavid du Colombier int ty; 1045*1a4050f5SDavid du Colombier Block *b; 1046*1a4050f5SDavid du Colombier TlsRec *volatile tr; 1047*1a4050f5SDavid du Colombier 1048*1a4050f5SDavid du Colombier ty = TYPE(c->qid); 1049*1a4050f5SDavid du Colombier switch(ty) { 1050*1a4050f5SDavid du Colombier default: 1051*1a4050f5SDavid du Colombier return devbread(c, n, offset); 1052*1a4050f5SDavid du Colombier case Qhand: 1053*1a4050f5SDavid du Colombier case Qdata: 1054*1a4050f5SDavid du Colombier break; 1055*1a4050f5SDavid du Colombier } 1056*1a4050f5SDavid du Colombier 1057*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 1058*1a4050f5SDavid du Colombier if(tr == nil) 1059*1a4050f5SDavid du Colombier panic("tlsbread"); 1060*1a4050f5SDavid du Colombier 1061*1a4050f5SDavid du Colombier if(waserror()){ 1062*1a4050f5SDavid du Colombier qunlock(&tr->in.io); 1063*1a4050f5SDavid du Colombier nexterror(); 1064*1a4050f5SDavid du Colombier } 1065*1a4050f5SDavid du Colombier qlock(&tr->in.io); 1066*1a4050f5SDavid du Colombier if(ty == Qdata){ 1067*1a4050f5SDavid du Colombier checkstate(tr, 0, SOpen); 1068*1a4050f5SDavid du Colombier while(tr->processed == nil) 1069*1a4050f5SDavid du Colombier tlsrecread(tr); 1070*1a4050f5SDavid du Colombier 1071*1a4050f5SDavid du Colombier /* return at most what was asked for */ 1072*1a4050f5SDavid du Colombier b = qgrab(&tr->processed, n); 1073*1a4050f5SDavid du Colombier if(tr->debug) pprint("consumed processed %d\n", BLEN(b)); 1074*1a4050f5SDavid du Colombier if(tr->debug) pdump(BLEN(b), b->rp, "consumed:"); 1075*1a4050f5SDavid du Colombier qunlock(&tr->in.io); 1076*1a4050f5SDavid du Colombier poperror(); 1077*1a4050f5SDavid du Colombier tr->datain += BLEN(b); 1078*1a4050f5SDavid du Colombier }else{ 1079*1a4050f5SDavid du Colombier checkstate(tr, 1, SOpen|SHandshake|SLClose); 1080*1a4050f5SDavid du Colombier 1081*1a4050f5SDavid du Colombier /* 1082*1a4050f5SDavid du Colombier * it's ok to look at state without the lock 1083*1a4050f5SDavid du Colombier * since it only protects reading records, 1084*1a4050f5SDavid du Colombier * and we have that tr->in.io held. 1085*1a4050f5SDavid du Colombier */ 1086*1a4050f5SDavid du Colombier while(!tr->opened && tr->hprocessed == nil && !qcanread(tr->handq)) 1087*1a4050f5SDavid du Colombier tlsrecread(tr); 1088*1a4050f5SDavid du Colombier 1089*1a4050f5SDavid du Colombier qunlock(&tr->in.io); 1090*1a4050f5SDavid du Colombier poperror(); 1091*1a4050f5SDavid du Colombier 1092*1a4050f5SDavid du Colombier if(waserror()){ 1093*1a4050f5SDavid du Colombier qunlock(&tr->hqread); 1094*1a4050f5SDavid du Colombier nexterror(); 1095*1a4050f5SDavid du Colombier } 1096*1a4050f5SDavid du Colombier qlock(&tr->hqread); 1097*1a4050f5SDavid du Colombier if(tr->hprocessed == nil){ 1098*1a4050f5SDavid du Colombier b = qbread(tr->handq, MaxRecLen + 1); 1099*1a4050f5SDavid du Colombier if(*b->rp++ == RAlert){ 1100*1a4050f5SDavid du Colombier kstrcpy(up->errstr, (char*)b->rp, ERRMAX); 1101*1a4050f5SDavid du Colombier freeb(b); 1102*1a4050f5SDavid du Colombier nexterror(); 1103*1a4050f5SDavid du Colombier } 1104*1a4050f5SDavid du Colombier tr->hprocessed = b; 1105*1a4050f5SDavid du Colombier } 1106*1a4050f5SDavid du Colombier b = qgrab(&tr->hprocessed, n); 1107*1a4050f5SDavid du Colombier poperror(); 1108*1a4050f5SDavid du Colombier qunlock(&tr->hqread); 1109*1a4050f5SDavid du Colombier tr->handin += BLEN(b); 1110*1a4050f5SDavid du Colombier } 1111*1a4050f5SDavid du Colombier 1112*1a4050f5SDavid du Colombier return b; 1113*1a4050f5SDavid du Colombier } 1114*1a4050f5SDavid du Colombier 1115*1a4050f5SDavid du Colombier static long 1116*1a4050f5SDavid du Colombier tlsread(Chan *c, void *a, long n, vlong off) 1117*1a4050f5SDavid du Colombier { 1118*1a4050f5SDavid du Colombier Block *volatile b; 1119*1a4050f5SDavid du Colombier Block *nb; 1120*1a4050f5SDavid du Colombier uchar *va; 1121*1a4050f5SDavid du Colombier int i, ty; 1122*1a4050f5SDavid du Colombier char *buf, *s, *e; 1123*1a4050f5SDavid du Colombier ulong offset = off; 1124*1a4050f5SDavid du Colombier TlsRec * tr; 1125*1a4050f5SDavid du Colombier 1126*1a4050f5SDavid du Colombier if(c->qid.type & QTDIR) 1127*1a4050f5SDavid du Colombier return devdirread(c, a, n, 0, 0, tlsgen); 1128*1a4050f5SDavid du Colombier 1129*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 1130*1a4050f5SDavid du Colombier ty = TYPE(c->qid); 1131*1a4050f5SDavid du Colombier switch(ty) { 1132*1a4050f5SDavid du Colombier default: 1133*1a4050f5SDavid du Colombier error(Ebadusefd); 1134*1a4050f5SDavid du Colombier case Qstatus: 1135*1a4050f5SDavid du Colombier buf = smalloc(Statlen); 1136*1a4050f5SDavid du Colombier qlock(&tr->in.seclock); 1137*1a4050f5SDavid du Colombier qlock(&tr->out.seclock); 1138*1a4050f5SDavid du Colombier s = buf; 1139*1a4050f5SDavid du Colombier e = buf + Statlen; 1140*1a4050f5SDavid du Colombier s = seprint(s, e, "State: %s\n", tlsstate(tr->state)); 1141*1a4050f5SDavid du Colombier s = seprint(s, e, "Version: 0x%x\n", tr->version); 1142*1a4050f5SDavid du Colombier if(tr->in.sec != nil) 1143*1a4050f5SDavid du Colombier s = seprint(s, e, "EncIn: %s\nHashIn: %s\n", tr->in.sec->encalg, tr->in.sec->hashalg); 1144*1a4050f5SDavid du Colombier if(tr->in.new != nil) 1145*1a4050f5SDavid du Colombier s = seprint(s, e, "NewEncIn: %s\nNewHashIn: %s\n", tr->in.new->encalg, tr->in.new->hashalg); 1146*1a4050f5SDavid du Colombier if(tr->out.sec != nil) 1147*1a4050f5SDavid du Colombier s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg); 1148*1a4050f5SDavid du Colombier if(tr->out.new != nil) 1149*1a4050f5SDavid du Colombier seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg); 1150*1a4050f5SDavid du Colombier qunlock(&tr->in.seclock); 1151*1a4050f5SDavid du Colombier qunlock(&tr->out.seclock); 1152*1a4050f5SDavid du Colombier n = readstr(offset, a, n, buf); 1153*1a4050f5SDavid du Colombier free(buf); 1154*1a4050f5SDavid du Colombier return n; 1155*1a4050f5SDavid du Colombier case Qstats: 1156*1a4050f5SDavid du Colombier buf = smalloc(Statlen); 1157*1a4050f5SDavid du Colombier s = buf; 1158*1a4050f5SDavid du Colombier e = buf + Statlen; 1159*1a4050f5SDavid du Colombier s = seprint(s, e, "DataIn: %lld\n", tr->datain); 1160*1a4050f5SDavid du Colombier s = seprint(s, e, "DataOut: %lld\n", tr->dataout); 1161*1a4050f5SDavid du Colombier s = seprint(s, e, "HandIn: %lld\n", tr->handin); 1162*1a4050f5SDavid du Colombier seprint(s, e, "HandOut: %lld\n", tr->handout); 1163*1a4050f5SDavid du Colombier n = readstr(offset, a, n, buf); 1164*1a4050f5SDavid du Colombier free(buf); 1165*1a4050f5SDavid du Colombier return n; 1166*1a4050f5SDavid du Colombier case Qctl: 1167*1a4050f5SDavid du Colombier buf = smalloc(Statlen); 1168*1a4050f5SDavid du Colombier snprint(buf, Statlen, "%llud", CONV(c->qid)); 1169*1a4050f5SDavid du Colombier n = readstr(offset, a, n, buf); 1170*1a4050f5SDavid du Colombier free(buf); 1171*1a4050f5SDavid du Colombier return n; 1172*1a4050f5SDavid du Colombier case Qdata: 1173*1a4050f5SDavid du Colombier case Qhand: 1174*1a4050f5SDavid du Colombier b = tlsbread(c, n, offset); 1175*1a4050f5SDavid du Colombier break; 1176*1a4050f5SDavid du Colombier case Qencalgs: 1177*1a4050f5SDavid du Colombier return readstr(offset, a, n, encalgs); 1178*1a4050f5SDavid du Colombier case Qhashalgs: 1179*1a4050f5SDavid du Colombier return readstr(offset, a, n, hashalgs); 1180*1a4050f5SDavid du Colombier } 1181*1a4050f5SDavid du Colombier 1182*1a4050f5SDavid du Colombier if(waserror()){ 1183*1a4050f5SDavid du Colombier freeblist(b); 1184*1a4050f5SDavid du Colombier nexterror(); 1185*1a4050f5SDavid du Colombier } 1186*1a4050f5SDavid du Colombier 1187*1a4050f5SDavid du Colombier n = 0; 1188*1a4050f5SDavid du Colombier va = a; 1189*1a4050f5SDavid du Colombier for(nb = b; nb; nb = nb->next){ 1190*1a4050f5SDavid du Colombier i = BLEN(nb); 1191*1a4050f5SDavid du Colombier memmove(va+n, nb->rp, i); 1192*1a4050f5SDavid du Colombier n += i; 1193*1a4050f5SDavid du Colombier } 1194*1a4050f5SDavid du Colombier 1195*1a4050f5SDavid du Colombier freeblist(b); 1196*1a4050f5SDavid du Colombier poperror(); 1197*1a4050f5SDavid du Colombier 1198*1a4050f5SDavid du Colombier return n; 1199*1a4050f5SDavid du Colombier } 1200*1a4050f5SDavid du Colombier 1201*1a4050f5SDavid du Colombier /* 1202*1a4050f5SDavid du Colombier * write a block in tls records 1203*1a4050f5SDavid du Colombier */ 1204*1a4050f5SDavid du Colombier static void 1205*1a4050f5SDavid du Colombier tlsrecwrite(TlsRec *tr, int type, Block *b) 1206*1a4050f5SDavid du Colombier { 1207*1a4050f5SDavid du Colombier Block *volatile bb; 1208*1a4050f5SDavid du Colombier Block *nb; 1209*1a4050f5SDavid du Colombier uchar *p, seq[8]; 1210*1a4050f5SDavid du Colombier OneWay *volatile out; 1211*1a4050f5SDavid du Colombier int n, maclen, pad, ok; 1212*1a4050f5SDavid du Colombier 1213*1a4050f5SDavid du Colombier out = &tr->out; 1214*1a4050f5SDavid du Colombier bb = b; 1215*1a4050f5SDavid du Colombier if(waserror()){ 1216*1a4050f5SDavid du Colombier qunlock(&out->io); 1217*1a4050f5SDavid du Colombier if(bb != nil) 1218*1a4050f5SDavid du Colombier freeb(bb); 1219*1a4050f5SDavid du Colombier nexterror(); 1220*1a4050f5SDavid du Colombier } 1221*1a4050f5SDavid du Colombier qlock(&out->io); 1222*1a4050f5SDavid du Colombier if(tr->debug)pprint("send %d\n", BLEN(b)); 1223*1a4050f5SDavid du Colombier if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); 1224*1a4050f5SDavid du Colombier 1225*1a4050f5SDavid du Colombier 1226*1a4050f5SDavid du Colombier ok = SHandshake|SOpen|SRClose; 1227*1a4050f5SDavid du Colombier if(type == RAlert) 1228*1a4050f5SDavid du Colombier ok |= SAlert; 1229*1a4050f5SDavid du Colombier while(bb != nil){ 1230*1a4050f5SDavid du Colombier checkstate(tr, type != RApplication, ok); 1231*1a4050f5SDavid du Colombier 1232*1a4050f5SDavid du Colombier /* 1233*1a4050f5SDavid du Colombier * get at most one maximal record's input, 1234*1a4050f5SDavid du Colombier * with padding on the front for header and 1235*1a4050f5SDavid du Colombier * back for mac and maximal block padding. 1236*1a4050f5SDavid du Colombier */ 1237*1a4050f5SDavid du Colombier if(waserror()){ 1238*1a4050f5SDavid du Colombier qunlock(&out->seclock); 1239*1a4050f5SDavid du Colombier nexterror(); 1240*1a4050f5SDavid du Colombier } 1241*1a4050f5SDavid du Colombier qlock(&out->seclock); 1242*1a4050f5SDavid du Colombier maclen = 0; 1243*1a4050f5SDavid du Colombier pad = 0; 1244*1a4050f5SDavid du Colombier if(out->sec != nil){ 1245*1a4050f5SDavid du Colombier maclen = out->sec->maclen; 1246*1a4050f5SDavid du Colombier pad = maclen + out->sec->block; 1247*1a4050f5SDavid du Colombier } 1248*1a4050f5SDavid du Colombier n = BLEN(bb); 1249*1a4050f5SDavid du Colombier if(n > MaxRecLen){ 1250*1a4050f5SDavid du Colombier n = MaxRecLen; 1251*1a4050f5SDavid du Colombier nb = allocb(n + pad + RecHdrLen); 1252*1a4050f5SDavid du Colombier memmove(nb->wp + RecHdrLen, bb->rp, n); 1253*1a4050f5SDavid du Colombier bb->rp += n; 1254*1a4050f5SDavid du Colombier }else{ 1255*1a4050f5SDavid du Colombier /* 1256*1a4050f5SDavid du Colombier * carefully reuse bb so it will get freed if we're out of memory 1257*1a4050f5SDavid du Colombier */ 1258*1a4050f5SDavid du Colombier bb = padblock(bb, RecHdrLen); 1259*1a4050f5SDavid du Colombier if(pad) 1260*1a4050f5SDavid du Colombier nb = padblock(bb, -pad); 1261*1a4050f5SDavid du Colombier else 1262*1a4050f5SDavid du Colombier nb = bb; 1263*1a4050f5SDavid du Colombier bb = nil; 1264*1a4050f5SDavid du Colombier } 1265*1a4050f5SDavid du Colombier 1266*1a4050f5SDavid du Colombier p = nb->rp; 1267*1a4050f5SDavid du Colombier p[0] = type; 1268*1a4050f5SDavid du Colombier put16(p+1, tr->version); 1269*1a4050f5SDavid du Colombier put16(p+3, n); 1270*1a4050f5SDavid du Colombier 1271*1a4050f5SDavid du Colombier if(out->sec != nil){ 1272*1a4050f5SDavid du Colombier put64(seq, out->seq); 1273*1a4050f5SDavid du Colombier out->seq++; 1274*1a4050f5SDavid du Colombier (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n); 1275*1a4050f5SDavid du Colombier n += maclen; 1276*1a4050f5SDavid du Colombier 1277*1a4050f5SDavid du Colombier /* encrypt */ 1278*1a4050f5SDavid du Colombier n = (*out->sec->enc)(out->sec, p + RecHdrLen, n); 1279*1a4050f5SDavid du Colombier nb->wp = p + RecHdrLen + n; 1280*1a4050f5SDavid du Colombier 1281*1a4050f5SDavid du Colombier /* update length */ 1282*1a4050f5SDavid du Colombier put16(p+3, n); 1283*1a4050f5SDavid du Colombier } 1284*1a4050f5SDavid du Colombier if(type == RChangeCipherSpec){ 1285*1a4050f5SDavid du Colombier if(out->new == nil) 1286*1a4050f5SDavid du Colombier error("change cipher without a new cipher"); 1287*1a4050f5SDavid du Colombier freeSec(out->sec); 1288*1a4050f5SDavid du Colombier out->sec = out->new; 1289*1a4050f5SDavid du Colombier out->new = nil; 1290*1a4050f5SDavid du Colombier out->seq = 0; 1291*1a4050f5SDavid du Colombier } 1292*1a4050f5SDavid du Colombier qunlock(&out->seclock); 1293*1a4050f5SDavid du Colombier poperror(); 1294*1a4050f5SDavid du Colombier 1295*1a4050f5SDavid du Colombier /* 1296*1a4050f5SDavid du Colombier * if bwrite error's, we assume the block is queued. 1297*1a4050f5SDavid du Colombier * if not, we're out of sync with the receiver and will not recover. 1298*1a4050f5SDavid du Colombier */ 1299*1a4050f5SDavid du Colombier if(waserror()){ 1300*1a4050f5SDavid du Colombier if(strcmp(up->errstr, "interrupted") != 0) 1301*1a4050f5SDavid du Colombier tlsError(tr, "channel error"); 1302*1a4050f5SDavid du Colombier nexterror(); 1303*1a4050f5SDavid du Colombier } 1304*1a4050f5SDavid du Colombier devtab[tr->c->type]->bwrite(tr->c, nb, 0); 1305*1a4050f5SDavid du Colombier poperror(); 1306*1a4050f5SDavid du Colombier } 1307*1a4050f5SDavid du Colombier qunlock(&out->io); 1308*1a4050f5SDavid du Colombier poperror(); 1309*1a4050f5SDavid du Colombier } 1310*1a4050f5SDavid du Colombier 1311*1a4050f5SDavid du Colombier static long 1312*1a4050f5SDavid du Colombier tlsbwrite(Chan *c, Block *b, ulong offset) 1313*1a4050f5SDavid du Colombier { 1314*1a4050f5SDavid du Colombier int ty; 1315*1a4050f5SDavid du Colombier ulong n; 1316*1a4050f5SDavid du Colombier TlsRec *tr; 1317*1a4050f5SDavid du Colombier 1318*1a4050f5SDavid du Colombier n = BLEN(b); 1319*1a4050f5SDavid du Colombier 1320*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 1321*1a4050f5SDavid du Colombier if(tr == nil) 1322*1a4050f5SDavid du Colombier panic("tlsbread"); 1323*1a4050f5SDavid du Colombier 1324*1a4050f5SDavid du Colombier ty = TYPE(c->qid); 1325*1a4050f5SDavid du Colombier switch(ty) { 1326*1a4050f5SDavid du Colombier default: 1327*1a4050f5SDavid du Colombier return devbwrite(c, b, offset); 1328*1a4050f5SDavid du Colombier case Qhand: 1329*1a4050f5SDavid du Colombier tlsrecwrite(tr, RHandshake, b); 1330*1a4050f5SDavid du Colombier tr->handout += n; 1331*1a4050f5SDavid du Colombier break; 1332*1a4050f5SDavid du Colombier case Qdata: 1333*1a4050f5SDavid du Colombier checkstate(tr, 0, SOpen); 1334*1a4050f5SDavid du Colombier tlsrecwrite(tr, RApplication, b); 1335*1a4050f5SDavid du Colombier tr->dataout += n; 1336*1a4050f5SDavid du Colombier break; 1337*1a4050f5SDavid du Colombier } 1338*1a4050f5SDavid du Colombier 1339*1a4050f5SDavid du Colombier return n; 1340*1a4050f5SDavid du Colombier } 1341*1a4050f5SDavid du Colombier 1342*1a4050f5SDavid du Colombier typedef struct Hashalg Hashalg; 1343*1a4050f5SDavid du Colombier struct Hashalg 1344*1a4050f5SDavid du Colombier { 1345*1a4050f5SDavid du Colombier char *name; 1346*1a4050f5SDavid du Colombier int maclen; 1347*1a4050f5SDavid du Colombier void (*initkey)(Hashalg *, int, Secret *, uchar*); 1348*1a4050f5SDavid du Colombier }; 1349*1a4050f5SDavid du Colombier 1350*1a4050f5SDavid du Colombier static void 1351*1a4050f5SDavid du Colombier initmd5key(Hashalg *ha, int version, Secret *s, uchar *p) 1352*1a4050f5SDavid du Colombier { 1353*1a4050f5SDavid du Colombier s->maclen = ha->maclen; 1354*1a4050f5SDavid du Colombier if(version == SSL3Version) 1355*1a4050f5SDavid du Colombier s->mac = sslmac_md5; 1356*1a4050f5SDavid du Colombier else 1357*1a4050f5SDavid du Colombier s->mac = hmac_md5; 1358*1a4050f5SDavid du Colombier memmove(s->mackey, p, ha->maclen); 1359*1a4050f5SDavid du Colombier } 1360*1a4050f5SDavid du Colombier 1361*1a4050f5SDavid du Colombier static void 1362*1a4050f5SDavid du Colombier initclearmac(Hashalg *unused1, int unused2, Secret *s, uchar *unused3) 1363*1a4050f5SDavid du Colombier { 1364*1a4050f5SDavid du Colombier s->maclen = 0; 1365*1a4050f5SDavid du Colombier s->mac = nomac; 1366*1a4050f5SDavid du Colombier } 1367*1a4050f5SDavid du Colombier 1368*1a4050f5SDavid du Colombier static void 1369*1a4050f5SDavid du Colombier initsha1key(Hashalg *ha, int version, Secret *s, uchar *p) 1370*1a4050f5SDavid du Colombier { 1371*1a4050f5SDavid du Colombier s->maclen = ha->maclen; 1372*1a4050f5SDavid du Colombier if(version == SSL3Version) 1373*1a4050f5SDavid du Colombier s->mac = sslmac_sha1; 1374*1a4050f5SDavid du Colombier else 1375*1a4050f5SDavid du Colombier s->mac = hmac_sha1; 1376*1a4050f5SDavid du Colombier memmove(s->mackey, p, ha->maclen); 1377*1a4050f5SDavid du Colombier } 1378*1a4050f5SDavid du Colombier 1379*1a4050f5SDavid du Colombier static Hashalg hashtab[] = 1380*1a4050f5SDavid du Colombier { 1381*1a4050f5SDavid du Colombier { "clear", 0, initclearmac, }, 1382*1a4050f5SDavid du Colombier { "md5", MD5dlen, initmd5key, }, 1383*1a4050f5SDavid du Colombier { "sha1", SHA1dlen, initsha1key, }, 1384*1a4050f5SDavid du Colombier { 0 } 1385*1a4050f5SDavid du Colombier }; 1386*1a4050f5SDavid du Colombier 1387*1a4050f5SDavid du Colombier static Hashalg* 1388*1a4050f5SDavid du Colombier parsehashalg(char *p) 1389*1a4050f5SDavid du Colombier { 1390*1a4050f5SDavid du Colombier Hashalg *ha; 1391*1a4050f5SDavid du Colombier 1392*1a4050f5SDavid du Colombier for(ha = hashtab; ha->name; ha++) 1393*1a4050f5SDavid du Colombier if(strcmp(p, ha->name) == 0) 1394*1a4050f5SDavid du Colombier return ha; 1395*1a4050f5SDavid du Colombier error("unsupported hash algorithm"); 1396*1a4050f5SDavid du Colombier return nil; 1397*1a4050f5SDavid du Colombier } 1398*1a4050f5SDavid du Colombier 1399*1a4050f5SDavid du Colombier typedef struct Encalg Encalg; 1400*1a4050f5SDavid du Colombier struct Encalg 1401*1a4050f5SDavid du Colombier { 1402*1a4050f5SDavid du Colombier char *name; 1403*1a4050f5SDavid du Colombier int keylen; 1404*1a4050f5SDavid du Colombier int ivlen; 1405*1a4050f5SDavid du Colombier void (*initkey)(Encalg *ea, Secret *, uchar*, uchar*); 1406*1a4050f5SDavid du Colombier }; 1407*1a4050f5SDavid du Colombier 1408*1a4050f5SDavid du Colombier static void 1409*1a4050f5SDavid du Colombier initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *unused1) 1410*1a4050f5SDavid du Colombier { 1411*1a4050f5SDavid du Colombier s->enckey = smalloc(sizeof(RC4state)); 1412*1a4050f5SDavid du Colombier s->enc = rc4enc; 1413*1a4050f5SDavid du Colombier s->dec = rc4enc; 1414*1a4050f5SDavid du Colombier s->block = 0; 1415*1a4050f5SDavid du Colombier setupRC4state(s->enckey, p, ea->keylen); 1416*1a4050f5SDavid du Colombier } 1417*1a4050f5SDavid du Colombier 1418*1a4050f5SDavid du Colombier static void 1419*1a4050f5SDavid du Colombier initDES3key(Encalg *unused1, Secret *s, uchar *p, uchar *iv) 1420*1a4050f5SDavid du Colombier { 1421*1a4050f5SDavid du Colombier s->enckey = smalloc(sizeof(DES3state)); 1422*1a4050f5SDavid du Colombier s->enc = des3enc; 1423*1a4050f5SDavid du Colombier s->dec = des3dec; 1424*1a4050f5SDavid du Colombier s->block = 8; 1425*1a4050f5SDavid du Colombier setupDES3state(s->enckey, (uchar(*)[8])p, iv); 1426*1a4050f5SDavid du Colombier } 1427*1a4050f5SDavid du Colombier 1428*1a4050f5SDavid du Colombier static void 1429*1a4050f5SDavid du Colombier initclearenc(Encalg *unused1, Secret *s, uchar *unused2, uchar *unused3) 1430*1a4050f5SDavid du Colombier { 1431*1a4050f5SDavid du Colombier s->enc = noenc; 1432*1a4050f5SDavid du Colombier s->dec = noenc; 1433*1a4050f5SDavid du Colombier s->block = 0; 1434*1a4050f5SDavid du Colombier } 1435*1a4050f5SDavid du Colombier 1436*1a4050f5SDavid du Colombier static Encalg encrypttab[] = 1437*1a4050f5SDavid du Colombier { 1438*1a4050f5SDavid du Colombier { "clear", 0, 0, initclearenc }, 1439*1a4050f5SDavid du Colombier { "rc4_128", 128/8, 0, initRC4key }, 1440*1a4050f5SDavid du Colombier { "3des_ede_cbc", 3 * 8, 8, initDES3key }, 1441*1a4050f5SDavid du Colombier { 0 } 1442*1a4050f5SDavid du Colombier }; 1443*1a4050f5SDavid du Colombier 1444*1a4050f5SDavid du Colombier static Encalg* 1445*1a4050f5SDavid du Colombier parseencalg(char *p) 1446*1a4050f5SDavid du Colombier { 1447*1a4050f5SDavid du Colombier Encalg *ea; 1448*1a4050f5SDavid du Colombier 1449*1a4050f5SDavid du Colombier for(ea = encrypttab; ea->name; ea++) 1450*1a4050f5SDavid du Colombier if(strcmp(p, ea->name) == 0) 1451*1a4050f5SDavid du Colombier return ea; 1452*1a4050f5SDavid du Colombier error("unsupported encryption algorithm"); 1453*1a4050f5SDavid du Colombier return nil; 1454*1a4050f5SDavid du Colombier } 1455*1a4050f5SDavid du Colombier 1456*1a4050f5SDavid du Colombier static long 1457*1a4050f5SDavid du Colombier tlswrite(Chan *c, void *a, long n, vlong off) 1458*1a4050f5SDavid du Colombier { 1459*1a4050f5SDavid du Colombier Encalg *ea; 1460*1a4050f5SDavid du Colombier Hashalg *ha; 1461*1a4050f5SDavid du Colombier TlsRec *volatile tr; 1462*1a4050f5SDavid du Colombier Secret *volatile tos, *volatile toc; 1463*1a4050f5SDavid du Colombier Block *volatile b; 1464*1a4050f5SDavid du Colombier Cmdbuf *volatile cb; 1465*1a4050f5SDavid du Colombier int m, ty; 1466*1a4050f5SDavid du Colombier char *p, *e; 1467*1a4050f5SDavid du Colombier uchar *volatile x; 1468*1a4050f5SDavid du Colombier ulong offset = off; 1469*1a4050f5SDavid du Colombier 1470*1a4050f5SDavid du Colombier tr = tlsdevs[CONV(c->qid)]; 1471*1a4050f5SDavid du Colombier if(tr == nil) 1472*1a4050f5SDavid du Colombier panic("tlswrite"); 1473*1a4050f5SDavid du Colombier 1474*1a4050f5SDavid du Colombier ty = TYPE(c->qid); 1475*1a4050f5SDavid du Colombier switch(ty){ 1476*1a4050f5SDavid du Colombier case Qdata: 1477*1a4050f5SDavid du Colombier case Qhand: 1478*1a4050f5SDavid du Colombier p = a; 1479*1a4050f5SDavid du Colombier e = p + n; 1480*1a4050f5SDavid du Colombier do{ 1481*1a4050f5SDavid du Colombier m = e - p; 1482*1a4050f5SDavid du Colombier if(m > MaxRecLen) 1483*1a4050f5SDavid du Colombier m = MaxRecLen; 1484*1a4050f5SDavid du Colombier 1485*1a4050f5SDavid du Colombier b = allocb(m); 1486*1a4050f5SDavid du Colombier if(waserror()){ 1487*1a4050f5SDavid du Colombier freeb(b); 1488*1a4050f5SDavid du Colombier nexterror(); 1489*1a4050f5SDavid du Colombier } 1490*1a4050f5SDavid du Colombier memmove(b->wp, p, m); 1491*1a4050f5SDavid du Colombier poperror(); 1492*1a4050f5SDavid du Colombier b->wp += m; 1493*1a4050f5SDavid du Colombier 1494*1a4050f5SDavid du Colombier tlsbwrite(c, b, offset); 1495*1a4050f5SDavid du Colombier 1496*1a4050f5SDavid du Colombier p += m; 1497*1a4050f5SDavid du Colombier }while(p < e); 1498*1a4050f5SDavid du Colombier return n; 1499*1a4050f5SDavid du Colombier case Qctl: 1500*1a4050f5SDavid du Colombier break; 1501*1a4050f5SDavid du Colombier default: 1502*1a4050f5SDavid du Colombier error(Ebadusefd); 1503*1a4050f5SDavid du Colombier return -1; 1504*1a4050f5SDavid du Colombier } 1505*1a4050f5SDavid du Colombier 1506*1a4050f5SDavid du Colombier cb = parsecmd(a, n); 1507*1a4050f5SDavid du Colombier if(waserror()){ 1508*1a4050f5SDavid du Colombier free(cb); 1509*1a4050f5SDavid du Colombier nexterror(); 1510*1a4050f5SDavid du Colombier } 1511*1a4050f5SDavid du Colombier if(cb->nf < 1) 1512*1a4050f5SDavid du Colombier error("short control request"); 1513*1a4050f5SDavid du Colombier 1514*1a4050f5SDavid du Colombier /* mutex with operations using what we're about to change */ 1515*1a4050f5SDavid du Colombier if(waserror()){ 1516*1a4050f5SDavid du Colombier qunlock(&tr->in.seclock); 1517*1a4050f5SDavid du Colombier qunlock(&tr->out.seclock); 1518*1a4050f5SDavid du Colombier nexterror(); 1519*1a4050f5SDavid du Colombier } 1520*1a4050f5SDavid du Colombier qlock(&tr->in.seclock); 1521*1a4050f5SDavid du Colombier qlock(&tr->out.seclock); 1522*1a4050f5SDavid du Colombier 1523*1a4050f5SDavid du Colombier if(strcmp(cb->f[0], "fd") == 0){ 1524*1a4050f5SDavid du Colombier if(cb->nf != 3) 1525*1a4050f5SDavid du Colombier error("usage: fd open-fd version"); 1526*1a4050f5SDavid du Colombier if(tr->c != nil) 1527*1a4050f5SDavid du Colombier error(Einuse); 1528*1a4050f5SDavid du Colombier m = strtol(cb->f[2], nil, 0); 1529*1a4050f5SDavid du Colombier if(m < MinProtoVersion || m > MaxProtoVersion) 1530*1a4050f5SDavid du Colombier error("unsupported version"); 1531*1a4050f5SDavid du Colombier tr->c = buftochan(cb->f[1]); 1532*1a4050f5SDavid du Colombier tr->version = m; 1533*1a4050f5SDavid du Colombier tlsSetState(tr, SHandshake, SClosed); 1534*1a4050f5SDavid du Colombier }else if(strcmp(cb->f[0], "version") == 0){ 1535*1a4050f5SDavid du Colombier if(cb->nf != 2) 1536*1a4050f5SDavid du Colombier error("usage: version vers"); 1537*1a4050f5SDavid du Colombier if(tr->c == nil) 1538*1a4050f5SDavid du Colombier error("must set fd before version"); 1539*1a4050f5SDavid du Colombier if(tr->verset) 1540*1a4050f5SDavid du Colombier error("version already set"); 1541*1a4050f5SDavid du Colombier m = strtol(cb->f[1], nil, 0); 1542*1a4050f5SDavid du Colombier if(m == SSL3Version) 1543*1a4050f5SDavid du Colombier tr->packMac = sslPackMac; 1544*1a4050f5SDavid du Colombier else if(m == TLSVersion) 1545*1a4050f5SDavid du Colombier tr->packMac = tlsPackMac; 1546*1a4050f5SDavid du Colombier else 1547*1a4050f5SDavid du Colombier error("unsupported version"); 1548*1a4050f5SDavid du Colombier tr->verset = 1; 1549*1a4050f5SDavid du Colombier tr->version = m; 1550*1a4050f5SDavid du Colombier }else if(strcmp(cb->f[0], "secret") == 0){ 1551*1a4050f5SDavid du Colombier if(cb->nf != 5) 1552*1a4050f5SDavid du Colombier error("usage: secret hashalg encalg isclient secretdata"); 1553*1a4050f5SDavid du Colombier if(tr->c == nil || !tr->verset) 1554*1a4050f5SDavid du Colombier error("must set fd and version before secrets"); 1555*1a4050f5SDavid du Colombier 1556*1a4050f5SDavid du Colombier if(tr->in.new != nil){ 1557*1a4050f5SDavid du Colombier freeSec(tr->in.new); 1558*1a4050f5SDavid du Colombier tr->in.new = nil; 1559*1a4050f5SDavid du Colombier } 1560*1a4050f5SDavid du Colombier if(tr->out.new != nil){ 1561*1a4050f5SDavid du Colombier freeSec(tr->out.new); 1562*1a4050f5SDavid du Colombier tr->out.new = nil; 1563*1a4050f5SDavid du Colombier } 1564*1a4050f5SDavid du Colombier 1565*1a4050f5SDavid du Colombier ha = parsehashalg(cb->f[1]); 1566*1a4050f5SDavid du Colombier ea = parseencalg(cb->f[2]); 1567*1a4050f5SDavid du Colombier 1568*1a4050f5SDavid du Colombier p = cb->f[4]; 1569*1a4050f5SDavid du Colombier m = (strlen(p)*3)/2; 1570*1a4050f5SDavid du Colombier x = smalloc(m); 1571*1a4050f5SDavid du Colombier tos = nil; 1572*1a4050f5SDavid du Colombier toc = nil; 1573*1a4050f5SDavid du Colombier if(waserror()){ 1574*1a4050f5SDavid du Colombier freeSec(tos); 1575*1a4050f5SDavid du Colombier freeSec(toc); 1576*1a4050f5SDavid du Colombier free(x); 1577*1a4050f5SDavid du Colombier nexterror(); 1578*1a4050f5SDavid du Colombier } 1579*1a4050f5SDavid du Colombier m = dec64(x, m, p, strlen(p)); 1580*1a4050f5SDavid du Colombier if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen) 1581*1a4050f5SDavid du Colombier error("not enough secret data provided"); 1582*1a4050f5SDavid du Colombier 1583*1a4050f5SDavid du Colombier tos = smalloc(sizeof(Secret)); 1584*1a4050f5SDavid du Colombier toc = smalloc(sizeof(Secret)); 1585*1a4050f5SDavid du Colombier if(!ha->initkey || !ea->initkey) 1586*1a4050f5SDavid du Colombier error("misimplemented secret algorithm"); 1587*1a4050f5SDavid du Colombier (*ha->initkey)(ha, tr->version, tos, &x[0]); 1588*1a4050f5SDavid du Colombier (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]); 1589*1a4050f5SDavid du Colombier (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]); 1590*1a4050f5SDavid du Colombier (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]); 1591*1a4050f5SDavid du Colombier 1592*1a4050f5SDavid du Colombier if(!tos->mac || !tos->enc || !tos->dec 1593*1a4050f5SDavid du Colombier || !toc->mac || !toc->enc || !toc->dec) 1594*1a4050f5SDavid du Colombier error("missing algorithm implementations"); 1595*1a4050f5SDavid du Colombier if(strtol(cb->f[3], nil, 0) == 0){ 1596*1a4050f5SDavid du Colombier tr->in.new = tos; 1597*1a4050f5SDavid du Colombier tr->out.new = toc; 1598*1a4050f5SDavid du Colombier }else{ 1599*1a4050f5SDavid du Colombier tr->in.new = toc; 1600*1a4050f5SDavid du Colombier tr->out.new = tos; 1601*1a4050f5SDavid du Colombier } 1602*1a4050f5SDavid du Colombier if(tr->version == SSL3Version){ 1603*1a4050f5SDavid du Colombier toc->unpad = sslunpad; 1604*1a4050f5SDavid du Colombier tos->unpad = sslunpad; 1605*1a4050f5SDavid du Colombier }else{ 1606*1a4050f5SDavid du Colombier toc->unpad = tlsunpad; 1607*1a4050f5SDavid du Colombier tos->unpad = tlsunpad; 1608*1a4050f5SDavid du Colombier } 1609*1a4050f5SDavid du Colombier toc->encalg = ea->name; 1610*1a4050f5SDavid du Colombier toc->hashalg = ha->name; 1611*1a4050f5SDavid du Colombier tos->encalg = ea->name; 1612*1a4050f5SDavid du Colombier tos->hashalg = ha->name; 1613*1a4050f5SDavid du Colombier 1614*1a4050f5SDavid du Colombier free(x); 1615*1a4050f5SDavid du Colombier poperror(); 1616*1a4050f5SDavid du Colombier }else if(strcmp(cb->f[0], "changecipher") == 0){ 1617*1a4050f5SDavid du Colombier if(cb->nf != 1) 1618*1a4050f5SDavid du Colombier error("usage: changecipher"); 1619*1a4050f5SDavid du Colombier if(tr->out.new == nil) 1620*1a4050f5SDavid du Colombier error("cannot change cipher spec without setting secret"); 1621*1a4050f5SDavid du Colombier 1622*1a4050f5SDavid du Colombier qunlock(&tr->in.seclock); 1623*1a4050f5SDavid du Colombier qunlock(&tr->out.seclock); 1624*1a4050f5SDavid du Colombier poperror(); 1625*1a4050f5SDavid du Colombier free(cb); 1626*1a4050f5SDavid du Colombier poperror(); 1627*1a4050f5SDavid du Colombier 1628*1a4050f5SDavid du Colombier /* 1629*1a4050f5SDavid du Colombier * the real work is done as the message is written 1630*1a4050f5SDavid du Colombier * so the stream is encrypted in sync. 1631*1a4050f5SDavid du Colombier */ 1632*1a4050f5SDavid du Colombier b = allocb(1); 1633*1a4050f5SDavid du Colombier *b->wp++ = 1; 1634*1a4050f5SDavid du Colombier tlsrecwrite(tr, RChangeCipherSpec, b); 1635*1a4050f5SDavid du Colombier return n; 1636*1a4050f5SDavid du Colombier }else if(strcmp(cb->f[0], "opened") == 0){ 1637*1a4050f5SDavid du Colombier if(cb->nf != 1) 1638*1a4050f5SDavid du Colombier error("usage: opened"); 1639*1a4050f5SDavid du Colombier if(tr->in.sec == nil || tr->out.sec == nil) 1640*1a4050f5SDavid du Colombier error("cipher must be configured before enabling data messages"); 1641*1a4050f5SDavid du Colombier lock(&tr->statelk); 1642*1a4050f5SDavid du Colombier if(tr->state != SHandshake && tr->state != SOpen){ 1643*1a4050f5SDavid du Colombier unlock(&tr->statelk); 1644*1a4050f5SDavid du Colombier error("cannot enable data messages"); 1645*1a4050f5SDavid du Colombier } 1646*1a4050f5SDavid du Colombier tr->state = SOpen; 1647*1a4050f5SDavid du Colombier unlock(&tr->statelk); 1648*1a4050f5SDavid du Colombier tr->opened = 1; 1649*1a4050f5SDavid du Colombier }else if(strcmp(cb->f[0], "alert") == 0){ 1650*1a4050f5SDavid du Colombier if(cb->nf != 2) 1651*1a4050f5SDavid du Colombier error("usage: alert n"); 1652*1a4050f5SDavid du Colombier if(tr->c == nil) 1653*1a4050f5SDavid du Colombier error("must set fd before sending alerts"); 1654*1a4050f5SDavid du Colombier m = strtol(cb->f[1], nil, 0); 1655*1a4050f5SDavid du Colombier 1656*1a4050f5SDavid du Colombier qunlock(&tr->in.seclock); 1657*1a4050f5SDavid du Colombier qunlock(&tr->out.seclock); 1658*1a4050f5SDavid du Colombier poperror(); 1659*1a4050f5SDavid du Colombier free(cb); 1660*1a4050f5SDavid du Colombier poperror(); 1661*1a4050f5SDavid du Colombier 1662*1a4050f5SDavid du Colombier sendAlert(tr, m); 1663*1a4050f5SDavid du Colombier 1664*1a4050f5SDavid du Colombier if(m == ECloseNotify) 1665*1a4050f5SDavid du Colombier tlsclosed(tr, SLClose); 1666*1a4050f5SDavid du Colombier 1667*1a4050f5SDavid du Colombier return n; 1668*1a4050f5SDavid du Colombier } else if(strcmp(cb->f[0], "debug") == 0){ 1669*1a4050f5SDavid du Colombier if(cb->nf == 2){ 1670*1a4050f5SDavid du Colombier if(strcmp(cb->f[1], "on") == 0) 1671*1a4050f5SDavid du Colombier tr->debug = 1; 1672*1a4050f5SDavid du Colombier else 1673*1a4050f5SDavid du Colombier tr->debug = 0; 1674*1a4050f5SDavid du Colombier } else 1675*1a4050f5SDavid du Colombier tr->debug = 1; 1676*1a4050f5SDavid du Colombier } else 1677*1a4050f5SDavid du Colombier error(Ebadarg); 1678*1a4050f5SDavid du Colombier 1679*1a4050f5SDavid du Colombier qunlock(&tr->in.seclock); 1680*1a4050f5SDavid du Colombier qunlock(&tr->out.seclock); 1681*1a4050f5SDavid du Colombier poperror(); 1682*1a4050f5SDavid du Colombier free(cb); 1683*1a4050f5SDavid du Colombier poperror(); 1684*1a4050f5SDavid du Colombier 1685*1a4050f5SDavid du Colombier return n; 1686*1a4050f5SDavid du Colombier } 1687*1a4050f5SDavid du Colombier 1688*1a4050f5SDavid du Colombier static void 1689*1a4050f5SDavid du Colombier tlsinit(void) 1690*1a4050f5SDavid du Colombier { 1691*1a4050f5SDavid du Colombier struct Encalg *e; 1692*1a4050f5SDavid du Colombier struct Hashalg *h; 1693*1a4050f5SDavid du Colombier int n; 1694*1a4050f5SDavid du Colombier char *cp; 1695*1a4050f5SDavid du Colombier static int already; 1696*1a4050f5SDavid du Colombier 1697*1a4050f5SDavid du Colombier if(!already){ 1698*1a4050f5SDavid du Colombier fmtinstall('H', encodefmt); 1699*1a4050f5SDavid du Colombier already = 1; 1700*1a4050f5SDavid du Colombier } 1701*1a4050f5SDavid du Colombier 1702*1a4050f5SDavid du Colombier tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs); 1703*1a4050f5SDavid du Colombier trnames = smalloc((sizeof *trnames) * maxtlsdevs); 1704*1a4050f5SDavid du Colombier 1705*1a4050f5SDavid du Colombier n = 1; 1706*1a4050f5SDavid du Colombier for(e = encrypttab; e->name != nil; e++) 1707*1a4050f5SDavid du Colombier n += strlen(e->name) + 1; 1708*1a4050f5SDavid du Colombier cp = encalgs = smalloc(n); 1709*1a4050f5SDavid du Colombier for(e = encrypttab;;){ 1710*1a4050f5SDavid du Colombier strcpy(cp, e->name); 1711*1a4050f5SDavid du Colombier cp += strlen(e->name); 1712*1a4050f5SDavid du Colombier e++; 1713*1a4050f5SDavid du Colombier if(e->name == nil) 1714*1a4050f5SDavid du Colombier break; 1715*1a4050f5SDavid du Colombier *cp++ = ' '; 1716*1a4050f5SDavid du Colombier } 1717*1a4050f5SDavid du Colombier *cp = 0; 1718*1a4050f5SDavid du Colombier 1719*1a4050f5SDavid du Colombier n = 1; 1720*1a4050f5SDavid du Colombier for(h = hashtab; h->name != nil; h++) 1721*1a4050f5SDavid du Colombier n += strlen(h->name) + 1; 1722*1a4050f5SDavid du Colombier cp = hashalgs = smalloc(n); 1723*1a4050f5SDavid du Colombier for(h = hashtab;;){ 1724*1a4050f5SDavid du Colombier strcpy(cp, h->name); 1725*1a4050f5SDavid du Colombier cp += strlen(h->name); 1726*1a4050f5SDavid du Colombier h++; 1727*1a4050f5SDavid du Colombier if(h->name == nil) 1728*1a4050f5SDavid du Colombier break; 1729*1a4050f5SDavid du Colombier *cp++ = ' '; 1730*1a4050f5SDavid du Colombier } 1731*1a4050f5SDavid du Colombier *cp = 0; 1732*1a4050f5SDavid du Colombier } 1733*1a4050f5SDavid du Colombier 1734*1a4050f5SDavid du Colombier Dev tlsdevtab = { 1735*1a4050f5SDavid du Colombier 'a', 1736*1a4050f5SDavid du Colombier "tls", 1737*1a4050f5SDavid du Colombier 1738*1a4050f5SDavid du Colombier devreset, 1739*1a4050f5SDavid du Colombier tlsinit, 1740*1a4050f5SDavid du Colombier devshutdown, 1741*1a4050f5SDavid du Colombier tlsattach, 1742*1a4050f5SDavid du Colombier tlswalk, 1743*1a4050f5SDavid du Colombier tlsstat, 1744*1a4050f5SDavid du Colombier tlsopen, 1745*1a4050f5SDavid du Colombier devcreate, 1746*1a4050f5SDavid du Colombier tlsclose, 1747*1a4050f5SDavid du Colombier tlsread, 1748*1a4050f5SDavid du Colombier tlsbread, 1749*1a4050f5SDavid du Colombier tlswrite, 1750*1a4050f5SDavid du Colombier tlsbwrite, 1751*1a4050f5SDavid du Colombier devremove, 1752*1a4050f5SDavid du Colombier tlswstat, 1753*1a4050f5SDavid du Colombier }; 1754*1a4050f5SDavid du Colombier 1755*1a4050f5SDavid du Colombier /* get channel associated with an fd */ 1756*1a4050f5SDavid du Colombier static Chan* 1757*1a4050f5SDavid du Colombier buftochan(char *p) 1758*1a4050f5SDavid du Colombier { 1759*1a4050f5SDavid du Colombier Chan *c; 1760*1a4050f5SDavid du Colombier int fd; 1761*1a4050f5SDavid du Colombier 1762*1a4050f5SDavid du Colombier if(p == 0) 1763*1a4050f5SDavid du Colombier error(Ebadarg); 1764*1a4050f5SDavid du Colombier fd = strtoul(p, 0, 0); 1765*1a4050f5SDavid du Colombier if(fd < 0) 1766*1a4050f5SDavid du Colombier error(Ebadarg); 1767*1a4050f5SDavid du Colombier c = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ 1768*1a4050f5SDavid du Colombier return c; 1769*1a4050f5SDavid du Colombier } 1770*1a4050f5SDavid du Colombier 1771*1a4050f5SDavid du Colombier static void 1772*1a4050f5SDavid du Colombier sendAlert(TlsRec *tr, int err) 1773*1a4050f5SDavid du Colombier { 1774*1a4050f5SDavid du Colombier Block *b; 1775*1a4050f5SDavid du Colombier int i, fatal; 1776*1a4050f5SDavid du Colombier char *msg; 1777*1a4050f5SDavid du Colombier 1778*1a4050f5SDavid du Colombier if(tr->debug)pprint("sendAlert %d\n", err); 1779*1a4050f5SDavid du Colombier fatal = 1; 1780*1a4050f5SDavid du Colombier msg = "tls unknown alert"; 1781*1a4050f5SDavid du Colombier for(i=0; i < nelem(tlserrs); i++) { 1782*1a4050f5SDavid du Colombier if(tlserrs[i].err == err) { 1783*1a4050f5SDavid du Colombier msg = tlserrs[i].msg; 1784*1a4050f5SDavid du Colombier if(tr->version == SSL3Version) 1785*1a4050f5SDavid du Colombier err = tlserrs[i].sslerr; 1786*1a4050f5SDavid du Colombier else 1787*1a4050f5SDavid du Colombier err = tlserrs[i].tlserr; 1788*1a4050f5SDavid du Colombier fatal = tlserrs[i].fatal; 1789*1a4050f5SDavid du Colombier break; 1790*1a4050f5SDavid du Colombier } 1791*1a4050f5SDavid du Colombier } 1792*1a4050f5SDavid du Colombier 1793*1a4050f5SDavid du Colombier if(!waserror()){ 1794*1a4050f5SDavid du Colombier b = allocb(2); 1795*1a4050f5SDavid du Colombier *b->wp++ = fatal + 1; 1796*1a4050f5SDavid du Colombier *b->wp++ = err; 1797*1a4050f5SDavid du Colombier if(fatal) 1798*1a4050f5SDavid du Colombier tlsSetState(tr, SAlert, SOpen|SHandshake|SRClose); 1799*1a4050f5SDavid du Colombier tlsrecwrite(tr, RAlert, b); 1800*1a4050f5SDavid du Colombier poperror(); 1801*1a4050f5SDavid du Colombier } 1802*1a4050f5SDavid du Colombier if(fatal) 1803*1a4050f5SDavid du Colombier tlsError(tr, msg); 1804*1a4050f5SDavid du Colombier } 1805*1a4050f5SDavid du Colombier 1806*1a4050f5SDavid du Colombier static void 1807*1a4050f5SDavid du Colombier tlsError(TlsRec *tr, char *msg) 1808*1a4050f5SDavid du Colombier { 1809*1a4050f5SDavid du Colombier int s; 1810*1a4050f5SDavid du Colombier 1811*1a4050f5SDavid du Colombier if(tr->debug)pprint("tleError %s\n", msg); 1812*1a4050f5SDavid du Colombier lock(&tr->statelk); 1813*1a4050f5SDavid du Colombier s = tr->state; 1814*1a4050f5SDavid du Colombier tr->state = SError; 1815*1a4050f5SDavid du Colombier if(s != SError){ 1816*1a4050f5SDavid du Colombier strncpy(tr->err, msg, ERRMAX - 1); 1817*1a4050f5SDavid du Colombier tr->err[ERRMAX - 1] = '\0'; 1818*1a4050f5SDavid du Colombier } 1819*1a4050f5SDavid du Colombier unlock(&tr->statelk); 1820*1a4050f5SDavid du Colombier if(s != SError) 1821*1a4050f5SDavid du Colombier alertHand(tr, msg); 1822*1a4050f5SDavid du Colombier } 1823*1a4050f5SDavid du Colombier 1824*1a4050f5SDavid du Colombier static void 1825*1a4050f5SDavid du Colombier tlsSetState(TlsRec *tr, int new, int old) 1826*1a4050f5SDavid du Colombier { 1827*1a4050f5SDavid du Colombier lock(&tr->statelk); 1828*1a4050f5SDavid du Colombier if(tr->state & old) 1829*1a4050f5SDavid du Colombier tr->state = new; 1830*1a4050f5SDavid du Colombier unlock(&tr->statelk); 1831*1a4050f5SDavid du Colombier } 1832*1a4050f5SDavid du Colombier 1833*1a4050f5SDavid du Colombier /* hand up a digest connection */ 1834*1a4050f5SDavid du Colombier static void 1835*1a4050f5SDavid du Colombier tlshangup(TlsRec *tr) 1836*1a4050f5SDavid du Colombier { 1837*1a4050f5SDavid du Colombier Block *b; 1838*1a4050f5SDavid du Colombier 1839*1a4050f5SDavid du Colombier qlock(&tr->in.io); 1840*1a4050f5SDavid du Colombier for(b = tr->processed; b; b = tr->processed){ 1841*1a4050f5SDavid du Colombier tr->processed = b->next; 1842*1a4050f5SDavid du Colombier freeb(b); 1843*1a4050f5SDavid du Colombier } 1844*1a4050f5SDavid du Colombier if(tr->unprocessed != nil){ 1845*1a4050f5SDavid du Colombier freeb(tr->unprocessed); 1846*1a4050f5SDavid du Colombier tr->unprocessed = nil; 1847*1a4050f5SDavid du Colombier } 1848*1a4050f5SDavid du Colombier qunlock(&tr->in.io); 1849*1a4050f5SDavid du Colombier 1850*1a4050f5SDavid du Colombier tlsSetState(tr, SClosed, ~0); 1851*1a4050f5SDavid du Colombier } 1852*1a4050f5SDavid du Colombier 1853*1a4050f5SDavid du Colombier static TlsRec* 1854*1a4050f5SDavid du Colombier newtls(Chan *ch) 1855*1a4050f5SDavid du Colombier { 1856*1a4050f5SDavid du Colombier TlsRec **pp, **ep, **np; 1857*1a4050f5SDavid du Colombier char **nmp; 1858*1a4050f5SDavid du Colombier int t, newmax; 1859*1a4050f5SDavid du Colombier 1860*1a4050f5SDavid du Colombier if(waserror()) { 1861*1a4050f5SDavid du Colombier unlock(&tdlock); 1862*1a4050f5SDavid du Colombier nexterror(); 1863*1a4050f5SDavid du Colombier } 1864*1a4050f5SDavid du Colombier lock(&tdlock); 1865*1a4050f5SDavid du Colombier ep = &tlsdevs[maxtlsdevs]; 1866*1a4050f5SDavid du Colombier for(pp = tlsdevs; pp < ep; pp++) 1867*1a4050f5SDavid du Colombier if(*pp == nil) 1868*1a4050f5SDavid du Colombier break; 1869*1a4050f5SDavid du Colombier if(pp >= ep) { 1870*1a4050f5SDavid du Colombier if(maxtlsdevs >= MaxTlsDevs) { 1871*1a4050f5SDavid du Colombier unlock(&tdlock); 1872*1a4050f5SDavid du Colombier poperror(); 1873*1a4050f5SDavid du Colombier return nil; 1874*1a4050f5SDavid du Colombier } 1875*1a4050f5SDavid du Colombier newmax = 2 * maxtlsdevs; 1876*1a4050f5SDavid du Colombier if(newmax > MaxTlsDevs) 1877*1a4050f5SDavid du Colombier newmax = MaxTlsDevs; 1878*1a4050f5SDavid du Colombier np = smalloc(sizeof(TlsRec*) * newmax); 1879*1a4050f5SDavid du Colombier memmove(np, tlsdevs, sizeof(TlsRec*) * maxtlsdevs); 1880*1a4050f5SDavid du Colombier tlsdevs = np; 1881*1a4050f5SDavid du Colombier pp = &tlsdevs[maxtlsdevs]; 1882*1a4050f5SDavid du Colombier memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs)); 1883*1a4050f5SDavid du Colombier 1884*1a4050f5SDavid du Colombier nmp = smalloc(sizeof *nmp * newmax); 1885*1a4050f5SDavid du Colombier memmove(nmp, trnames, sizeof *nmp * maxtlsdevs); 1886*1a4050f5SDavid du Colombier trnames = nmp; 1887*1a4050f5SDavid du Colombier 1888*1a4050f5SDavid du Colombier maxtlsdevs = newmax; 1889*1a4050f5SDavid du Colombier } 1890*1a4050f5SDavid du Colombier *pp = mktlsrec(); 1891*1a4050f5SDavid du Colombier if(pp - tlsdevs >= tdhiwat) 1892*1a4050f5SDavid du Colombier tdhiwat++; 1893*1a4050f5SDavid du Colombier t = TYPE(ch->qid); 1894*1a4050f5SDavid du Colombier if(t == Qclonus) 1895*1a4050f5SDavid du Colombier t = Qctl; 1896*1a4050f5SDavid du Colombier ch->qid.path = QID(pp - tlsdevs, t); 1897*1a4050f5SDavid du Colombier ch->qid.vers = 0; 1898*1a4050f5SDavid du Colombier unlock(&tdlock); 1899*1a4050f5SDavid du Colombier poperror(); 1900*1a4050f5SDavid du Colombier return *pp; 1901*1a4050f5SDavid du Colombier } 1902*1a4050f5SDavid du Colombier 1903*1a4050f5SDavid du Colombier static TlsRec * 1904*1a4050f5SDavid du Colombier mktlsrec(void) 1905*1a4050f5SDavid du Colombier { 1906*1a4050f5SDavid du Colombier TlsRec *tr; 1907*1a4050f5SDavid du Colombier 1908*1a4050f5SDavid du Colombier tr = mallocz(sizeof(*tr), 1); 1909*1a4050f5SDavid du Colombier if(tr == nil) 1910*1a4050f5SDavid du Colombier error(Enomem); 1911*1a4050f5SDavid du Colombier tr->state = SClosed; 1912*1a4050f5SDavid du Colombier tr->ref = 1; 1913*1a4050f5SDavid du Colombier kstrdup(&tr->user, up->user); 1914*1a4050f5SDavid du Colombier tr->perm = 0660; 1915*1a4050f5SDavid du Colombier return tr; 1916*1a4050f5SDavid du Colombier } 1917*1a4050f5SDavid du Colombier 1918*1a4050f5SDavid du Colombier static char* 1919*1a4050f5SDavid du Colombier tlsstate(int s) 1920*1a4050f5SDavid du Colombier { 1921*1a4050f5SDavid du Colombier switch(s){ 1922*1a4050f5SDavid du Colombier case SHandshake: 1923*1a4050f5SDavid du Colombier return "Handshaking"; 1924*1a4050f5SDavid du Colombier case SOpen: 1925*1a4050f5SDavid du Colombier return "Established"; 1926*1a4050f5SDavid du Colombier case SRClose: 1927*1a4050f5SDavid du Colombier return "RemoteClosed"; 1928*1a4050f5SDavid du Colombier case SLClose: 1929*1a4050f5SDavid du Colombier return "LocalClosed"; 1930*1a4050f5SDavid du Colombier case SAlert: 1931*1a4050f5SDavid du Colombier return "Alerting"; 1932*1a4050f5SDavid du Colombier case SError: 1933*1a4050f5SDavid du Colombier return "Errored"; 1934*1a4050f5SDavid du Colombier case SClosed: 1935*1a4050f5SDavid du Colombier return "Closed"; 1936*1a4050f5SDavid du Colombier } 1937*1a4050f5SDavid du Colombier return "Unknown"; 1938*1a4050f5SDavid du Colombier } 1939*1a4050f5SDavid du Colombier 1940*1a4050f5SDavid du Colombier static void 1941*1a4050f5SDavid du Colombier freeSec(Secret *s) 1942*1a4050f5SDavid du Colombier { 1943*1a4050f5SDavid du Colombier if(s != nil){ 1944*1a4050f5SDavid du Colombier free(s->enckey); 1945*1a4050f5SDavid du Colombier free(s); 1946*1a4050f5SDavid du Colombier } 1947*1a4050f5SDavid du Colombier } 1948*1a4050f5SDavid du Colombier 1949*1a4050f5SDavid du Colombier static int 1950*1a4050f5SDavid du Colombier noenc(Secret *unused1, uchar *unused2, int n) 1951*1a4050f5SDavid du Colombier { 1952*1a4050f5SDavid du Colombier return n; 1953*1a4050f5SDavid du Colombier } 1954*1a4050f5SDavid du Colombier 1955*1a4050f5SDavid du Colombier static int 1956*1a4050f5SDavid du Colombier rc4enc(Secret *sec, uchar *buf, int n) 1957*1a4050f5SDavid du Colombier { 1958*1a4050f5SDavid du Colombier rc4(sec->enckey, buf, n); 1959*1a4050f5SDavid du Colombier return n; 1960*1a4050f5SDavid du Colombier } 1961*1a4050f5SDavid du Colombier 1962*1a4050f5SDavid du Colombier static int 1963*1a4050f5SDavid du Colombier tlsunpad(uchar *buf, int n, int block) 1964*1a4050f5SDavid du Colombier { 1965*1a4050f5SDavid du Colombier int pad, nn; 1966*1a4050f5SDavid du Colombier 1967*1a4050f5SDavid du Colombier pad = buf[n - 1]; 1968*1a4050f5SDavid du Colombier nn = n - 1 - pad; 1969*1a4050f5SDavid du Colombier if(nn <= 0 || n % block) 1970*1a4050f5SDavid du Colombier return -1; 1971*1a4050f5SDavid du Colombier while(--n > nn) 1972*1a4050f5SDavid du Colombier if(pad != buf[n - 1]) 1973*1a4050f5SDavid du Colombier return -1; 1974*1a4050f5SDavid du Colombier return nn; 1975*1a4050f5SDavid du Colombier } 1976*1a4050f5SDavid du Colombier 1977*1a4050f5SDavid du Colombier static int 1978*1a4050f5SDavid du Colombier sslunpad(uchar *buf, int n, int block) 1979*1a4050f5SDavid du Colombier { 1980*1a4050f5SDavid du Colombier int pad, nn; 1981*1a4050f5SDavid du Colombier 1982*1a4050f5SDavid du Colombier pad = buf[n - 1]; 1983*1a4050f5SDavid du Colombier nn = n - 1 - pad; 1984*1a4050f5SDavid du Colombier if(nn <= 0 || n % block) 1985*1a4050f5SDavid du Colombier return -1; 1986*1a4050f5SDavid du Colombier return nn; 1987*1a4050f5SDavid du Colombier } 1988*1a4050f5SDavid du Colombier 1989*1a4050f5SDavid du Colombier static int 1990*1a4050f5SDavid du Colombier blockpad(uchar *buf, int n, int block) 1991*1a4050f5SDavid du Colombier { 1992*1a4050f5SDavid du Colombier int pad, nn; 1993*1a4050f5SDavid du Colombier 1994*1a4050f5SDavid du Colombier nn = n + block; 1995*1a4050f5SDavid du Colombier nn -= nn % block; 1996*1a4050f5SDavid du Colombier pad = nn - (n + 1); 1997*1a4050f5SDavid du Colombier while(n < nn) 1998*1a4050f5SDavid du Colombier buf[n++] = pad; 1999*1a4050f5SDavid du Colombier return nn; 2000*1a4050f5SDavid du Colombier } 2001*1a4050f5SDavid du Colombier 2002*1a4050f5SDavid du Colombier static int 2003*1a4050f5SDavid du Colombier des3enc(Secret *sec, uchar *buf, int n) 2004*1a4050f5SDavid du Colombier { 2005*1a4050f5SDavid du Colombier n = blockpad(buf, n, 8); 2006*1a4050f5SDavid du Colombier des3CBCencrypt(buf, n, sec->enckey); 2007*1a4050f5SDavid du Colombier return n; 2008*1a4050f5SDavid du Colombier } 2009*1a4050f5SDavid du Colombier 2010*1a4050f5SDavid du Colombier static int 2011*1a4050f5SDavid du Colombier des3dec(Secret *sec, uchar *buf, int n) 2012*1a4050f5SDavid du Colombier { 2013*1a4050f5SDavid du Colombier des3CBCdecrypt(buf, n, sec->enckey); 2014*1a4050f5SDavid du Colombier return (*sec->unpad)(buf, n, 8); 2015*1a4050f5SDavid du Colombier } 2016*1a4050f5SDavid du Colombier static DigestState* 2017*1a4050f5SDavid du Colombier nomac(uchar *unused1, ulong unused2, uchar *unused3, ulong unused4, 2018*1a4050f5SDavid du Colombier uchar *unused5, DigestState *unused6) 2019*1a4050f5SDavid du Colombier { 2020*1a4050f5SDavid du Colombier return nil; 2021*1a4050f5SDavid du Colombier } 2022*1a4050f5SDavid du Colombier 2023*1a4050f5SDavid du Colombier /* 2024*1a4050f5SDavid du Colombier * sslmac: mac calculations for ssl 3.0 only; tls 1.0 uses the standard hmac. 2025*1a4050f5SDavid du Colombier */ 2026*1a4050f5SDavid du Colombier static DigestState* 2027*1a4050f5SDavid du Colombier sslmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, 2028*1a4050f5SDavid du Colombier DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen, int padlen) 2029*1a4050f5SDavid du Colombier { 2030*1a4050f5SDavid du Colombier int i; 2031*1a4050f5SDavid du Colombier uchar pad[48], innerdigest[20]; 2032*1a4050f5SDavid du Colombier 2033*1a4050f5SDavid du Colombier if(xlen > sizeof(innerdigest) 2034*1a4050f5SDavid du Colombier || padlen > sizeof(pad)) 2035*1a4050f5SDavid du Colombier return nil; 2036*1a4050f5SDavid du Colombier 2037*1a4050f5SDavid du Colombier if(klen>64) 2038*1a4050f5SDavid du Colombier return nil; 2039*1a4050f5SDavid du Colombier 2040*1a4050f5SDavid du Colombier /* first time through */ 2041*1a4050f5SDavid du Colombier if(s == nil){ 2042*1a4050f5SDavid du Colombier for(i=0; i<padlen; i++) 2043*1a4050f5SDavid du Colombier pad[i] = 0x36; 2044*1a4050f5SDavid du Colombier s = (*x)(key, klen, nil, nil); 2045*1a4050f5SDavid du Colombier s = (*x)(pad, padlen, nil, s); 2046*1a4050f5SDavid du Colombier if(s == nil) 2047*1a4050f5SDavid du Colombier return nil; 2048*1a4050f5SDavid du Colombier } 2049*1a4050f5SDavid du Colombier 2050*1a4050f5SDavid du Colombier s = (*x)(p, len, nil, s); 2051*1a4050f5SDavid du Colombier if(digest == nil) 2052*1a4050f5SDavid du Colombier return s; 2053*1a4050f5SDavid du Colombier 2054*1a4050f5SDavid du Colombier /* last time through */ 2055*1a4050f5SDavid du Colombier for(i=0; i<padlen; i++) 2056*1a4050f5SDavid du Colombier pad[i] = 0x5c; 2057*1a4050f5SDavid du Colombier (*x)(nil, 0, innerdigest, s); 2058*1a4050f5SDavid du Colombier s = (*x)(key, klen, nil, nil); 2059*1a4050f5SDavid du Colombier s = (*x)(pad, padlen, nil, s); 2060*1a4050f5SDavid du Colombier (*x)(innerdigest, xlen, digest, s); 2061*1a4050f5SDavid du Colombier return nil; 2062*1a4050f5SDavid du Colombier } 2063*1a4050f5SDavid du Colombier 2064*1a4050f5SDavid du Colombier static DigestState* 2065*1a4050f5SDavid du Colombier sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s) 2066*1a4050f5SDavid du Colombier { 2067*1a4050f5SDavid du Colombier return sslmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen, 40); 2068*1a4050f5SDavid du Colombier } 2069*1a4050f5SDavid du Colombier 2070*1a4050f5SDavid du Colombier static DigestState* 2071*1a4050f5SDavid du Colombier sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s) 2072*1a4050f5SDavid du Colombier { 2073*1a4050f5SDavid du Colombier return sslmac_x(p, len, key, klen, digest, s, md5, MD5dlen, 48); 2074*1a4050f5SDavid du Colombier } 2075*1a4050f5SDavid du Colombier 2076*1a4050f5SDavid du Colombier static void 2077*1a4050f5SDavid du Colombier sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac) 2078*1a4050f5SDavid du Colombier { 2079*1a4050f5SDavid du Colombier DigestState *s; 2080*1a4050f5SDavid du Colombier uchar buf[11]; 2081*1a4050f5SDavid du Colombier 2082*1a4050f5SDavid du Colombier memmove(buf, seq, 8); 2083*1a4050f5SDavid du Colombier buf[8] = header[0]; 2084*1a4050f5SDavid du Colombier buf[9] = header[3]; 2085*1a4050f5SDavid du Colombier buf[10] = header[4]; 2086*1a4050f5SDavid du Colombier 2087*1a4050f5SDavid du Colombier s = (*sec->mac)(buf, 11, mackey, sec->maclen, 0, 0); 2088*1a4050f5SDavid du Colombier (*sec->mac)(body, len, mackey, sec->maclen, mac, s); 2089*1a4050f5SDavid du Colombier } 2090*1a4050f5SDavid du Colombier 2091*1a4050f5SDavid du Colombier static void 2092*1a4050f5SDavid du Colombier tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac) 2093*1a4050f5SDavid du Colombier { 2094*1a4050f5SDavid du Colombier DigestState *s; 2095*1a4050f5SDavid du Colombier uchar buf[13]; 2096*1a4050f5SDavid du Colombier 2097*1a4050f5SDavid du Colombier memmove(buf, seq, 8); 2098*1a4050f5SDavid du Colombier memmove(&buf[8], header, 5); 2099*1a4050f5SDavid du Colombier 2100*1a4050f5SDavid du Colombier s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0); 2101*1a4050f5SDavid du Colombier (*sec->mac)(body, len, mackey, sec->maclen, mac, s); 2102*1a4050f5SDavid du Colombier } 2103*1a4050f5SDavid du Colombier 2104*1a4050f5SDavid du Colombier static void 2105*1a4050f5SDavid du Colombier put32(uchar *p, u32int x) 2106*1a4050f5SDavid du Colombier { 2107*1a4050f5SDavid du Colombier p[0] = x>>24; 2108*1a4050f5SDavid du Colombier p[1] = x>>16; 2109*1a4050f5SDavid du Colombier p[2] = x>>8; 2110*1a4050f5SDavid du Colombier p[3] = x; 2111*1a4050f5SDavid du Colombier } 2112*1a4050f5SDavid du Colombier 2113*1a4050f5SDavid du Colombier static void 2114*1a4050f5SDavid du Colombier put64(uchar *p, vlong x) 2115*1a4050f5SDavid du Colombier { 2116*1a4050f5SDavid du Colombier put32(p, (u32int)(x >> 32)); 2117*1a4050f5SDavid du Colombier put32(p+4, (u32int)x); 2118*1a4050f5SDavid du Colombier } 2119*1a4050f5SDavid du Colombier 2120*1a4050f5SDavid du Colombier static void 2121*1a4050f5SDavid du Colombier put24(uchar *p, int x) 2122*1a4050f5SDavid du Colombier { 2123*1a4050f5SDavid du Colombier p[0] = x>>16; 2124*1a4050f5SDavid du Colombier p[1] = x>>8; 2125*1a4050f5SDavid du Colombier p[2] = x; 2126*1a4050f5SDavid du Colombier } 2127*1a4050f5SDavid du Colombier 2128*1a4050f5SDavid du Colombier static void 2129*1a4050f5SDavid du Colombier put16(uchar *p, int x) 2130*1a4050f5SDavid du Colombier { 2131*1a4050f5SDavid du Colombier p[0] = x>>8; 2132*1a4050f5SDavid du Colombier p[1] = x; 2133*1a4050f5SDavid du Colombier } 2134*1a4050f5SDavid du Colombier 2135*1a4050f5SDavid du Colombier static u32int 2136*1a4050f5SDavid du Colombier get32(uchar *p) 2137*1a4050f5SDavid du Colombier { 2138*1a4050f5SDavid du Colombier return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; 2139*1a4050f5SDavid du Colombier } 2140*1a4050f5SDavid du Colombier 2141*1a4050f5SDavid du Colombier static int 2142*1a4050f5SDavid du Colombier get16(uchar *p) 2143*1a4050f5SDavid du Colombier { 2144*1a4050f5SDavid du Colombier return (p[0]<<8)|p[1]; 2145*1a4050f5SDavid du Colombier } 2146*1a4050f5SDavid du Colombier 2147*1a4050f5SDavid du Colombier static char *charmap = "0123456789abcdef"; 2148*1a4050f5SDavid du Colombier 2149*1a4050f5SDavid du Colombier static void 2150*1a4050f5SDavid du Colombier pdump(int len, void *a, char *tag) 2151*1a4050f5SDavid du Colombier { 2152*1a4050f5SDavid du Colombier uchar *p; 2153*1a4050f5SDavid du Colombier int i; 2154*1a4050f5SDavid du Colombier char buf[65+32]; 2155*1a4050f5SDavid du Colombier char *q; 2156*1a4050f5SDavid du Colombier 2157*1a4050f5SDavid du Colombier p = a; 2158*1a4050f5SDavid du Colombier strcpy(buf, tag); 2159*1a4050f5SDavid du Colombier while(len > 0){ 2160*1a4050f5SDavid du Colombier q = buf + strlen(tag); 2161*1a4050f5SDavid du Colombier for(i = 0; len > 0 && i < 32; i++){ 2162*1a4050f5SDavid du Colombier if(*p >= ' ' && *p < 0x7f){ 2163*1a4050f5SDavid du Colombier *q++ = ' '; 2164*1a4050f5SDavid du Colombier *q++ = *p; 2165*1a4050f5SDavid du Colombier } else { 2166*1a4050f5SDavid du Colombier *q++ = charmap[*p>>4]; 2167*1a4050f5SDavid du Colombier *q++ = charmap[*p & 0xf]; 2168*1a4050f5SDavid du Colombier } 2169*1a4050f5SDavid du Colombier len--; 2170*1a4050f5SDavid du Colombier p++; 2171*1a4050f5SDavid du Colombier } 2172*1a4050f5SDavid du Colombier *q = 0; 2173*1a4050f5SDavid du Colombier 2174*1a4050f5SDavid du Colombier if(len > 0) 2175*1a4050f5SDavid du Colombier pprint("%s...\n", buf); 2176*1a4050f5SDavid du Colombier else 2177*1a4050f5SDavid du Colombier pprint("%s\n", buf); 2178*1a4050f5SDavid du Colombier } 2179*1a4050f5SDavid du Colombier } 2180