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