xref: /plan9/sys/src/9/ppc/devtls.c (revision 458db83292ea45506704800dedf36a95598fc2ec)
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