xref: /plan9/sys/src/cmd/unix/drawterm/libsec/tlshand.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <bio.h>
4*8ccd4a63SDavid du Colombier #include <auth.h>
5*8ccd4a63SDavid du Colombier #include <mp.h>
6*8ccd4a63SDavid du Colombier #include <libsec.h>
7*8ccd4a63SDavid du Colombier 
8*8ccd4a63SDavid du Colombier // The main groups of functions are:
9*8ccd4a63SDavid du Colombier //		client/server - main handshake protocol definition
10*8ccd4a63SDavid du Colombier //		message functions - formating handshake messages
11*8ccd4a63SDavid du Colombier //		cipher choices - catalog of digest and encrypt algorithms
12*8ccd4a63SDavid du Colombier //		security functions - PKCS#1, sslHMAC, session keygen
13*8ccd4a63SDavid du Colombier //		general utility functions - malloc, serialization
14*8ccd4a63SDavid du Colombier // The handshake protocol builds on the TLS/SSL3 record layer protocol,
15*8ccd4a63SDavid du Colombier // which is implemented in kernel device #a.  See also /lib/rfc/rfc2246.
16*8ccd4a63SDavid du Colombier 
17*8ccd4a63SDavid du Colombier enum {
18*8ccd4a63SDavid du Colombier 	TLSFinishedLen = 12,
19*8ccd4a63SDavid du Colombier 	SSL3FinishedLen = MD5dlen+SHA1dlen,
20*8ccd4a63SDavid du Colombier 	MaxKeyData = 104,	// amount of secret we may need
21*8ccd4a63SDavid du Colombier 	MaxChunk = 1<<14,
22*8ccd4a63SDavid du Colombier 	RandomSize = 32,
23*8ccd4a63SDavid du Colombier 	SidSize = 32,
24*8ccd4a63SDavid du Colombier 	MasterSecretSize = 48,
25*8ccd4a63SDavid du Colombier 	AQueue = 0,
26*8ccd4a63SDavid du Colombier 	AFlush = 1,
27*8ccd4a63SDavid du Colombier };
28*8ccd4a63SDavid du Colombier 
29*8ccd4a63SDavid du Colombier typedef struct TlsSec TlsSec;
30*8ccd4a63SDavid du Colombier 
31*8ccd4a63SDavid du Colombier typedef struct Bytes{
32*8ccd4a63SDavid du Colombier 	int len;
33*8ccd4a63SDavid du Colombier 	uchar data[1];  // [len]
34*8ccd4a63SDavid du Colombier } Bytes;
35*8ccd4a63SDavid du Colombier 
36*8ccd4a63SDavid du Colombier typedef struct Ints{
37*8ccd4a63SDavid du Colombier 	int len;
38*8ccd4a63SDavid du Colombier 	int data[1];  // [len]
39*8ccd4a63SDavid du Colombier } Ints;
40*8ccd4a63SDavid du Colombier 
41*8ccd4a63SDavid du Colombier typedef struct Algs{
42*8ccd4a63SDavid du Colombier 	char *enc;
43*8ccd4a63SDavid du Colombier 	char *digest;
44*8ccd4a63SDavid du Colombier 	int nsecret;
45*8ccd4a63SDavid du Colombier 	int tlsid;
46*8ccd4a63SDavid du Colombier 	int ok;
47*8ccd4a63SDavid du Colombier } Algs;
48*8ccd4a63SDavid du Colombier 
49*8ccd4a63SDavid du Colombier typedef struct Finished{
50*8ccd4a63SDavid du Colombier 	uchar verify[SSL3FinishedLen];
51*8ccd4a63SDavid du Colombier 	int n;
52*8ccd4a63SDavid du Colombier } Finished;
53*8ccd4a63SDavid du Colombier 
54*8ccd4a63SDavid du Colombier typedef struct TlsConnection{
55*8ccd4a63SDavid du Colombier 	TlsSec *sec;	// security management goo
56*8ccd4a63SDavid du Colombier 	int hand, ctl;	// record layer file descriptors
57*8ccd4a63SDavid du Colombier 	int erred;		// set when tlsError called
58*8ccd4a63SDavid du Colombier 	int (*trace)(char*fmt, ...); // for debugging
59*8ccd4a63SDavid du Colombier 	int version;	// protocol we are speaking
60*8ccd4a63SDavid du Colombier 	int verset;		// version has been set
61*8ccd4a63SDavid du Colombier 	int ver2hi;		// server got a version 2 hello
62*8ccd4a63SDavid du Colombier 	int isClient;	// is this the client or server?
63*8ccd4a63SDavid du Colombier 	Bytes *sid;		// SessionID
64*8ccd4a63SDavid du Colombier 	Bytes *cert;	// only last - no chain
65*8ccd4a63SDavid du Colombier 
66*8ccd4a63SDavid du Colombier 	Lock statelk;
67*8ccd4a63SDavid du Colombier 	int state;		// must be set using setstate
68*8ccd4a63SDavid du Colombier 
69*8ccd4a63SDavid du Colombier 	// input buffer for handshake messages
70*8ccd4a63SDavid du Colombier 	uchar buf[MaxChunk+2048];
71*8ccd4a63SDavid du Colombier 	uchar *rp, *ep;
72*8ccd4a63SDavid du Colombier 
73*8ccd4a63SDavid du Colombier 	uchar crandom[RandomSize];	// client random
74*8ccd4a63SDavid du Colombier 	uchar srandom[RandomSize];	// server random
75*8ccd4a63SDavid du Colombier 	int clientVersion;	// version in ClientHello
76*8ccd4a63SDavid du Colombier 	char *digest;	// name of digest algorithm to use
77*8ccd4a63SDavid du Colombier 	char *enc;		// name of encryption algorithm to use
78*8ccd4a63SDavid du Colombier 	int nsecret;	// amount of secret data to init keys
79*8ccd4a63SDavid du Colombier 
80*8ccd4a63SDavid du Colombier 	// for finished messages
81*8ccd4a63SDavid du Colombier 	MD5state	hsmd5;	// handshake hash
82*8ccd4a63SDavid du Colombier 	SHAstate	hssha1;	// handshake hash
83*8ccd4a63SDavid du Colombier 	Finished	finished;
84*8ccd4a63SDavid du Colombier } TlsConnection;
85*8ccd4a63SDavid du Colombier 
86*8ccd4a63SDavid du Colombier typedef struct Msg{
87*8ccd4a63SDavid du Colombier 	int tag;
88*8ccd4a63SDavid du Colombier 	union {
89*8ccd4a63SDavid du Colombier 		struct {
90*8ccd4a63SDavid du Colombier 			int version;
91*8ccd4a63SDavid du Colombier 			uchar 	random[RandomSize];
92*8ccd4a63SDavid du Colombier 			Bytes*	sid;
93*8ccd4a63SDavid du Colombier 			Ints*	ciphers;
94*8ccd4a63SDavid du Colombier 			Bytes*	compressors;
95*8ccd4a63SDavid du Colombier 		} clientHello;
96*8ccd4a63SDavid du Colombier 		struct {
97*8ccd4a63SDavid du Colombier 			int version;
98*8ccd4a63SDavid du Colombier 			uchar 	random[RandomSize];
99*8ccd4a63SDavid du Colombier 			Bytes*	sid;
100*8ccd4a63SDavid du Colombier 			int cipher;
101*8ccd4a63SDavid du Colombier 			int compressor;
102*8ccd4a63SDavid du Colombier 		} serverHello;
103*8ccd4a63SDavid du Colombier 		struct {
104*8ccd4a63SDavid du Colombier 			int ncert;
105*8ccd4a63SDavid du Colombier 			Bytes **certs;
106*8ccd4a63SDavid du Colombier 		} certificate;
107*8ccd4a63SDavid du Colombier 		struct {
108*8ccd4a63SDavid du Colombier 			Bytes *types;
109*8ccd4a63SDavid du Colombier 			int nca;
110*8ccd4a63SDavid du Colombier 			Bytes **cas;
111*8ccd4a63SDavid du Colombier 		} certificateRequest;
112*8ccd4a63SDavid du Colombier 		struct {
113*8ccd4a63SDavid du Colombier 			Bytes *key;
114*8ccd4a63SDavid du Colombier 		} clientKeyExchange;
115*8ccd4a63SDavid du Colombier 		Finished finished;
116*8ccd4a63SDavid du Colombier 	} u;
117*8ccd4a63SDavid du Colombier } Msg;
118*8ccd4a63SDavid du Colombier 
119*8ccd4a63SDavid du Colombier typedef struct TlsSec{
120*8ccd4a63SDavid du Colombier 	char *server;	// name of remote; nil for server
121*8ccd4a63SDavid du Colombier 	int ok;	// <0 killed; ==0 in progress; >0 reusable
122*8ccd4a63SDavid du Colombier 	RSApub *rsapub;
123*8ccd4a63SDavid du Colombier 	AuthRpc *rpc;	// factotum for rsa private key
124*8ccd4a63SDavid du Colombier 	uchar sec[MasterSecretSize];	// master secret
125*8ccd4a63SDavid du Colombier 	uchar crandom[RandomSize];	// client random
126*8ccd4a63SDavid du Colombier 	uchar srandom[RandomSize];	// server random
127*8ccd4a63SDavid du Colombier 	int clientVers;		// version in ClientHello
128*8ccd4a63SDavid du Colombier 	int vers;			// final version
129*8ccd4a63SDavid du Colombier 	// byte generation and handshake checksum
130*8ccd4a63SDavid du Colombier 	void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
131*8ccd4a63SDavid du Colombier 	void (*setFinished)(TlsSec*, MD5state, SHAstate, uchar*, int);
132*8ccd4a63SDavid du Colombier 	int nfin;
133*8ccd4a63SDavid du Colombier } TlsSec;
134*8ccd4a63SDavid du Colombier 
135*8ccd4a63SDavid du Colombier 
136*8ccd4a63SDavid du Colombier enum {
137*8ccd4a63SDavid du Colombier 	TLSVersion = 0x0301,
138*8ccd4a63SDavid du Colombier 	SSL3Version = 0x0300,
139*8ccd4a63SDavid du Colombier 	ProtocolVersion = 0x0301,	// maximum version we speak
140*8ccd4a63SDavid du Colombier 	MinProtoVersion = 0x0300,	// limits on version we accept
141*8ccd4a63SDavid du Colombier 	MaxProtoVersion	= 0x03ff,
142*8ccd4a63SDavid du Colombier };
143*8ccd4a63SDavid du Colombier 
144*8ccd4a63SDavid du Colombier // handshake type
145*8ccd4a63SDavid du Colombier enum {
146*8ccd4a63SDavid du Colombier 	HHelloRequest,
147*8ccd4a63SDavid du Colombier 	HClientHello,
148*8ccd4a63SDavid du Colombier 	HServerHello,
149*8ccd4a63SDavid du Colombier 	HSSL2ClientHello = 9,  /* local convention;  see devtls.c */
150*8ccd4a63SDavid du Colombier 	HCertificate = 11,
151*8ccd4a63SDavid du Colombier 	HServerKeyExchange,
152*8ccd4a63SDavid du Colombier 	HCertificateRequest,
153*8ccd4a63SDavid du Colombier 	HServerHelloDone,
154*8ccd4a63SDavid du Colombier 	HCertificateVerify,
155*8ccd4a63SDavid du Colombier 	HClientKeyExchange,
156*8ccd4a63SDavid du Colombier 	HFinished = 20,
157*8ccd4a63SDavid du Colombier 	HMax
158*8ccd4a63SDavid du Colombier };
159*8ccd4a63SDavid du Colombier 
160*8ccd4a63SDavid du Colombier // alerts
161*8ccd4a63SDavid du Colombier enum {
162*8ccd4a63SDavid du Colombier 	ECloseNotify = 0,
163*8ccd4a63SDavid du Colombier 	EUnexpectedMessage = 10,
164*8ccd4a63SDavid du Colombier 	EBadRecordMac = 20,
165*8ccd4a63SDavid du Colombier 	EDecryptionFailed = 21,
166*8ccd4a63SDavid du Colombier 	ERecordOverflow = 22,
167*8ccd4a63SDavid du Colombier 	EDecompressionFailure = 30,
168*8ccd4a63SDavid du Colombier 	EHandshakeFailure = 40,
169*8ccd4a63SDavid du Colombier 	ENoCertificate = 41,
170*8ccd4a63SDavid du Colombier 	EBadCertificate = 42,
171*8ccd4a63SDavid du Colombier 	EUnsupportedCertificate = 43,
172*8ccd4a63SDavid du Colombier 	ECertificateRevoked = 44,
173*8ccd4a63SDavid du Colombier 	ECertificateExpired = 45,
174*8ccd4a63SDavid du Colombier 	ECertificateUnknown = 46,
175*8ccd4a63SDavid du Colombier 	EIllegalParameter = 47,
176*8ccd4a63SDavid du Colombier 	EUnknownCa = 48,
177*8ccd4a63SDavid du Colombier 	EAccessDenied = 49,
178*8ccd4a63SDavid du Colombier 	EDecodeError = 50,
179*8ccd4a63SDavid du Colombier 	EDecryptError = 51,
180*8ccd4a63SDavid du Colombier 	EExportRestriction = 60,
181*8ccd4a63SDavid du Colombier 	EProtocolVersion = 70,
182*8ccd4a63SDavid du Colombier 	EInsufficientSecurity = 71,
183*8ccd4a63SDavid du Colombier 	EInternalError = 80,
184*8ccd4a63SDavid du Colombier 	EUserCanceled = 90,
185*8ccd4a63SDavid du Colombier 	ENoRenegotiation = 100,
186*8ccd4a63SDavid du Colombier 	EMax = 256
187*8ccd4a63SDavid du Colombier };
188*8ccd4a63SDavid du Colombier 
189*8ccd4a63SDavid du Colombier // cipher suites
190*8ccd4a63SDavid du Colombier enum {
191*8ccd4a63SDavid du Colombier 	TLS_NULL_WITH_NULL_NULL	 		= 0x0000,
192*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_NULL_MD5 			= 0x0001,
193*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_NULL_SHA 			= 0x0002,
194*8ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_RC4_40_MD5 		= 0x0003,
195*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_RC4_128_MD5 		= 0x0004,
196*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_RC4_128_SHA 		= 0x0005,
197*8ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	= 0X0006,
198*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_IDEA_CBC_SHA 		= 0X0007,
199*8ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0008,
200*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_DES_CBC_SHA		= 0X0009,
201*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_3DES_EDE_CBC_SHA		= 0X000A,
202*8ccd4a63SDavid du Colombier 	TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X000B,
203*8ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_DES_CBC_SHA		= 0X000C,
204*8ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	= 0X000D,
205*8ccd4a63SDavid du Colombier 	TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X000E,
206*8ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_DES_CBC_SHA		= 0X000F,
207*8ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0010,
208*8ccd4a63SDavid du Colombier 	TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X0011,
209*8ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_DES_CBC_SHA		= 0X0012,
210*8ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	= 0X0013,	// ZZZ must be implemented for tls1.0 compliance
211*8ccd4a63SDavid du Colombier 	TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0014,
212*8ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_DES_CBC_SHA		= 0X0015,
213*8ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0016,
214*8ccd4a63SDavid du Colombier 	TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	= 0x0017,
215*8ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_RC4_128_MD5 		= 0x0018,
216*8ccd4a63SDavid du Colombier 	TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	= 0X0019,
217*8ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_DES_CBC_SHA		= 0X001A,
218*8ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	= 0X001B,
219*8ccd4a63SDavid du Colombier 
220*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_AES_128_CBC_SHA		= 0X002f,	// aes, aka rijndael with 128 bit blocks
221*8ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_AES_128_CBC_SHA		= 0X0030,
222*8ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_AES_128_CBC_SHA		= 0X0031,
223*8ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_AES_128_CBC_SHA	= 0X0032,
224*8ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_AES_128_CBC_SHA	= 0X0033,
225*8ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_AES_128_CBC_SHA	= 0X0034,
226*8ccd4a63SDavid du Colombier 	TLS_RSA_WITH_AES_256_CBC_SHA		= 0X0035,
227*8ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_AES_256_CBC_SHA		= 0X0036,
228*8ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_AES_256_CBC_SHA		= 0X0037,
229*8ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_AES_256_CBC_SHA	= 0X0038,
230*8ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_AES_256_CBC_SHA	= 0X0039,
231*8ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_AES_256_CBC_SHA	= 0X003A,
232*8ccd4a63SDavid du Colombier 	CipherMax
233*8ccd4a63SDavid du Colombier };
234*8ccd4a63SDavid du Colombier 
235*8ccd4a63SDavid du Colombier // compression methods
236*8ccd4a63SDavid du Colombier enum {
237*8ccd4a63SDavid du Colombier 	CompressionNull = 0,
238*8ccd4a63SDavid du Colombier 	CompressionMax
239*8ccd4a63SDavid du Colombier };
240*8ccd4a63SDavid du Colombier 
241*8ccd4a63SDavid du Colombier static Algs cipherAlgs[] = {
242*8ccd4a63SDavid du Colombier 	{"rc4_128", "md5",	2 * (16 + MD5dlen), TLS_RSA_WITH_RC4_128_MD5},
243*8ccd4a63SDavid du Colombier 	{"rc4_128", "sha1",	2 * (16 + SHA1dlen), TLS_RSA_WITH_RC4_128_SHA},
244*8ccd4a63SDavid du Colombier 	{"3des_ede_cbc","sha1",2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},
245*8ccd4a63SDavid du Colombier };
246*8ccd4a63SDavid du Colombier 
247*8ccd4a63SDavid du Colombier static uchar compressors[] = {
248*8ccd4a63SDavid du Colombier 	CompressionNull,
249*8ccd4a63SDavid du Colombier };
250*8ccd4a63SDavid du Colombier 
251*8ccd4a63SDavid du Colombier static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...));
252*8ccd4a63SDavid du Colombier static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...));
253*8ccd4a63SDavid du Colombier 
254*8ccd4a63SDavid du Colombier static void	msgClear(Msg *m);
255*8ccd4a63SDavid du Colombier static char* msgPrint(char *buf, int n, Msg *m);
256*8ccd4a63SDavid du Colombier static int	msgRecv(TlsConnection *c, Msg *m);
257*8ccd4a63SDavid du Colombier static int	msgSend(TlsConnection *c, Msg *m, int act);
258*8ccd4a63SDavid du Colombier static void	tlsError(TlsConnection *c, int err, char *msg, ...);
259*8ccd4a63SDavid du Colombier #pragma	varargck argpos	tlsError 3
260*8ccd4a63SDavid du Colombier static int setVersion(TlsConnection *c, int version);
261*8ccd4a63SDavid du Colombier static int finishedMatch(TlsConnection *c, Finished *f);
262*8ccd4a63SDavid du Colombier static void tlsConnectionFree(TlsConnection *c);
263*8ccd4a63SDavid du Colombier 
264*8ccd4a63SDavid du Colombier static int setAlgs(TlsConnection *c, int a);
265*8ccd4a63SDavid du Colombier static int okCipher(Ints *cv);
266*8ccd4a63SDavid du Colombier static int okCompression(Bytes *cv);
267*8ccd4a63SDavid du Colombier static int initCiphers(void);
268*8ccd4a63SDavid du Colombier static Ints* makeciphers(void);
269*8ccd4a63SDavid du Colombier 
270*8ccd4a63SDavid du Colombier static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom);
271*8ccd4a63SDavid du Colombier static int	tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd);
272*8ccd4a63SDavid du Colombier static TlsSec*	tlsSecInitc(int cvers, uchar *crandom);
273*8ccd4a63SDavid du Colombier static int	tlsSecSecretc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers, uchar **epm, int *nepm, uchar *kd, int nkd);
274*8ccd4a63SDavid du Colombier static int	tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient);
275*8ccd4a63SDavid du Colombier static void	tlsSecOk(TlsSec *sec);
276*8ccd4a63SDavid du Colombier static void	tlsSecKill(TlsSec *sec);
277*8ccd4a63SDavid du Colombier static void	tlsSecClose(TlsSec *sec);
278*8ccd4a63SDavid du Colombier static void	setMasterSecret(TlsSec *sec, Bytes *pm);
279*8ccd4a63SDavid du Colombier static void	serverMasterSecret(TlsSec *sec, uchar *epm, int nepm);
280*8ccd4a63SDavid du Colombier static void	setSecrets(TlsSec *sec, uchar *kd, int nkd);
281*8ccd4a63SDavid du Colombier static int	clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm);
282*8ccd4a63SDavid du Colombier static Bytes *pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);
283*8ccd4a63SDavid du Colombier static Bytes *pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm);
284*8ccd4a63SDavid du Colombier static void	tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
285*8ccd4a63SDavid du Colombier static void	sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
286*8ccd4a63SDavid du Colombier static void	sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label,
287*8ccd4a63SDavid du Colombier 			uchar *seed0, int nseed0, uchar *seed1, int nseed1);
288*8ccd4a63SDavid du Colombier static int setVers(TlsSec *sec, int version);
289*8ccd4a63SDavid du Colombier 
290*8ccd4a63SDavid du Colombier static AuthRpc* factotum_rsa_open(uchar *cert, int certlen);
291*8ccd4a63SDavid du Colombier static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);
292*8ccd4a63SDavid du Colombier static void factotum_rsa_close(AuthRpc*rpc);
293*8ccd4a63SDavid du Colombier 
294*8ccd4a63SDavid du Colombier static void* emalloc(int);
295*8ccd4a63SDavid du Colombier static void* erealloc(void*, int);
296*8ccd4a63SDavid du Colombier static void put32(uchar *p, u32int);
297*8ccd4a63SDavid du Colombier static void put24(uchar *p, int);
298*8ccd4a63SDavid du Colombier static void put16(uchar *p, int);
299*8ccd4a63SDavid du Colombier static u32int get32(uchar *p);
300*8ccd4a63SDavid du Colombier static int get24(uchar *p);
301*8ccd4a63SDavid du Colombier static int get16(uchar *p);
302*8ccd4a63SDavid du Colombier static Bytes* newbytes(int len);
303*8ccd4a63SDavid du Colombier static Bytes* makebytes(uchar* buf, int len);
304*8ccd4a63SDavid du Colombier static void freebytes(Bytes* b);
305*8ccd4a63SDavid du Colombier static Ints* newints(int len);
306*8ccd4a63SDavid du Colombier static Ints* makeints(int* buf, int len);
307*8ccd4a63SDavid du Colombier static void freeints(Ints* b);
308*8ccd4a63SDavid du Colombier 
309*8ccd4a63SDavid du Colombier //================= client/server ========================
310*8ccd4a63SDavid du Colombier 
311*8ccd4a63SDavid du Colombier //	push TLS onto fd, returning new (application) file descriptor
312*8ccd4a63SDavid du Colombier //		or -1 if error.
313*8ccd4a63SDavid du Colombier int
314*8ccd4a63SDavid du Colombier tlsServer(int fd, TLSconn *conn)
315*8ccd4a63SDavid du Colombier {
316*8ccd4a63SDavid du Colombier 	char buf[8];
317*8ccd4a63SDavid du Colombier 	char dname[64];
318*8ccd4a63SDavid du Colombier 	int n, data, ctl, hand;
319*8ccd4a63SDavid du Colombier 	TlsConnection *tls;
320*8ccd4a63SDavid du Colombier 
321*8ccd4a63SDavid du Colombier 	if(conn == nil)
322*8ccd4a63SDavid du Colombier 		return -1;
323*8ccd4a63SDavid du Colombier 	ctl = open("#a/tls/clone", ORDWR);
324*8ccd4a63SDavid du Colombier 	if(ctl < 0)
325*8ccd4a63SDavid du Colombier 		return -1;
326*8ccd4a63SDavid du Colombier 	n = read(ctl, buf, sizeof(buf)-1);
327*8ccd4a63SDavid du Colombier 	if(n < 0){
328*8ccd4a63SDavid du Colombier 		close(ctl);
329*8ccd4a63SDavid du Colombier 		return -1;
330*8ccd4a63SDavid du Colombier 	}
331*8ccd4a63SDavid du Colombier 	buf[n] = 0;
332*8ccd4a63SDavid du Colombier 	sprint(conn->dir, "#a/tls/%s", buf);
333*8ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/hand", buf);
334*8ccd4a63SDavid du Colombier 	hand = open(dname, ORDWR);
335*8ccd4a63SDavid du Colombier 	if(hand < 0){
336*8ccd4a63SDavid du Colombier 		close(ctl);
337*8ccd4a63SDavid du Colombier 		return -1;
338*8ccd4a63SDavid du Colombier 	}
339*8ccd4a63SDavid du Colombier 	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
340*8ccd4a63SDavid du Colombier 	tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace);
341*8ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/data", buf);
342*8ccd4a63SDavid du Colombier 	data = open(dname, ORDWR);
343*8ccd4a63SDavid du Colombier 	close(fd);
344*8ccd4a63SDavid du Colombier 	close(hand);
345*8ccd4a63SDavid du Colombier 	close(ctl);
346*8ccd4a63SDavid du Colombier 	if(data < 0){
347*8ccd4a63SDavid du Colombier 		return -1;
348*8ccd4a63SDavid du Colombier 	}
349*8ccd4a63SDavid du Colombier 	if(tls == nil){
350*8ccd4a63SDavid du Colombier 		close(data);
351*8ccd4a63SDavid du Colombier 		return -1;
352*8ccd4a63SDavid du Colombier 	}
353*8ccd4a63SDavid du Colombier 	if(conn->cert)
354*8ccd4a63SDavid du Colombier 		free(conn->cert);
355*8ccd4a63SDavid du Colombier 	conn->cert = 0;  // client certificates are not yet implemented
356*8ccd4a63SDavid du Colombier 	conn->certlen = 0;
357*8ccd4a63SDavid du Colombier 	conn->sessionIDlen = tls->sid->len;
358*8ccd4a63SDavid du Colombier 	conn->sessionID = emalloc(conn->sessionIDlen);
359*8ccd4a63SDavid du Colombier 	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
360*8ccd4a63SDavid du Colombier 	tlsConnectionFree(tls);
361*8ccd4a63SDavid du Colombier 	return data;
362*8ccd4a63SDavid du Colombier }
363*8ccd4a63SDavid du Colombier 
364*8ccd4a63SDavid du Colombier //	push TLS onto fd, returning new (application) file descriptor
365*8ccd4a63SDavid du Colombier //		or -1 if error.
366*8ccd4a63SDavid du Colombier int
367*8ccd4a63SDavid du Colombier tlsClient(int fd, TLSconn *conn)
368*8ccd4a63SDavid du Colombier {
369*8ccd4a63SDavid du Colombier 	char buf[8];
370*8ccd4a63SDavid du Colombier 	char dname[64];
371*8ccd4a63SDavid du Colombier 	int n, data, ctl, hand;
372*8ccd4a63SDavid du Colombier 	TlsConnection *tls;
373*8ccd4a63SDavid du Colombier 
374*8ccd4a63SDavid du Colombier 	if(!conn)
375*8ccd4a63SDavid du Colombier 		return -1;
376*8ccd4a63SDavid du Colombier 	ctl = open("#a/tls/clone", ORDWR);
377*8ccd4a63SDavid du Colombier 	if(ctl < 0)
378*8ccd4a63SDavid du Colombier 		return -1;
379*8ccd4a63SDavid du Colombier 	n = read(ctl, buf, sizeof(buf)-1);
380*8ccd4a63SDavid du Colombier 	if(n < 0){
381*8ccd4a63SDavid du Colombier 		close(ctl);
382*8ccd4a63SDavid du Colombier 		return -1;
383*8ccd4a63SDavid du Colombier 	}
384*8ccd4a63SDavid du Colombier 	buf[n] = 0;
385*8ccd4a63SDavid du Colombier 	sprint(conn->dir, "#a/tls/%s", buf);
386*8ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/hand", buf);
387*8ccd4a63SDavid du Colombier 	hand = open(dname, ORDWR);
388*8ccd4a63SDavid du Colombier 	if(hand < 0){
389*8ccd4a63SDavid du Colombier 		close(ctl);
390*8ccd4a63SDavid du Colombier 		return -1;
391*8ccd4a63SDavid du Colombier 	}
392*8ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/data", buf);
393*8ccd4a63SDavid du Colombier 	data = open(dname, ORDWR);
394*8ccd4a63SDavid du Colombier 	if(data < 0)
395*8ccd4a63SDavid du Colombier 		return -1;
396*8ccd4a63SDavid du Colombier 	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
397*8ccd4a63SDavid du Colombier 	tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace);
398*8ccd4a63SDavid du Colombier 	close(fd);
399*8ccd4a63SDavid du Colombier 	close(hand);
400*8ccd4a63SDavid du Colombier 	close(ctl);
401*8ccd4a63SDavid du Colombier 	if(tls == nil){
402*8ccd4a63SDavid du Colombier 		close(data);
403*8ccd4a63SDavid du Colombier 		return -1;
404*8ccd4a63SDavid du Colombier 	}
405*8ccd4a63SDavid du Colombier 	conn->certlen = tls->cert->len;
406*8ccd4a63SDavid du Colombier 	conn->cert = emalloc(conn->certlen);
407*8ccd4a63SDavid du Colombier 	memcpy(conn->cert, tls->cert->data, conn->certlen);
408*8ccd4a63SDavid du Colombier 	conn->sessionIDlen = tls->sid->len;
409*8ccd4a63SDavid du Colombier 	conn->sessionID = emalloc(conn->sessionIDlen);
410*8ccd4a63SDavid du Colombier 	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
411*8ccd4a63SDavid du Colombier 	tlsConnectionFree(tls);
412*8ccd4a63SDavid du Colombier 	return data;
413*8ccd4a63SDavid du Colombier }
414*8ccd4a63SDavid du Colombier 
415*8ccd4a63SDavid du Colombier static TlsConnection *
416*8ccd4a63SDavid du Colombier tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...))
417*8ccd4a63SDavid du Colombier {
418*8ccd4a63SDavid du Colombier 	TlsConnection *c;
419*8ccd4a63SDavid du Colombier 	Msg m;
420*8ccd4a63SDavid du Colombier 	Bytes *csid;
421*8ccd4a63SDavid du Colombier 	uchar sid[SidSize], kd[MaxKeyData];
422*8ccd4a63SDavid du Colombier 	char *secrets;
423*8ccd4a63SDavid du Colombier 	int cipher, compressor, nsid, rv;
424*8ccd4a63SDavid du Colombier 
425*8ccd4a63SDavid du Colombier 	if(trace)
426*8ccd4a63SDavid du Colombier 		trace("tlsServer2\n");
427*8ccd4a63SDavid du Colombier 	if(!initCiphers())
428*8ccd4a63SDavid du Colombier 		return nil;
429*8ccd4a63SDavid du Colombier 	c = emalloc(sizeof(TlsConnection));
430*8ccd4a63SDavid du Colombier 	c->ctl = ctl;
431*8ccd4a63SDavid du Colombier 	c->hand = hand;
432*8ccd4a63SDavid du Colombier 	c->trace = trace;
433*8ccd4a63SDavid du Colombier 	c->version = ProtocolVersion;
434*8ccd4a63SDavid du Colombier 
435*8ccd4a63SDavid du Colombier 	memset(&m, 0, sizeof(m));
436*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m)){
437*8ccd4a63SDavid du Colombier 		if(trace)
438*8ccd4a63SDavid du Colombier 			trace("initial msgRecv failed\n");
439*8ccd4a63SDavid du Colombier 		goto Err;
440*8ccd4a63SDavid du Colombier 	}
441*8ccd4a63SDavid du Colombier 	if(m.tag != HClientHello) {
442*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a client hello");
443*8ccd4a63SDavid du Colombier 		goto Err;
444*8ccd4a63SDavid du Colombier 	}
445*8ccd4a63SDavid du Colombier 	c->clientVersion = m.u.clientHello.version;
446*8ccd4a63SDavid du Colombier 	if(trace)
447*8ccd4a63SDavid du Colombier 		trace("ClientHello version %x\n", c->clientVersion);
448*8ccd4a63SDavid du Colombier 	if(setVersion(c, m.u.clientHello.version) < 0) {
449*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "incompatible version");
450*8ccd4a63SDavid du Colombier 		goto Err;
451*8ccd4a63SDavid du Colombier 	}
452*8ccd4a63SDavid du Colombier 
453*8ccd4a63SDavid du Colombier 	memmove(c->crandom, m.u.clientHello.random, RandomSize);
454*8ccd4a63SDavid du Colombier 	cipher = okCipher(m.u.clientHello.ciphers);
455*8ccd4a63SDavid du Colombier 	if(cipher < 0) {
456*8ccd4a63SDavid du Colombier 		// reply with EInsufficientSecurity if we know that's the case
457*8ccd4a63SDavid du Colombier 		if(cipher == -2)
458*8ccd4a63SDavid du Colombier 			tlsError(c, EInsufficientSecurity, "cipher suites too weak");
459*8ccd4a63SDavid du Colombier 		else
460*8ccd4a63SDavid du Colombier 			tlsError(c, EHandshakeFailure, "no matching cipher suite");
461*8ccd4a63SDavid du Colombier 		goto Err;
462*8ccd4a63SDavid du Colombier 	}
463*8ccd4a63SDavid du Colombier 	if(!setAlgs(c, cipher)){
464*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "no matching cipher suite");
465*8ccd4a63SDavid du Colombier 		goto Err;
466*8ccd4a63SDavid du Colombier 	}
467*8ccd4a63SDavid du Colombier 	compressor = okCompression(m.u.clientHello.compressors);
468*8ccd4a63SDavid du Colombier 	if(compressor < 0) {
469*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "no matching compressor");
470*8ccd4a63SDavid du Colombier 		goto Err;
471*8ccd4a63SDavid du Colombier 	}
472*8ccd4a63SDavid du Colombier 
473*8ccd4a63SDavid du Colombier 	csid = m.u.clientHello.sid;
474*8ccd4a63SDavid du Colombier 	if(trace)
475*8ccd4a63SDavid du Colombier 		trace("  cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len);
476*8ccd4a63SDavid du Colombier 	c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom);
477*8ccd4a63SDavid du Colombier 	if(c->sec == nil){
478*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't initialize security: %r");
479*8ccd4a63SDavid du Colombier 		goto Err;
480*8ccd4a63SDavid du Colombier 	}
481*8ccd4a63SDavid du Colombier 	c->sec->rpc = factotum_rsa_open(cert, ncert);
482*8ccd4a63SDavid du Colombier 	if(c->sec->rpc == nil){
483*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
484*8ccd4a63SDavid du Colombier 		goto Err;
485*8ccd4a63SDavid du Colombier 	}
486*8ccd4a63SDavid du Colombier 	c->sec->rsapub = X509toRSApub(cert, ncert, nil, 0);
487*8ccd4a63SDavid du Colombier 	msgClear(&m);
488*8ccd4a63SDavid du Colombier 
489*8ccd4a63SDavid du Colombier 	m.tag = HServerHello;
490*8ccd4a63SDavid du Colombier 	m.u.serverHello.version = c->version;
491*8ccd4a63SDavid du Colombier 	memmove(m.u.serverHello.random, c->srandom, RandomSize);
492*8ccd4a63SDavid du Colombier 	m.u.serverHello.cipher = cipher;
493*8ccd4a63SDavid du Colombier 	m.u.serverHello.compressor = compressor;
494*8ccd4a63SDavid du Colombier 	c->sid = makebytes(sid, nsid);
495*8ccd4a63SDavid du Colombier 	m.u.serverHello.sid = makebytes(c->sid->data, c->sid->len);
496*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AQueue))
497*8ccd4a63SDavid du Colombier 		goto Err;
498*8ccd4a63SDavid du Colombier 	msgClear(&m);
499*8ccd4a63SDavid du Colombier 
500*8ccd4a63SDavid du Colombier 	m.tag = HCertificate;
501*8ccd4a63SDavid du Colombier 	m.u.certificate.ncert = 1;
502*8ccd4a63SDavid du Colombier 	m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes));
503*8ccd4a63SDavid du Colombier 	m.u.certificate.certs[0] = makebytes(cert, ncert);
504*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AQueue))
505*8ccd4a63SDavid du Colombier 		goto Err;
506*8ccd4a63SDavid du Colombier 	msgClear(&m);
507*8ccd4a63SDavid du Colombier 
508*8ccd4a63SDavid du Colombier 	m.tag = HServerHelloDone;
509*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
510*8ccd4a63SDavid du Colombier 		goto Err;
511*8ccd4a63SDavid du Colombier 	msgClear(&m);
512*8ccd4a63SDavid du Colombier 
513*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
514*8ccd4a63SDavid du Colombier 		goto Err;
515*8ccd4a63SDavid du Colombier 	if(m.tag != HClientKeyExchange) {
516*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a client key exchange");
517*8ccd4a63SDavid du Colombier 		goto Err;
518*8ccd4a63SDavid du Colombier 	}
519*8ccd4a63SDavid du Colombier 	if(tlsSecSecrets(c->sec, c->version, m.u.clientKeyExchange.key->data, m.u.clientKeyExchange.key->len, kd, c->nsecret) < 0){
520*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
521*8ccd4a63SDavid du Colombier 		goto Err;
522*8ccd4a63SDavid du Colombier 	}
523*8ccd4a63SDavid du Colombier 	if(trace)
524*8ccd4a63SDavid du Colombier 		trace("tls secrets\n");
525*8ccd4a63SDavid du Colombier 	secrets = (char*)emalloc(2*c->nsecret);
526*8ccd4a63SDavid du Colombier 	enc64(secrets, 2*c->nsecret, kd, c->nsecret);
527*8ccd4a63SDavid du Colombier 	rv = fprint(c->ctl, "secret %s %s 0 %s", c->digest, c->enc, secrets);
528*8ccd4a63SDavid du Colombier 	memset(secrets, 0, 2*c->nsecret);
529*8ccd4a63SDavid du Colombier 	free(secrets);
530*8ccd4a63SDavid du Colombier 	memset(kd, 0, c->nsecret);
531*8ccd4a63SDavid du Colombier 	if(rv < 0){
532*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set keys: %r");
533*8ccd4a63SDavid du Colombier 		goto Err;
534*8ccd4a63SDavid du Colombier 	}
535*8ccd4a63SDavid du Colombier 	msgClear(&m);
536*8ccd4a63SDavid du Colombier 
537*8ccd4a63SDavid du Colombier 	/* no CertificateVerify; skip to Finished */
538*8ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
539*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished: %r");
540*8ccd4a63SDavid du Colombier 		goto Err;
541*8ccd4a63SDavid du Colombier 	}
542*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
543*8ccd4a63SDavid du Colombier 		goto Err;
544*8ccd4a63SDavid du Colombier 	if(m.tag != HFinished) {
545*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a finished");
546*8ccd4a63SDavid du Colombier 		goto Err;
547*8ccd4a63SDavid du Colombier 	}
548*8ccd4a63SDavid du Colombier 	if(!finishedMatch(c, &m.u.finished)) {
549*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "finished verification failed");
550*8ccd4a63SDavid du Colombier 		goto Err;
551*8ccd4a63SDavid du Colombier 	}
552*8ccd4a63SDavid du Colombier 	msgClear(&m);
553*8ccd4a63SDavid du Colombier 
554*8ccd4a63SDavid du Colombier 	/* change cipher spec */
555*8ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "changecipher") < 0){
556*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't enable cipher: %r");
557*8ccd4a63SDavid du Colombier 		goto Err;
558*8ccd4a63SDavid du Colombier 	}
559*8ccd4a63SDavid du Colombier 
560*8ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
561*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished: %r");
562*8ccd4a63SDavid du Colombier 		goto Err;
563*8ccd4a63SDavid du Colombier 	}
564*8ccd4a63SDavid du Colombier 	m.tag = HFinished;
565*8ccd4a63SDavid du Colombier 	m.u.finished = c->finished;
566*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
567*8ccd4a63SDavid du Colombier 		goto Err;
568*8ccd4a63SDavid du Colombier 	msgClear(&m);
569*8ccd4a63SDavid du Colombier 	if(trace)
570*8ccd4a63SDavid du Colombier 		trace("tls finished\n");
571*8ccd4a63SDavid du Colombier 
572*8ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "opened") < 0)
573*8ccd4a63SDavid du Colombier 		goto Err;
574*8ccd4a63SDavid du Colombier 	tlsSecOk(c->sec);
575*8ccd4a63SDavid du Colombier 	return c;
576*8ccd4a63SDavid du Colombier 
577*8ccd4a63SDavid du Colombier Err:
578*8ccd4a63SDavid du Colombier 	msgClear(&m);
579*8ccd4a63SDavid du Colombier 	tlsConnectionFree(c);
580*8ccd4a63SDavid du Colombier 	return 0;
581*8ccd4a63SDavid du Colombier }
582*8ccd4a63SDavid du Colombier 
583*8ccd4a63SDavid du Colombier static TlsConnection *
584*8ccd4a63SDavid du Colombier tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...))
585*8ccd4a63SDavid du Colombier {
586*8ccd4a63SDavid du Colombier 	TlsConnection *c;
587*8ccd4a63SDavid du Colombier 	Msg m;
588*8ccd4a63SDavid du Colombier 	uchar kd[MaxKeyData], *epm;
589*8ccd4a63SDavid du Colombier 	char *secrets;
590*8ccd4a63SDavid du Colombier 	int creq, nepm, rv;
591*8ccd4a63SDavid du Colombier 
592*8ccd4a63SDavid du Colombier 	if(!initCiphers())
593*8ccd4a63SDavid du Colombier 		return nil;
594*8ccd4a63SDavid du Colombier 	epm = nil;
595*8ccd4a63SDavid du Colombier 	c = emalloc(sizeof(TlsConnection));
596*8ccd4a63SDavid du Colombier 	c->version = ProtocolVersion;
597*8ccd4a63SDavid du Colombier 	c->ctl = ctl;
598*8ccd4a63SDavid du Colombier 	c->hand = hand;
599*8ccd4a63SDavid du Colombier 	c->trace = trace;
600*8ccd4a63SDavid du Colombier 	c->isClient = 1;
601*8ccd4a63SDavid du Colombier 	c->clientVersion = c->version;
602*8ccd4a63SDavid du Colombier 
603*8ccd4a63SDavid du Colombier 	c->sec = tlsSecInitc(c->clientVersion, c->crandom);
604*8ccd4a63SDavid du Colombier 	if(c->sec == nil)
605*8ccd4a63SDavid du Colombier 		goto Err;
606*8ccd4a63SDavid du Colombier 
607*8ccd4a63SDavid du Colombier 	/* client hello */
608*8ccd4a63SDavid du Colombier 	memset(&m, 0, sizeof(m));
609*8ccd4a63SDavid du Colombier 	m.tag = HClientHello;
610*8ccd4a63SDavid du Colombier 	m.u.clientHello.version = c->clientVersion;
611*8ccd4a63SDavid du Colombier 	memmove(m.u.clientHello.random, c->crandom, RandomSize);
612*8ccd4a63SDavid du Colombier 	m.u.clientHello.sid = makebytes(csid, ncsid);
613*8ccd4a63SDavid du Colombier 	m.u.clientHello.ciphers = makeciphers();
614*8ccd4a63SDavid du Colombier 	m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors));
615*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
616*8ccd4a63SDavid du Colombier 		goto Err;
617*8ccd4a63SDavid du Colombier 	msgClear(&m);
618*8ccd4a63SDavid du Colombier 
619*8ccd4a63SDavid du Colombier 	/* server hello */
620*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
621*8ccd4a63SDavid du Colombier 		goto Err;
622*8ccd4a63SDavid du Colombier 	if(m.tag != HServerHello) {
623*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a server hello");
624*8ccd4a63SDavid du Colombier 		goto Err;
625*8ccd4a63SDavid du Colombier 	}
626*8ccd4a63SDavid du Colombier 	if(setVersion(c, m.u.serverHello.version) < 0) {
627*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "incompatible version %r");
628*8ccd4a63SDavid du Colombier 		goto Err;
629*8ccd4a63SDavid du Colombier 	}
630*8ccd4a63SDavid du Colombier 	memmove(c->srandom, m.u.serverHello.random, RandomSize);
631*8ccd4a63SDavid du Colombier 	c->sid = makebytes(m.u.serverHello.sid->data, m.u.serverHello.sid->len);
632*8ccd4a63SDavid du Colombier 	if(c->sid->len != 0 && c->sid->len != SidSize) {
633*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid server session identifier");
634*8ccd4a63SDavid du Colombier 		goto Err;
635*8ccd4a63SDavid du Colombier 	}
636*8ccd4a63SDavid du Colombier 	if(!setAlgs(c, m.u.serverHello.cipher)) {
637*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid cipher suite");
638*8ccd4a63SDavid du Colombier 		goto Err;
639*8ccd4a63SDavid du Colombier 	}
640*8ccd4a63SDavid du Colombier 	if(m.u.serverHello.compressor != CompressionNull) {
641*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid compression");
642*8ccd4a63SDavid du Colombier 		goto Err;
643*8ccd4a63SDavid du Colombier 	}
644*8ccd4a63SDavid du Colombier 	msgClear(&m);
645*8ccd4a63SDavid du Colombier 
646*8ccd4a63SDavid du Colombier 	/* certificate */
647*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m) || m.tag != HCertificate) {
648*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a certificate");
649*8ccd4a63SDavid du Colombier 		goto Err;
650*8ccd4a63SDavid du Colombier 	}
651*8ccd4a63SDavid du Colombier 	if(m.u.certificate.ncert < 1) {
652*8ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "runt certificate");
653*8ccd4a63SDavid du Colombier 		goto Err;
654*8ccd4a63SDavid du Colombier 	}
655*8ccd4a63SDavid du Colombier 	c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
656*8ccd4a63SDavid du Colombier 	msgClear(&m);
657*8ccd4a63SDavid du Colombier 
658*8ccd4a63SDavid du Colombier 	/* server key exchange (optional) */
659*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
660*8ccd4a63SDavid du Colombier 		goto Err;
661*8ccd4a63SDavid du Colombier 	if(m.tag == HServerKeyExchange) {
662*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "got an server key exchange");
663*8ccd4a63SDavid du Colombier 		goto Err;
664*8ccd4a63SDavid du Colombier 		// If implementing this later, watch out for rollback attack
665*8ccd4a63SDavid du Colombier 		// described in Wagner Schneier 1996, section 4.4.
666*8ccd4a63SDavid du Colombier 	}
667*8ccd4a63SDavid du Colombier 
668*8ccd4a63SDavid du Colombier 	/* certificate request (optional) */
669*8ccd4a63SDavid du Colombier 	creq = 0;
670*8ccd4a63SDavid du Colombier 	if(m.tag == HCertificateRequest) {
671*8ccd4a63SDavid du Colombier 		creq = 1;
672*8ccd4a63SDavid du Colombier 		msgClear(&m);
673*8ccd4a63SDavid du Colombier 		if(!msgRecv(c, &m))
674*8ccd4a63SDavid du Colombier 			goto Err;
675*8ccd4a63SDavid du Colombier 	}
676*8ccd4a63SDavid du Colombier 
677*8ccd4a63SDavid du Colombier 	if(m.tag != HServerHelloDone) {
678*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a server hello done");
679*8ccd4a63SDavid du Colombier 		goto Err;
680*8ccd4a63SDavid du Colombier 	}
681*8ccd4a63SDavid du Colombier 	msgClear(&m);
682*8ccd4a63SDavid du Colombier 
683*8ccd4a63SDavid du Colombier 	if(tlsSecSecretc(c->sec, c->sid->data, c->sid->len, c->srandom,
684*8ccd4a63SDavid du Colombier 			c->cert->data, c->cert->len, c->version, &epm, &nepm,
685*8ccd4a63SDavid du Colombier 			kd, c->nsecret) < 0){
686*8ccd4a63SDavid du Colombier 		tlsError(c, EBadCertificate, "invalid x509/rsa certificate");
687*8ccd4a63SDavid du Colombier 		goto Err;
688*8ccd4a63SDavid du Colombier 	}
689*8ccd4a63SDavid du Colombier 	secrets = (char*)emalloc(2*c->nsecret);
690*8ccd4a63SDavid du Colombier 	enc64(secrets, 2*c->nsecret, kd, c->nsecret);
691*8ccd4a63SDavid du Colombier 	rv = fprint(c->ctl, "secret %s %s 1 %s", c->digest, c->enc, secrets);
692*8ccd4a63SDavid du Colombier 	memset(secrets, 0, 2*c->nsecret);
693*8ccd4a63SDavid du Colombier 	free(secrets);
694*8ccd4a63SDavid du Colombier 	memset(kd, 0, c->nsecret);
695*8ccd4a63SDavid du Colombier 	if(rv < 0){
696*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set keys: %r");
697*8ccd4a63SDavid du Colombier 		goto Err;
698*8ccd4a63SDavid du Colombier 	}
699*8ccd4a63SDavid du Colombier 
700*8ccd4a63SDavid du Colombier 	if(creq) {
701*8ccd4a63SDavid du Colombier 		/* send a zero length certificate */
702*8ccd4a63SDavid du Colombier 		m.tag = HCertificate;
703*8ccd4a63SDavid du Colombier 		if(!msgSend(c, &m, AFlush))
704*8ccd4a63SDavid du Colombier 			goto Err;
705*8ccd4a63SDavid du Colombier 		msgClear(&m);
706*8ccd4a63SDavid du Colombier 	}
707*8ccd4a63SDavid du Colombier 
708*8ccd4a63SDavid du Colombier 	/* client key exchange */
709*8ccd4a63SDavid du Colombier 	m.tag = HClientKeyExchange;
710*8ccd4a63SDavid du Colombier 	m.u.clientKeyExchange.key = makebytes(epm, nepm);
711*8ccd4a63SDavid du Colombier 	free(epm);
712*8ccd4a63SDavid du Colombier 	epm = nil;
713*8ccd4a63SDavid du Colombier 	if(m.u.clientKeyExchange.key == nil) {
714*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set secret: %r");
715*8ccd4a63SDavid du Colombier 		goto Err;
716*8ccd4a63SDavid du Colombier 	}
717*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
718*8ccd4a63SDavid du Colombier 		goto Err;
719*8ccd4a63SDavid du Colombier 	msgClear(&m);
720*8ccd4a63SDavid du Colombier 
721*8ccd4a63SDavid du Colombier 	/* change cipher spec */
722*8ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "changecipher") < 0){
723*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't enable cipher: %r");
724*8ccd4a63SDavid du Colombier 		goto Err;
725*8ccd4a63SDavid du Colombier 	}
726*8ccd4a63SDavid du Colombier 
727*8ccd4a63SDavid du Colombier 	// Cipherchange must occur immediately before Finished to avoid
728*8ccd4a63SDavid du Colombier 	// potential hole;  see section 4.3 of Wagner Schneier 1996.
729*8ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
730*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished 1: %r");
731*8ccd4a63SDavid du Colombier 		goto Err;
732*8ccd4a63SDavid du Colombier 	}
733*8ccd4a63SDavid du Colombier 	m.tag = HFinished;
734*8ccd4a63SDavid du Colombier 	m.u.finished = c->finished;
735*8ccd4a63SDavid du Colombier 
736*8ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush)) {
737*8ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
738*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't flush after client Finished: %r");
739*8ccd4a63SDavid du Colombier 		goto Err;
740*8ccd4a63SDavid du Colombier 	}
741*8ccd4a63SDavid du Colombier 	msgClear(&m);
742*8ccd4a63SDavid du Colombier 
743*8ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
744*8ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
745*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished 0: %r");
746*8ccd4a63SDavid du Colombier 		goto Err;
747*8ccd4a63SDavid du Colombier 	}
748*8ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m)) {
749*8ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
750*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't read server Finished: %r");
751*8ccd4a63SDavid du Colombier 		goto Err;
752*8ccd4a63SDavid du Colombier 	}
753*8ccd4a63SDavid du Colombier 	if(m.tag != HFinished) {
754*8ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
755*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a Finished msg from server");
756*8ccd4a63SDavid du Colombier 		goto Err;
757*8ccd4a63SDavid du Colombier 	}
758*8ccd4a63SDavid du Colombier 
759*8ccd4a63SDavid du Colombier 	if(!finishedMatch(c, &m.u.finished)) {
760*8ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "finished verification failed");
761*8ccd4a63SDavid du Colombier 		goto Err;
762*8ccd4a63SDavid du Colombier 	}
763*8ccd4a63SDavid du Colombier 	msgClear(&m);
764*8ccd4a63SDavid du Colombier 
765*8ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "opened") < 0){
766*8ccd4a63SDavid du Colombier 		if(trace)
767*8ccd4a63SDavid du Colombier 			trace("unable to do final open: %r\n");
768*8ccd4a63SDavid du Colombier 		goto Err;
769*8ccd4a63SDavid du Colombier 	}
770*8ccd4a63SDavid du Colombier 	tlsSecOk(c->sec);
771*8ccd4a63SDavid du Colombier 	return c;
772*8ccd4a63SDavid du Colombier 
773*8ccd4a63SDavid du Colombier Err:
774*8ccd4a63SDavid du Colombier 	free(epm);
775*8ccd4a63SDavid du Colombier 	msgClear(&m);
776*8ccd4a63SDavid du Colombier 	tlsConnectionFree(c);
777*8ccd4a63SDavid du Colombier 	return 0;
778*8ccd4a63SDavid du Colombier }
779*8ccd4a63SDavid du Colombier 
780*8ccd4a63SDavid du Colombier 
781*8ccd4a63SDavid du Colombier //================= message functions ========================
782*8ccd4a63SDavid du Colombier 
783*8ccd4a63SDavid du Colombier static uchar sendbuf[9000], *sendp;
784*8ccd4a63SDavid du Colombier 
785*8ccd4a63SDavid du Colombier static int
786*8ccd4a63SDavid du Colombier msgSend(TlsConnection *c, Msg *m, int act)
787*8ccd4a63SDavid du Colombier {
788*8ccd4a63SDavid du Colombier 	uchar *p; // sendp = start of new message;  p = write pointer
789*8ccd4a63SDavid du Colombier 	int nn, n, i;
790*8ccd4a63SDavid du Colombier 
791*8ccd4a63SDavid du Colombier 	if(sendp == nil)
792*8ccd4a63SDavid du Colombier 		sendp = sendbuf;
793*8ccd4a63SDavid du Colombier 	p = sendp;
794*8ccd4a63SDavid du Colombier 	if(c->trace)
795*8ccd4a63SDavid du Colombier 		c->trace("send %s", msgPrint((char*)p, (sizeof sendbuf) - (p-sendbuf), m));
796*8ccd4a63SDavid du Colombier 
797*8ccd4a63SDavid du Colombier 	p[0] = m->tag;	// header - fill in size later
798*8ccd4a63SDavid du Colombier 	p += 4;
799*8ccd4a63SDavid du Colombier 
800*8ccd4a63SDavid du Colombier 	switch(m->tag) {
801*8ccd4a63SDavid du Colombier 	default:
802*8ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't encode a %d", m->tag);
803*8ccd4a63SDavid du Colombier 		goto Err;
804*8ccd4a63SDavid du Colombier 	case HClientHello:
805*8ccd4a63SDavid du Colombier 		// version
806*8ccd4a63SDavid du Colombier 		put16(p, m->u.clientHello.version);
807*8ccd4a63SDavid du Colombier 		p += 2;
808*8ccd4a63SDavid du Colombier 
809*8ccd4a63SDavid du Colombier 		// random
810*8ccd4a63SDavid du Colombier 		memmove(p, m->u.clientHello.random, RandomSize);
811*8ccd4a63SDavid du Colombier 		p += RandomSize;
812*8ccd4a63SDavid du Colombier 
813*8ccd4a63SDavid du Colombier 		// sid
814*8ccd4a63SDavid du Colombier 		n = m->u.clientHello.sid->len;
815*8ccd4a63SDavid du Colombier 		assert(n < 256);
816*8ccd4a63SDavid du Colombier 		p[0] = n;
817*8ccd4a63SDavid du Colombier 		memmove(p+1, m->u.clientHello.sid->data, n);
818*8ccd4a63SDavid du Colombier 		p += n+1;
819*8ccd4a63SDavid du Colombier 
820*8ccd4a63SDavid du Colombier 		n = m->u.clientHello.ciphers->len;
821*8ccd4a63SDavid du Colombier 		assert(n > 0 && n < 200);
822*8ccd4a63SDavid du Colombier 		put16(p, n*2);
823*8ccd4a63SDavid du Colombier 		p += 2;
824*8ccd4a63SDavid du Colombier 		for(i=0; i<n; i++) {
825*8ccd4a63SDavid du Colombier 			put16(p, m->u.clientHello.ciphers->data[i]);
826*8ccd4a63SDavid du Colombier 			p += 2;
827*8ccd4a63SDavid du Colombier 		}
828*8ccd4a63SDavid du Colombier 
829*8ccd4a63SDavid du Colombier 		n = m->u.clientHello.compressors->len;
830*8ccd4a63SDavid du Colombier 		assert(n > 0);
831*8ccd4a63SDavid du Colombier 		p[0] = n;
832*8ccd4a63SDavid du Colombier 		memmove(p+1, m->u.clientHello.compressors->data, n);
833*8ccd4a63SDavid du Colombier 		p += n+1;
834*8ccd4a63SDavid du Colombier 		break;
835*8ccd4a63SDavid du Colombier 	case HServerHello:
836*8ccd4a63SDavid du Colombier 		put16(p, m->u.serverHello.version);
837*8ccd4a63SDavid du Colombier 		p += 2;
838*8ccd4a63SDavid du Colombier 
839*8ccd4a63SDavid du Colombier 		// random
840*8ccd4a63SDavid du Colombier 		memmove(p, m->u.serverHello.random, RandomSize);
841*8ccd4a63SDavid du Colombier 		p += RandomSize;
842*8ccd4a63SDavid du Colombier 
843*8ccd4a63SDavid du Colombier 		// sid
844*8ccd4a63SDavid du Colombier 		n = m->u.serverHello.sid->len;
845*8ccd4a63SDavid du Colombier 		assert(n < 256);
846*8ccd4a63SDavid du Colombier 		p[0] = n;
847*8ccd4a63SDavid du Colombier 		memmove(p+1, m->u.serverHello.sid->data, n);
848*8ccd4a63SDavid du Colombier 		p += n+1;
849*8ccd4a63SDavid du Colombier 
850*8ccd4a63SDavid du Colombier 		put16(p, m->u.serverHello.cipher);
851*8ccd4a63SDavid du Colombier 		p += 2;
852*8ccd4a63SDavid du Colombier 		p[0] = m->u.serverHello.compressor;
853*8ccd4a63SDavid du Colombier 		p += 1;
854*8ccd4a63SDavid du Colombier 		break;
855*8ccd4a63SDavid du Colombier 	case HServerHelloDone:
856*8ccd4a63SDavid du Colombier 		break;
857*8ccd4a63SDavid du Colombier 	case HCertificate:
858*8ccd4a63SDavid du Colombier 		nn = 0;
859*8ccd4a63SDavid du Colombier 		for(i = 0; i < m->u.certificate.ncert; i++)
860*8ccd4a63SDavid du Colombier 			nn += 3 + m->u.certificate.certs[i]->len;
861*8ccd4a63SDavid du Colombier 		if(p + 3 + nn - sendbuf > sizeof(sendbuf)) {
862*8ccd4a63SDavid du Colombier 			tlsError(c, EInternalError, "output buffer too small for certificate");
863*8ccd4a63SDavid du Colombier 			goto Err;
864*8ccd4a63SDavid du Colombier 		}
865*8ccd4a63SDavid du Colombier 		put24(p, nn);
866*8ccd4a63SDavid du Colombier 		p += 3;
867*8ccd4a63SDavid du Colombier 		for(i = 0; i < m->u.certificate.ncert; i++){
868*8ccd4a63SDavid du Colombier 			put24(p, m->u.certificate.certs[i]->len);
869*8ccd4a63SDavid du Colombier 			p += 3;
870*8ccd4a63SDavid du Colombier 			memmove(p, m->u.certificate.certs[i]->data, m->u.certificate.certs[i]->len);
871*8ccd4a63SDavid du Colombier 			p += m->u.certificate.certs[i]->len;
872*8ccd4a63SDavid du Colombier 		}
873*8ccd4a63SDavid du Colombier 		break;
874*8ccd4a63SDavid du Colombier 	case HClientKeyExchange:
875*8ccd4a63SDavid du Colombier 		n = m->u.clientKeyExchange.key->len;
876*8ccd4a63SDavid du Colombier 		if(c->version != SSL3Version){
877*8ccd4a63SDavid du Colombier 			put16(p, n);
878*8ccd4a63SDavid du Colombier 			p += 2;
879*8ccd4a63SDavid du Colombier 		}
880*8ccd4a63SDavid du Colombier 		memmove(p, m->u.clientKeyExchange.key->data, n);
881*8ccd4a63SDavid du Colombier 		p += n;
882*8ccd4a63SDavid du Colombier 		break;
883*8ccd4a63SDavid du Colombier 	case HFinished:
884*8ccd4a63SDavid du Colombier 		memmove(p, m->u.finished.verify, m->u.finished.n);
885*8ccd4a63SDavid du Colombier 		p += m->u.finished.n;
886*8ccd4a63SDavid du Colombier 		break;
887*8ccd4a63SDavid du Colombier 	}
888*8ccd4a63SDavid du Colombier 
889*8ccd4a63SDavid du Colombier 	// go back and fill in size
890*8ccd4a63SDavid du Colombier 	n = p-sendp;
891*8ccd4a63SDavid du Colombier 	assert(p <= sendbuf+sizeof(sendbuf));
892*8ccd4a63SDavid du Colombier 	put24(sendp+1, n-4);
893*8ccd4a63SDavid du Colombier 
894*8ccd4a63SDavid du Colombier 	// remember hash of Handshake messages
895*8ccd4a63SDavid du Colombier 	if(m->tag != HHelloRequest) {
896*8ccd4a63SDavid du Colombier 		md5(sendp, n, 0, &c->hsmd5);
897*8ccd4a63SDavid du Colombier 		sha1(sendp, n, 0, &c->hssha1);
898*8ccd4a63SDavid du Colombier 	}
899*8ccd4a63SDavid du Colombier 
900*8ccd4a63SDavid du Colombier 	sendp = p;
901*8ccd4a63SDavid du Colombier 	if(act == AFlush){
902*8ccd4a63SDavid du Colombier 		sendp = sendbuf;
903*8ccd4a63SDavid du Colombier 		if(write(c->hand, sendbuf, p-sendbuf) < 0){
904*8ccd4a63SDavid du Colombier 			fprint(2, "write error: %r\n");
905*8ccd4a63SDavid du Colombier 			goto Err;
906*8ccd4a63SDavid du Colombier 		}
907*8ccd4a63SDavid du Colombier 	}
908*8ccd4a63SDavid du Colombier 	msgClear(m);
909*8ccd4a63SDavid du Colombier 	return 1;
910*8ccd4a63SDavid du Colombier Err:
911*8ccd4a63SDavid du Colombier 	msgClear(m);
912*8ccd4a63SDavid du Colombier 	return 0;
913*8ccd4a63SDavid du Colombier }
914*8ccd4a63SDavid du Colombier 
915*8ccd4a63SDavid du Colombier static uchar*
916*8ccd4a63SDavid du Colombier tlsReadN(TlsConnection *c, int n)
917*8ccd4a63SDavid du Colombier {
918*8ccd4a63SDavid du Colombier 	uchar *p;
919*8ccd4a63SDavid du Colombier 	int nn, nr;
920*8ccd4a63SDavid du Colombier 
921*8ccd4a63SDavid du Colombier 	nn = c->ep - c->rp;
922*8ccd4a63SDavid du Colombier 	if(nn < n){
923*8ccd4a63SDavid du Colombier 		if(c->rp != c->buf){
924*8ccd4a63SDavid du Colombier 			memmove(c->buf, c->rp, nn);
925*8ccd4a63SDavid du Colombier 			c->rp = c->buf;
926*8ccd4a63SDavid du Colombier 			c->ep = &c->buf[nn];
927*8ccd4a63SDavid du Colombier 		}
928*8ccd4a63SDavid du Colombier 		for(; nn < n; nn += nr) {
929*8ccd4a63SDavid du Colombier 			nr = read(c->hand, &c->rp[nn], n - nn);
930*8ccd4a63SDavid du Colombier 			if(nr <= 0)
931*8ccd4a63SDavid du Colombier 				return nil;
932*8ccd4a63SDavid du Colombier 			c->ep += nr;
933*8ccd4a63SDavid du Colombier 		}
934*8ccd4a63SDavid du Colombier 	}
935*8ccd4a63SDavid du Colombier 	p = c->rp;
936*8ccd4a63SDavid du Colombier 	c->rp += n;
937*8ccd4a63SDavid du Colombier 	return p;
938*8ccd4a63SDavid du Colombier }
939*8ccd4a63SDavid du Colombier 
940*8ccd4a63SDavid du Colombier static int
941*8ccd4a63SDavid du Colombier msgRecv(TlsConnection *c, Msg *m)
942*8ccd4a63SDavid du Colombier {
943*8ccd4a63SDavid du Colombier 	uchar *p;
944*8ccd4a63SDavid du Colombier 	int type, n, nn, i, nsid, nrandom, nciph;
945*8ccd4a63SDavid du Colombier 
946*8ccd4a63SDavid du Colombier 	for(;;) {
947*8ccd4a63SDavid du Colombier 		p = tlsReadN(c, 4);
948*8ccd4a63SDavid du Colombier 		if(p == nil)
949*8ccd4a63SDavid du Colombier 			return 0;
950*8ccd4a63SDavid du Colombier 		type = p[0];
951*8ccd4a63SDavid du Colombier 		n = get24(p+1);
952*8ccd4a63SDavid du Colombier 
953*8ccd4a63SDavid du Colombier 		if(type != HHelloRequest)
954*8ccd4a63SDavid du Colombier 			break;
955*8ccd4a63SDavid du Colombier 		if(n != 0) {
956*8ccd4a63SDavid du Colombier 			tlsError(c, EDecodeError, "invalid hello request during handshake");
957*8ccd4a63SDavid du Colombier 			return 0;
958*8ccd4a63SDavid du Colombier 		}
959*8ccd4a63SDavid du Colombier 	}
960*8ccd4a63SDavid du Colombier 
961*8ccd4a63SDavid du Colombier 	if(n > sizeof(c->buf)) {
962*8ccd4a63SDavid du Colombier 		tlsError(c, EDecodeError, "handshake message too long %d %d", n, sizeof(c->buf));
963*8ccd4a63SDavid du Colombier 		return 0;
964*8ccd4a63SDavid du Colombier 	}
965*8ccd4a63SDavid du Colombier 
966*8ccd4a63SDavid du Colombier 	if(type == HSSL2ClientHello){
967*8ccd4a63SDavid du Colombier 		/* Cope with an SSL3 ClientHello expressed in SSL2 record format.
968*8ccd4a63SDavid du Colombier 			This is sent by some clients that we must interoperate
969*8ccd4a63SDavid du Colombier 			with, such as Java's JSSE and Microsoft's Internet Explorer. */
970*8ccd4a63SDavid du Colombier 		p = tlsReadN(c, n);
971*8ccd4a63SDavid du Colombier 		if(p == nil)
972*8ccd4a63SDavid du Colombier 			return 0;
973*8ccd4a63SDavid du Colombier 		md5(p, n, 0, &c->hsmd5);
974*8ccd4a63SDavid du Colombier 		sha1(p, n, 0, &c->hssha1);
975*8ccd4a63SDavid du Colombier 		m->tag = HClientHello;
976*8ccd4a63SDavid du Colombier 		if(n < 22)
977*8ccd4a63SDavid du Colombier 			goto Short;
978*8ccd4a63SDavid du Colombier 		m->u.clientHello.version = get16(p+1);
979*8ccd4a63SDavid du Colombier 		p += 3;
980*8ccd4a63SDavid du Colombier 		n -= 3;
981*8ccd4a63SDavid du Colombier 		nn = get16(p); /* cipher_spec_len */
982*8ccd4a63SDavid du Colombier 		nsid = get16(p + 2);
983*8ccd4a63SDavid du Colombier 		nrandom = get16(p + 4);
984*8ccd4a63SDavid du Colombier 		p += 6;
985*8ccd4a63SDavid du Colombier 		n -= 6;
986*8ccd4a63SDavid du Colombier 		if(nsid != 0 	/* no sid's, since shouldn't restart using ssl2 header */
987*8ccd4a63SDavid du Colombier 				|| nrandom < 16 || nn % 3)
988*8ccd4a63SDavid du Colombier 			goto Err;
989*8ccd4a63SDavid du Colombier 		if(c->trace && (n - nrandom != nn))
990*8ccd4a63SDavid du Colombier 			c->trace("n-nrandom!=nn: n=%d nrandom=%d nn=%d\n", n, nrandom, nn);
991*8ccd4a63SDavid du Colombier 		/* ignore ssl2 ciphers and look for {0x00, ssl3 cipher} */
992*8ccd4a63SDavid du Colombier 		nciph = 0;
993*8ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 3)
994*8ccd4a63SDavid du Colombier 			if(p[i] == 0)
995*8ccd4a63SDavid du Colombier 				nciph++;
996*8ccd4a63SDavid du Colombier 		m->u.clientHello.ciphers = newints(nciph);
997*8ccd4a63SDavid du Colombier 		nciph = 0;
998*8ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 3)
999*8ccd4a63SDavid du Colombier 			if(p[i] == 0)
1000*8ccd4a63SDavid du Colombier 				m->u.clientHello.ciphers->data[nciph++] = get16(&p[i + 1]);
1001*8ccd4a63SDavid du Colombier 		p += nn;
1002*8ccd4a63SDavid du Colombier 		m->u.clientHello.sid = makebytes(nil, 0);
1003*8ccd4a63SDavid du Colombier 		if(nrandom > RandomSize)
1004*8ccd4a63SDavid du Colombier 			nrandom = RandomSize;
1005*8ccd4a63SDavid du Colombier 		memset(m->u.clientHello.random, 0, RandomSize - nrandom);
1006*8ccd4a63SDavid du Colombier 		memmove(&m->u.clientHello.random[RandomSize - nrandom], p, nrandom);
1007*8ccd4a63SDavid du Colombier 		m->u.clientHello.compressors = newbytes(1);
1008*8ccd4a63SDavid du Colombier 		m->u.clientHello.compressors->data[0] = CompressionNull;
1009*8ccd4a63SDavid du Colombier 		goto Ok;
1010*8ccd4a63SDavid du Colombier 	}
1011*8ccd4a63SDavid du Colombier 
1012*8ccd4a63SDavid du Colombier 	md5(p, 4, 0, &c->hsmd5);
1013*8ccd4a63SDavid du Colombier 	sha1(p, 4, 0, &c->hssha1);
1014*8ccd4a63SDavid du Colombier 
1015*8ccd4a63SDavid du Colombier 	p = tlsReadN(c, n);
1016*8ccd4a63SDavid du Colombier 	if(p == nil)
1017*8ccd4a63SDavid du Colombier 		return 0;
1018*8ccd4a63SDavid du Colombier 
1019*8ccd4a63SDavid du Colombier 	md5(p, n, 0, &c->hsmd5);
1020*8ccd4a63SDavid du Colombier 	sha1(p, n, 0, &c->hssha1);
1021*8ccd4a63SDavid du Colombier 
1022*8ccd4a63SDavid du Colombier 	m->tag = type;
1023*8ccd4a63SDavid du Colombier 
1024*8ccd4a63SDavid du Colombier 	switch(type) {
1025*8ccd4a63SDavid du Colombier 	default:
1026*8ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "can't decode a %d", type);
1027*8ccd4a63SDavid du Colombier 		goto Err;
1028*8ccd4a63SDavid du Colombier 	case HClientHello:
1029*8ccd4a63SDavid du Colombier 		if(n < 2)
1030*8ccd4a63SDavid du Colombier 			goto Short;
1031*8ccd4a63SDavid du Colombier 		m->u.clientHello.version = get16(p);
1032*8ccd4a63SDavid du Colombier 		p += 2;
1033*8ccd4a63SDavid du Colombier 		n -= 2;
1034*8ccd4a63SDavid du Colombier 
1035*8ccd4a63SDavid du Colombier 		if(n < RandomSize)
1036*8ccd4a63SDavid du Colombier 			goto Short;
1037*8ccd4a63SDavid du Colombier 		memmove(m->u.clientHello.random, p, RandomSize);
1038*8ccd4a63SDavid du Colombier 		p += RandomSize;
1039*8ccd4a63SDavid du Colombier 		n -= RandomSize;
1040*8ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1)
1041*8ccd4a63SDavid du Colombier 			goto Short;
1042*8ccd4a63SDavid du Colombier 		m->u.clientHello.sid = makebytes(p+1, p[0]);
1043*8ccd4a63SDavid du Colombier 		p += m->u.clientHello.sid->len+1;
1044*8ccd4a63SDavid du Colombier 		n -= m->u.clientHello.sid->len+1;
1045*8ccd4a63SDavid du Colombier 
1046*8ccd4a63SDavid du Colombier 		if(n < 2)
1047*8ccd4a63SDavid du Colombier 			goto Short;
1048*8ccd4a63SDavid du Colombier 		nn = get16(p);
1049*8ccd4a63SDavid du Colombier 		p += 2;
1050*8ccd4a63SDavid du Colombier 		n -= 2;
1051*8ccd4a63SDavid du Colombier 
1052*8ccd4a63SDavid du Colombier 		if((nn & 1) || n < nn || nn < 2)
1053*8ccd4a63SDavid du Colombier 			goto Short;
1054*8ccd4a63SDavid du Colombier 		m->u.clientHello.ciphers = newints(nn >> 1);
1055*8ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 2)
1056*8ccd4a63SDavid du Colombier 			m->u.clientHello.ciphers->data[i >> 1] = get16(&p[i]);
1057*8ccd4a63SDavid du Colombier 		p += nn;
1058*8ccd4a63SDavid du Colombier 		n -= nn;
1059*8ccd4a63SDavid du Colombier 
1060*8ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1 || p[0] == 0)
1061*8ccd4a63SDavid du Colombier 			goto Short;
1062*8ccd4a63SDavid du Colombier 		nn = p[0];
1063*8ccd4a63SDavid du Colombier 		m->u.clientHello.compressors = newbytes(nn);
1064*8ccd4a63SDavid du Colombier 		memmove(m->u.clientHello.compressors->data, p+1, nn);
1065*8ccd4a63SDavid du Colombier 		n -= nn + 1;
1066*8ccd4a63SDavid du Colombier 		break;
1067*8ccd4a63SDavid du Colombier 	case HServerHello:
1068*8ccd4a63SDavid du Colombier 		if(n < 2)
1069*8ccd4a63SDavid du Colombier 			goto Short;
1070*8ccd4a63SDavid du Colombier 		m->u.serverHello.version = get16(p);
1071*8ccd4a63SDavid du Colombier 		p += 2;
1072*8ccd4a63SDavid du Colombier 		n -= 2;
1073*8ccd4a63SDavid du Colombier 
1074*8ccd4a63SDavid du Colombier 		if(n < RandomSize)
1075*8ccd4a63SDavid du Colombier 			goto Short;
1076*8ccd4a63SDavid du Colombier 		memmove(m->u.serverHello.random, p, RandomSize);
1077*8ccd4a63SDavid du Colombier 		p += RandomSize;
1078*8ccd4a63SDavid du Colombier 		n -= RandomSize;
1079*8ccd4a63SDavid du Colombier 
1080*8ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1)
1081*8ccd4a63SDavid du Colombier 			goto Short;
1082*8ccd4a63SDavid du Colombier 		m->u.serverHello.sid = makebytes(p+1, p[0]);
1083*8ccd4a63SDavid du Colombier 		p += m->u.serverHello.sid->len+1;
1084*8ccd4a63SDavid du Colombier 		n -= m->u.serverHello.sid->len+1;
1085*8ccd4a63SDavid du Colombier 
1086*8ccd4a63SDavid du Colombier 		if(n < 3)
1087*8ccd4a63SDavid du Colombier 			goto Short;
1088*8ccd4a63SDavid du Colombier 		m->u.serverHello.cipher = get16(p);
1089*8ccd4a63SDavid du Colombier 		m->u.serverHello.compressor = p[2];
1090*8ccd4a63SDavid du Colombier 		n -= 3;
1091*8ccd4a63SDavid du Colombier 		break;
1092*8ccd4a63SDavid du Colombier 	case HCertificate:
1093*8ccd4a63SDavid du Colombier 		if(n < 3)
1094*8ccd4a63SDavid du Colombier 			goto Short;
1095*8ccd4a63SDavid du Colombier 		nn = get24(p);
1096*8ccd4a63SDavid du Colombier 		p += 3;
1097*8ccd4a63SDavid du Colombier 		n -= 3;
1098*8ccd4a63SDavid du Colombier 		if(n != nn)
1099*8ccd4a63SDavid du Colombier 			goto Short;
1100*8ccd4a63SDavid du Colombier 		/* certs */
1101*8ccd4a63SDavid du Colombier 		i = 0;
1102*8ccd4a63SDavid du Colombier 		while(n > 0) {
1103*8ccd4a63SDavid du Colombier 			if(n < 3)
1104*8ccd4a63SDavid du Colombier 				goto Short;
1105*8ccd4a63SDavid du Colombier 			nn = get24(p);
1106*8ccd4a63SDavid du Colombier 			p += 3;
1107*8ccd4a63SDavid du Colombier 			n -= 3;
1108*8ccd4a63SDavid du Colombier 			if(nn > n)
1109*8ccd4a63SDavid du Colombier 				goto Short;
1110*8ccd4a63SDavid du Colombier 			m->u.certificate.ncert = i+1;
1111*8ccd4a63SDavid du Colombier 			m->u.certificate.certs = erealloc(m->u.certificate.certs, (i+1)*sizeof(Bytes));
1112*8ccd4a63SDavid du Colombier 			m->u.certificate.certs[i] = makebytes(p, nn);
1113*8ccd4a63SDavid du Colombier 			p += nn;
1114*8ccd4a63SDavid du Colombier 			n -= nn;
1115*8ccd4a63SDavid du Colombier 			i++;
1116*8ccd4a63SDavid du Colombier 		}
1117*8ccd4a63SDavid du Colombier 		break;
1118*8ccd4a63SDavid du Colombier 	case HCertificateRequest:
1119*8ccd4a63SDavid du Colombier 		if(n < 2)
1120*8ccd4a63SDavid du Colombier 			goto Short;
1121*8ccd4a63SDavid du Colombier 		nn = get16(p);
1122*8ccd4a63SDavid du Colombier 		p += 2;
1123*8ccd4a63SDavid du Colombier 		n -= 2;
1124*8ccd4a63SDavid du Colombier 		if(nn < 1 || nn > n)
1125*8ccd4a63SDavid du Colombier 			goto Short;
1126*8ccd4a63SDavid du Colombier 		m->u.certificateRequest.types = makebytes(p, nn);
1127*8ccd4a63SDavid du Colombier 		nn = get24(p);
1128*8ccd4a63SDavid du Colombier 		p += 3;
1129*8ccd4a63SDavid du Colombier 		n -= 3;
1130*8ccd4a63SDavid du Colombier 		if(nn == 0 || n != nn)
1131*8ccd4a63SDavid du Colombier 			goto Short;
1132*8ccd4a63SDavid du Colombier 		/* cas */
1133*8ccd4a63SDavid du Colombier 		i = 0;
1134*8ccd4a63SDavid du Colombier 		while(n > 0) {
1135*8ccd4a63SDavid du Colombier 			if(n < 2)
1136*8ccd4a63SDavid du Colombier 				goto Short;
1137*8ccd4a63SDavid du Colombier 			nn = get16(p);
1138*8ccd4a63SDavid du Colombier 			p += 2;
1139*8ccd4a63SDavid du Colombier 			n -= 2;
1140*8ccd4a63SDavid du Colombier 			if(nn < 1 || nn > n)
1141*8ccd4a63SDavid du Colombier 				goto Short;
1142*8ccd4a63SDavid du Colombier 			m->u.certificateRequest.nca = i+1;
1143*8ccd4a63SDavid du Colombier 			m->u.certificateRequest.cas = erealloc(m->u.certificateRequest.cas, (i+1)*sizeof(Bytes));
1144*8ccd4a63SDavid du Colombier 			m->u.certificateRequest.cas[i] = makebytes(p, nn);
1145*8ccd4a63SDavid du Colombier 			p += nn;
1146*8ccd4a63SDavid du Colombier 			n -= nn;
1147*8ccd4a63SDavid du Colombier 			i++;
1148*8ccd4a63SDavid du Colombier 		}
1149*8ccd4a63SDavid du Colombier 		break;
1150*8ccd4a63SDavid du Colombier 	case HServerHelloDone:
1151*8ccd4a63SDavid du Colombier 		break;
1152*8ccd4a63SDavid du Colombier 	case HClientKeyExchange:
1153*8ccd4a63SDavid du Colombier 		/*
1154*8ccd4a63SDavid du Colombier 		 * this message depends upon the encryption selected
1155*8ccd4a63SDavid du Colombier 		 * assume rsa.
1156*8ccd4a63SDavid du Colombier 		 */
1157*8ccd4a63SDavid du Colombier 		if(c->version == SSL3Version)
1158*8ccd4a63SDavid du Colombier 			nn = n;
1159*8ccd4a63SDavid du Colombier 		else{
1160*8ccd4a63SDavid du Colombier 			if(n < 2)
1161*8ccd4a63SDavid du Colombier 				goto Short;
1162*8ccd4a63SDavid du Colombier 			nn = get16(p);
1163*8ccd4a63SDavid du Colombier 			p += 2;
1164*8ccd4a63SDavid du Colombier 			n -= 2;
1165*8ccd4a63SDavid du Colombier 		}
1166*8ccd4a63SDavid du Colombier 		if(n < nn)
1167*8ccd4a63SDavid du Colombier 			goto Short;
1168*8ccd4a63SDavid du Colombier 		m->u.clientKeyExchange.key = makebytes(p, nn);
1169*8ccd4a63SDavid du Colombier 		n -= nn;
1170*8ccd4a63SDavid du Colombier 		break;
1171*8ccd4a63SDavid du Colombier 	case HFinished:
1172*8ccd4a63SDavid du Colombier 		m->u.finished.n = c->finished.n;
1173*8ccd4a63SDavid du Colombier 		if(n < m->u.finished.n)
1174*8ccd4a63SDavid du Colombier 			goto Short;
1175*8ccd4a63SDavid du Colombier 		memmove(m->u.finished.verify, p, m->u.finished.n);
1176*8ccd4a63SDavid du Colombier 		n -= m->u.finished.n;
1177*8ccd4a63SDavid du Colombier 		break;
1178*8ccd4a63SDavid du Colombier 	}
1179*8ccd4a63SDavid du Colombier 
1180*8ccd4a63SDavid du Colombier 	if(type != HClientHello && n != 0)
1181*8ccd4a63SDavid du Colombier 		goto Short;
1182*8ccd4a63SDavid du Colombier Ok:
1183*8ccd4a63SDavid du Colombier 	if(c->trace){
1184*8ccd4a63SDavid du Colombier 		char buf[8000];
1185*8ccd4a63SDavid du Colombier 		c->trace("recv %s", msgPrint(buf, sizeof buf, m));
1186*8ccd4a63SDavid du Colombier 	}
1187*8ccd4a63SDavid du Colombier 	return 1;
1188*8ccd4a63SDavid du Colombier Short:
1189*8ccd4a63SDavid du Colombier 	tlsError(c, EDecodeError, "handshake message has invalid length");
1190*8ccd4a63SDavid du Colombier Err:
1191*8ccd4a63SDavid du Colombier 	msgClear(m);
1192*8ccd4a63SDavid du Colombier 	return 0;
1193*8ccd4a63SDavid du Colombier }
1194*8ccd4a63SDavid du Colombier 
1195*8ccd4a63SDavid du Colombier static void
1196*8ccd4a63SDavid du Colombier msgClear(Msg *m)
1197*8ccd4a63SDavid du Colombier {
1198*8ccd4a63SDavid du Colombier 	int i;
1199*8ccd4a63SDavid du Colombier 
1200*8ccd4a63SDavid du Colombier 	switch(m->tag) {
1201*8ccd4a63SDavid du Colombier 	default:
1202*8ccd4a63SDavid du Colombier 		sysfatal("msgClear: unknown message type: %d\n", m->tag);
1203*8ccd4a63SDavid du Colombier 	case HHelloRequest:
1204*8ccd4a63SDavid du Colombier 		break;
1205*8ccd4a63SDavid du Colombier 	case HClientHello:
1206*8ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.sid);
1207*8ccd4a63SDavid du Colombier 		freeints(m->u.clientHello.ciphers);
1208*8ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.compressors);
1209*8ccd4a63SDavid du Colombier 		break;
1210*8ccd4a63SDavid du Colombier 	case HServerHello:
1211*8ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.sid);
1212*8ccd4a63SDavid du Colombier 		break;
1213*8ccd4a63SDavid du Colombier 	case HCertificate:
1214*8ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificate.ncert; i++)
1215*8ccd4a63SDavid du Colombier 			freebytes(m->u.certificate.certs[i]);
1216*8ccd4a63SDavid du Colombier 		free(m->u.certificate.certs);
1217*8ccd4a63SDavid du Colombier 		break;
1218*8ccd4a63SDavid du Colombier 	case HCertificateRequest:
1219*8ccd4a63SDavid du Colombier 		freebytes(m->u.certificateRequest.types);
1220*8ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificateRequest.nca; i++)
1221*8ccd4a63SDavid du Colombier 			freebytes(m->u.certificateRequest.cas[i]);
1222*8ccd4a63SDavid du Colombier 		free(m->u.certificateRequest.cas);
1223*8ccd4a63SDavid du Colombier 		break;
1224*8ccd4a63SDavid du Colombier 	case HServerHelloDone:
1225*8ccd4a63SDavid du Colombier 		break;
1226*8ccd4a63SDavid du Colombier 	case HClientKeyExchange:
1227*8ccd4a63SDavid du Colombier 		freebytes(m->u.clientKeyExchange.key);
1228*8ccd4a63SDavid du Colombier 		break;
1229*8ccd4a63SDavid du Colombier 	case HFinished:
1230*8ccd4a63SDavid du Colombier 		break;
1231*8ccd4a63SDavid du Colombier 	}
1232*8ccd4a63SDavid du Colombier 	memset(m, 0, sizeof(Msg));
1233*8ccd4a63SDavid du Colombier }
1234*8ccd4a63SDavid du Colombier 
1235*8ccd4a63SDavid du Colombier static char *
1236*8ccd4a63SDavid du Colombier bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1)
1237*8ccd4a63SDavid du Colombier {
1238*8ccd4a63SDavid du Colombier 	int i;
1239*8ccd4a63SDavid du Colombier 
1240*8ccd4a63SDavid du Colombier 	if(s0)
1241*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s0);
1242*8ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "[");
1243*8ccd4a63SDavid du Colombier 	if(b == nil)
1244*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "nil");
1245*8ccd4a63SDavid du Colombier 	else
1246*8ccd4a63SDavid du Colombier 		for(i=0; i<b->len; i++)
1247*8ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x ", b->data[i]);
1248*8ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "]");
1249*8ccd4a63SDavid du Colombier 	if(s1)
1250*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s1);
1251*8ccd4a63SDavid du Colombier 	return bs;
1252*8ccd4a63SDavid du Colombier }
1253*8ccd4a63SDavid du Colombier 
1254*8ccd4a63SDavid du Colombier static char *
1255*8ccd4a63SDavid du Colombier intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1)
1256*8ccd4a63SDavid du Colombier {
1257*8ccd4a63SDavid du Colombier 	int i;
1258*8ccd4a63SDavid du Colombier 
1259*8ccd4a63SDavid du Colombier 	if(s0)
1260*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s0);
1261*8ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "[");
1262*8ccd4a63SDavid du Colombier 	if(b == nil)
1263*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "nil");
1264*8ccd4a63SDavid du Colombier 	else
1265*8ccd4a63SDavid du Colombier 		for(i=0; i<b->len; i++)
1266*8ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%x ", b->data[i]);
1267*8ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "]");
1268*8ccd4a63SDavid du Colombier 	if(s1)
1269*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s1);
1270*8ccd4a63SDavid du Colombier 	return bs;
1271*8ccd4a63SDavid du Colombier }
1272*8ccd4a63SDavid du Colombier 
1273*8ccd4a63SDavid du Colombier static char*
1274*8ccd4a63SDavid du Colombier msgPrint(char *buf, int n, Msg *m)
1275*8ccd4a63SDavid du Colombier {
1276*8ccd4a63SDavid du Colombier 	int i;
1277*8ccd4a63SDavid du Colombier 	char *bs = buf, *be = buf+n;
1278*8ccd4a63SDavid du Colombier 
1279*8ccd4a63SDavid du Colombier 	switch(m->tag) {
1280*8ccd4a63SDavid du Colombier 	default:
1281*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "unknown %d\n", m->tag);
1282*8ccd4a63SDavid du Colombier 		break;
1283*8ccd4a63SDavid du Colombier 	case HClientHello:
1284*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ClientHello\n");
1285*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tversion: %.4x\n", m->u.clientHello.version);
1286*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\trandom: ");
1287*8ccd4a63SDavid du Colombier 		for(i=0; i<RandomSize; i++)
1288*8ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.clientHello.random[i]);
1289*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
1290*8ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tsid: ", m->u.clientHello.sid, "\n");
1291*8ccd4a63SDavid du Colombier 		bs = intsPrint(bs, be, "\tciphers: ", m->u.clientHello.ciphers, "\n");
1292*8ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tcompressors: ", m->u.clientHello.compressors, "\n");
1293*8ccd4a63SDavid du Colombier 		break;
1294*8ccd4a63SDavid du Colombier 	case HServerHello:
1295*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ServerHello\n");
1296*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tversion: %.4x\n", m->u.serverHello.version);
1297*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\trandom: ");
1298*8ccd4a63SDavid du Colombier 		for(i=0; i<RandomSize; i++)
1299*8ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.serverHello.random[i]);
1300*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
1301*8ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tsid: ", m->u.serverHello.sid, "\n");
1302*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcipher: %.4x\n", m->u.serverHello.cipher);
1303*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcompressor: %.2x\n", m->u.serverHello.compressor);
1304*8ccd4a63SDavid du Colombier 		break;
1305*8ccd4a63SDavid du Colombier 	case HCertificate:
1306*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "Certificate\n");
1307*8ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificate.ncert; i++)
1308*8ccd4a63SDavid du Colombier 			bs = bytesPrint(bs, be, "\t", m->u.certificate.certs[i], "\n");
1309*8ccd4a63SDavid du Colombier 		break;
1310*8ccd4a63SDavid du Colombier 	case HCertificateRequest:
1311*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "CertificateRequest\n");
1312*8ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n");
1313*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcertificateauthorities\n");
1314*8ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificateRequest.nca; i++)
1315*8ccd4a63SDavid du Colombier 			bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
1316*8ccd4a63SDavid du Colombier 		break;
1317*8ccd4a63SDavid du Colombier 	case HServerHelloDone:
1318*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ServerHelloDone\n");
1319*8ccd4a63SDavid du Colombier 		break;
1320*8ccd4a63SDavid du Colombier 	case HClientKeyExchange:
1321*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "HClientKeyExchange\n");
1322*8ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n");
1323*8ccd4a63SDavid du Colombier 		break;
1324*8ccd4a63SDavid du Colombier 	case HFinished:
1325*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "HFinished\n");
1326*8ccd4a63SDavid du Colombier 		for(i=0; i<m->u.finished.n; i++)
1327*8ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.finished.verify[i]);
1328*8ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
1329*8ccd4a63SDavid du Colombier 		break;
1330*8ccd4a63SDavid du Colombier 	}
1331*8ccd4a63SDavid du Colombier 	USED(bs);
1332*8ccd4a63SDavid du Colombier 	return buf;
1333*8ccd4a63SDavid du Colombier }
1334*8ccd4a63SDavid du Colombier 
1335*8ccd4a63SDavid du Colombier static void
1336*8ccd4a63SDavid du Colombier tlsError(TlsConnection *c, int err, char *fmt, ...)
1337*8ccd4a63SDavid du Colombier {
1338*8ccd4a63SDavid du Colombier 	char msg[512];
1339*8ccd4a63SDavid du Colombier 	va_list arg;
1340*8ccd4a63SDavid du Colombier 
1341*8ccd4a63SDavid du Colombier 	va_start(arg, fmt);
1342*8ccd4a63SDavid du Colombier 	vseprint(msg, msg+sizeof(msg), fmt, arg);
1343*8ccd4a63SDavid du Colombier 	va_end(arg);
1344*8ccd4a63SDavid du Colombier 	if(c->trace)
1345*8ccd4a63SDavid du Colombier 		c->trace("tlsError: %s\n", msg);
1346*8ccd4a63SDavid du Colombier 	else if(c->erred)
1347*8ccd4a63SDavid du Colombier 		fprint(2, "double error: %r, %s", msg);
1348*8ccd4a63SDavid du Colombier 	else
1349*8ccd4a63SDavid du Colombier 		werrstr("tls: local %s", msg);
1350*8ccd4a63SDavid du Colombier 	c->erred = 1;
1351*8ccd4a63SDavid du Colombier 	fprint(c->ctl, "alert %d", err);
1352*8ccd4a63SDavid du Colombier }
1353*8ccd4a63SDavid du Colombier 
1354*8ccd4a63SDavid du Colombier // commit to specific version number
1355*8ccd4a63SDavid du Colombier static int
1356*8ccd4a63SDavid du Colombier setVersion(TlsConnection *c, int version)
1357*8ccd4a63SDavid du Colombier {
1358*8ccd4a63SDavid du Colombier 	if(c->verset || version > MaxProtoVersion || version < MinProtoVersion)
1359*8ccd4a63SDavid du Colombier 		return -1;
1360*8ccd4a63SDavid du Colombier 	if(version > c->version)
1361*8ccd4a63SDavid du Colombier 		version = c->version;
1362*8ccd4a63SDavid du Colombier 	if(version == SSL3Version) {
1363*8ccd4a63SDavid du Colombier 		c->version = version;
1364*8ccd4a63SDavid du Colombier 		c->finished.n = SSL3FinishedLen;
1365*8ccd4a63SDavid du Colombier 	}else if(version == TLSVersion){
1366*8ccd4a63SDavid du Colombier 		c->version = version;
1367*8ccd4a63SDavid du Colombier 		c->finished.n = TLSFinishedLen;
1368*8ccd4a63SDavid du Colombier 	}else
1369*8ccd4a63SDavid du Colombier 		return -1;
1370*8ccd4a63SDavid du Colombier 	c->verset = 1;
1371*8ccd4a63SDavid du Colombier 	return fprint(c->ctl, "version 0x%x", version);
1372*8ccd4a63SDavid du Colombier }
1373*8ccd4a63SDavid du Colombier 
1374*8ccd4a63SDavid du Colombier // confirm that received Finished message matches the expected value
1375*8ccd4a63SDavid du Colombier static int
1376*8ccd4a63SDavid du Colombier finishedMatch(TlsConnection *c, Finished *f)
1377*8ccd4a63SDavid du Colombier {
1378*8ccd4a63SDavid du Colombier 	return memcmp(f->verify, c->finished.verify, f->n) == 0;
1379*8ccd4a63SDavid du Colombier }
1380*8ccd4a63SDavid du Colombier 
1381*8ccd4a63SDavid du Colombier // free memory associated with TlsConnection struct
1382*8ccd4a63SDavid du Colombier //		(but don't close the TLS channel itself)
1383*8ccd4a63SDavid du Colombier static void
1384*8ccd4a63SDavid du Colombier tlsConnectionFree(TlsConnection *c)
1385*8ccd4a63SDavid du Colombier {
1386*8ccd4a63SDavid du Colombier 	tlsSecClose(c->sec);
1387*8ccd4a63SDavid du Colombier 	freebytes(c->sid);
1388*8ccd4a63SDavid du Colombier 	freebytes(c->cert);
1389*8ccd4a63SDavid du Colombier 	memset(c, 0, sizeof(c));
1390*8ccd4a63SDavid du Colombier 	free(c);
1391*8ccd4a63SDavid du Colombier }
1392*8ccd4a63SDavid du Colombier 
1393*8ccd4a63SDavid du Colombier 
1394*8ccd4a63SDavid du Colombier //================= cipher choices ========================
1395*8ccd4a63SDavid du Colombier 
1396*8ccd4a63SDavid du Colombier static int weakCipher[CipherMax] =
1397*8ccd4a63SDavid du Colombier {
1398*8ccd4a63SDavid du Colombier 	1,	/* TLS_NULL_WITH_NULL_NULL */
1399*8ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_WITH_NULL_MD5 */
1400*8ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_WITH_NULL_SHA */
1401*8ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */
1402*8ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_RC4_128_MD5 */
1403*8ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_RC4_128_SHA */
1404*8ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */
1405*8ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_IDEA_CBC_SHA */
1406*8ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */
1407*8ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_DES_CBC_SHA */
1408*8ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_3DES_EDE_CBC_SHA */
1409*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */
1410*8ccd4a63SDavid du Colombier 	0,	/* TLS_DH_DSS_WITH_DES_CBC_SHA */
1411*8ccd4a63SDavid du Colombier 	0,	/* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */
1412*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */
1413*8ccd4a63SDavid du Colombier 	0,	/* TLS_DH_RSA_WITH_DES_CBC_SHA */
1414*8ccd4a63SDavid du Colombier 	0,	/* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */
1415*8ccd4a63SDavid du Colombier 	1,	/* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */
1416*8ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_DSS_WITH_DES_CBC_SHA */
1417*8ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */
1418*8ccd4a63SDavid du Colombier 	1,	/* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */
1419*8ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_RSA_WITH_DES_CBC_SHA */
1420*8ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */
1421*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */
1422*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_RC4_128_MD5 */
1423*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */
1424*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_DES_CBC_SHA */
1425*8ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */
1426*8ccd4a63SDavid du Colombier };
1427*8ccd4a63SDavid du Colombier 
1428*8ccd4a63SDavid du Colombier static int
1429*8ccd4a63SDavid du Colombier setAlgs(TlsConnection *c, int a)
1430*8ccd4a63SDavid du Colombier {
1431*8ccd4a63SDavid du Colombier 	int i;
1432*8ccd4a63SDavid du Colombier 
1433*8ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
1434*8ccd4a63SDavid du Colombier 		if(cipherAlgs[i].tlsid == a){
1435*8ccd4a63SDavid du Colombier 			c->enc = cipherAlgs[i].enc;
1436*8ccd4a63SDavid du Colombier 			c->digest = cipherAlgs[i].digest;
1437*8ccd4a63SDavid du Colombier 			c->nsecret = cipherAlgs[i].nsecret;
1438*8ccd4a63SDavid du Colombier 			if(c->nsecret > MaxKeyData)
1439*8ccd4a63SDavid du Colombier 				return 0;
1440*8ccd4a63SDavid du Colombier 			return 1;
1441*8ccd4a63SDavid du Colombier 		}
1442*8ccd4a63SDavid du Colombier 	}
1443*8ccd4a63SDavid du Colombier 	return 0;
1444*8ccd4a63SDavid du Colombier }
1445*8ccd4a63SDavid du Colombier 
1446*8ccd4a63SDavid du Colombier static int
1447*8ccd4a63SDavid du Colombier okCipher(Ints *cv)
1448*8ccd4a63SDavid du Colombier {
1449*8ccd4a63SDavid du Colombier 	int weak, i, j, c;
1450*8ccd4a63SDavid du Colombier 
1451*8ccd4a63SDavid du Colombier 	weak = 1;
1452*8ccd4a63SDavid du Colombier 	for(i = 0; i < cv->len; i++) {
1453*8ccd4a63SDavid du Colombier 		c = cv->data[i];
1454*8ccd4a63SDavid du Colombier 		if(c >= CipherMax)
1455*8ccd4a63SDavid du Colombier 			weak = 0;
1456*8ccd4a63SDavid du Colombier 		else
1457*8ccd4a63SDavid du Colombier 			weak &= weakCipher[c];
1458*8ccd4a63SDavid du Colombier 		for(j = 0; j < nelem(cipherAlgs); j++)
1459*8ccd4a63SDavid du Colombier 			if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
1460*8ccd4a63SDavid du Colombier 				return c;
1461*8ccd4a63SDavid du Colombier 	}
1462*8ccd4a63SDavid du Colombier 	if(weak)
1463*8ccd4a63SDavid du Colombier 		return -2;
1464*8ccd4a63SDavid du Colombier 	return -1;
1465*8ccd4a63SDavid du Colombier }
1466*8ccd4a63SDavid du Colombier 
1467*8ccd4a63SDavid du Colombier static int
1468*8ccd4a63SDavid du Colombier okCompression(Bytes *cv)
1469*8ccd4a63SDavid du Colombier {
1470*8ccd4a63SDavid du Colombier 	int i, j, c;
1471*8ccd4a63SDavid du Colombier 
1472*8ccd4a63SDavid du Colombier 	for(i = 0; i < cv->len; i++) {
1473*8ccd4a63SDavid du Colombier 		c = cv->data[i];
1474*8ccd4a63SDavid du Colombier 		for(j = 0; j < nelem(compressors); j++) {
1475*8ccd4a63SDavid du Colombier 			if(compressors[j] == c)
1476*8ccd4a63SDavid du Colombier 				return c;
1477*8ccd4a63SDavid du Colombier 		}
1478*8ccd4a63SDavid du Colombier 	}
1479*8ccd4a63SDavid du Colombier 	return -1;
1480*8ccd4a63SDavid du Colombier }
1481*8ccd4a63SDavid du Colombier 
1482*8ccd4a63SDavid du Colombier static Lock	ciphLock;
1483*8ccd4a63SDavid du Colombier static int	nciphers;
1484*8ccd4a63SDavid du Colombier 
1485*8ccd4a63SDavid du Colombier static int
1486*8ccd4a63SDavid du Colombier initCiphers(void)
1487*8ccd4a63SDavid du Colombier {
1488*8ccd4a63SDavid du Colombier 	enum {MaxAlgF = 1024, MaxAlgs = 10};
1489*8ccd4a63SDavid du Colombier 	char s[MaxAlgF], *flds[MaxAlgs];
1490*8ccd4a63SDavid du Colombier 	int i, j, n, ok;
1491*8ccd4a63SDavid du Colombier 
1492*8ccd4a63SDavid du Colombier 	lock(&ciphLock);
1493*8ccd4a63SDavid du Colombier 	if(nciphers){
1494*8ccd4a63SDavid du Colombier 		unlock(&ciphLock);
1495*8ccd4a63SDavid du Colombier 		return nciphers;
1496*8ccd4a63SDavid du Colombier 	}
1497*8ccd4a63SDavid du Colombier 	j = open("#a/tls/encalgs", OREAD);
1498*8ccd4a63SDavid du Colombier 	if(j < 0){
1499*8ccd4a63SDavid du Colombier 		werrstr("can't open #a/tls/encalgs: %r");
1500*8ccd4a63SDavid du Colombier 		return 0;
1501*8ccd4a63SDavid du Colombier 	}
1502*8ccd4a63SDavid du Colombier 	n = read(j, s, MaxAlgF-1);
1503*8ccd4a63SDavid du Colombier 	close(j);
1504*8ccd4a63SDavid du Colombier 	if(n <= 0){
1505*8ccd4a63SDavid du Colombier 		werrstr("nothing in #a/tls/encalgs: %r");
1506*8ccd4a63SDavid du Colombier 		return 0;
1507*8ccd4a63SDavid du Colombier 	}
1508*8ccd4a63SDavid du Colombier 	s[n] = 0;
1509*8ccd4a63SDavid du Colombier 	n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
1510*8ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
1511*8ccd4a63SDavid du Colombier 		ok = 0;
1512*8ccd4a63SDavid du Colombier 		for(j = 0; j < n; j++){
1513*8ccd4a63SDavid du Colombier 			if(strcmp(cipherAlgs[i].enc, flds[j]) == 0){
1514*8ccd4a63SDavid du Colombier 				ok = 1;
1515*8ccd4a63SDavid du Colombier 				break;
1516*8ccd4a63SDavid du Colombier 			}
1517*8ccd4a63SDavid du Colombier 		}
1518*8ccd4a63SDavid du Colombier 		cipherAlgs[i].ok = ok;
1519*8ccd4a63SDavid du Colombier 	}
1520*8ccd4a63SDavid du Colombier 
1521*8ccd4a63SDavid du Colombier 	j = open("#a/tls/hashalgs", OREAD);
1522*8ccd4a63SDavid du Colombier 	if(j < 0){
1523*8ccd4a63SDavid du Colombier 		werrstr("can't open #a/tls/hashalgs: %r");
1524*8ccd4a63SDavid du Colombier 		return 0;
1525*8ccd4a63SDavid du Colombier 	}
1526*8ccd4a63SDavid du Colombier 	n = read(j, s, MaxAlgF-1);
1527*8ccd4a63SDavid du Colombier 	close(j);
1528*8ccd4a63SDavid du Colombier 	if(n <= 0){
1529*8ccd4a63SDavid du Colombier 		werrstr("nothing in #a/tls/hashalgs: %r");
1530*8ccd4a63SDavid du Colombier 		return 0;
1531*8ccd4a63SDavid du Colombier 	}
1532*8ccd4a63SDavid du Colombier 	s[n] = 0;
1533*8ccd4a63SDavid du Colombier 	n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
1534*8ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
1535*8ccd4a63SDavid du Colombier 		ok = 0;
1536*8ccd4a63SDavid du Colombier 		for(j = 0; j < n; j++){
1537*8ccd4a63SDavid du Colombier 			if(strcmp(cipherAlgs[i].digest, flds[j]) == 0){
1538*8ccd4a63SDavid du Colombier 				ok = 1;
1539*8ccd4a63SDavid du Colombier 				break;
1540*8ccd4a63SDavid du Colombier 			}
1541*8ccd4a63SDavid du Colombier 		}
1542*8ccd4a63SDavid du Colombier 		cipherAlgs[i].ok &= ok;
1543*8ccd4a63SDavid du Colombier 		if(cipherAlgs[i].ok)
1544*8ccd4a63SDavid du Colombier 			nciphers++;
1545*8ccd4a63SDavid du Colombier 	}
1546*8ccd4a63SDavid du Colombier 	unlock(&ciphLock);
1547*8ccd4a63SDavid du Colombier 	return nciphers;
1548*8ccd4a63SDavid du Colombier }
1549*8ccd4a63SDavid du Colombier 
1550*8ccd4a63SDavid du Colombier static Ints*
1551*8ccd4a63SDavid du Colombier makeciphers(void)
1552*8ccd4a63SDavid du Colombier {
1553*8ccd4a63SDavid du Colombier 	Ints *is;
1554*8ccd4a63SDavid du Colombier 	int i, j;
1555*8ccd4a63SDavid du Colombier 
1556*8ccd4a63SDavid du Colombier 	is = newints(nciphers);
1557*8ccd4a63SDavid du Colombier 	j = 0;
1558*8ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
1559*8ccd4a63SDavid du Colombier 		if(cipherAlgs[i].ok)
1560*8ccd4a63SDavid du Colombier 			is->data[j++] = cipherAlgs[i].tlsid;
1561*8ccd4a63SDavid du Colombier 	}
1562*8ccd4a63SDavid du Colombier 	return is;
1563*8ccd4a63SDavid du Colombier }
1564*8ccd4a63SDavid du Colombier 
1565*8ccd4a63SDavid du Colombier 
1566*8ccd4a63SDavid du Colombier 
1567*8ccd4a63SDavid du Colombier //================= security functions ========================
1568*8ccd4a63SDavid du Colombier 
1569*8ccd4a63SDavid du Colombier // given X.509 certificate, set up connection to factotum
1570*8ccd4a63SDavid du Colombier //	for using corresponding private key
1571*8ccd4a63SDavid du Colombier static AuthRpc*
1572*8ccd4a63SDavid du Colombier factotum_rsa_open(uchar *cert, int certlen)
1573*8ccd4a63SDavid du Colombier {
1574*8ccd4a63SDavid du Colombier 	int afd;
1575*8ccd4a63SDavid du Colombier 	char *s;
1576*8ccd4a63SDavid du Colombier 	mpint *pub = nil;
1577*8ccd4a63SDavid du Colombier 	RSApub *rsapub;
1578*8ccd4a63SDavid du Colombier 	AuthRpc *rpc;
1579*8ccd4a63SDavid du Colombier 
1580*8ccd4a63SDavid du Colombier 	// start talking to factotum
1581*8ccd4a63SDavid du Colombier 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
1582*8ccd4a63SDavid du Colombier 		return nil;
1583*8ccd4a63SDavid du Colombier 	if((rpc = auth_allocrpc(afd)) == nil){
1584*8ccd4a63SDavid du Colombier 		close(afd);
1585*8ccd4a63SDavid du Colombier 		return nil;
1586*8ccd4a63SDavid du Colombier 	}
1587*8ccd4a63SDavid du Colombier 	s = "proto=rsa service=tls role=client";
1588*8ccd4a63SDavid du Colombier 	if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
1589*8ccd4a63SDavid du Colombier 		factotum_rsa_close(rpc);
1590*8ccd4a63SDavid du Colombier 		return nil;
1591*8ccd4a63SDavid du Colombier 	}
1592*8ccd4a63SDavid du Colombier 
1593*8ccd4a63SDavid du Colombier 	// roll factotum keyring around to match certificate
1594*8ccd4a63SDavid du Colombier 	rsapub = X509toRSApub(cert, certlen, nil, 0);
1595*8ccd4a63SDavid du Colombier 	while(1){
1596*8ccd4a63SDavid du Colombier 		if(auth_rpc(rpc, "read", nil, 0) != ARok){
1597*8ccd4a63SDavid du Colombier 			factotum_rsa_close(rpc);
1598*8ccd4a63SDavid du Colombier 			rpc = nil;
1599*8ccd4a63SDavid du Colombier 			goto done;
1600*8ccd4a63SDavid du Colombier 		}
1601*8ccd4a63SDavid du Colombier 		pub = strtomp(rpc->arg, nil, 16, nil);
1602*8ccd4a63SDavid du Colombier 		assert(pub != nil);
1603*8ccd4a63SDavid du Colombier 		if(mpcmp(pub,rsapub->n) == 0)
1604*8ccd4a63SDavid du Colombier 			break;
1605*8ccd4a63SDavid du Colombier 	}
1606*8ccd4a63SDavid du Colombier done:
1607*8ccd4a63SDavid du Colombier 	mpfree(pub);
1608*8ccd4a63SDavid du Colombier 	rsapubfree(rsapub);
1609*8ccd4a63SDavid du Colombier 	return rpc;
1610*8ccd4a63SDavid du Colombier }
1611*8ccd4a63SDavid du Colombier 
1612*8ccd4a63SDavid du Colombier static mpint*
1613*8ccd4a63SDavid du Colombier factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher)
1614*8ccd4a63SDavid du Colombier {
1615*8ccd4a63SDavid du Colombier 	char *p;
1616*8ccd4a63SDavid du Colombier 	int rv;
1617*8ccd4a63SDavid du Colombier 
1618*8ccd4a63SDavid du Colombier 	if((p = mptoa(cipher, 16, nil, 0)) == nil)
1619*8ccd4a63SDavid du Colombier 		return nil;
1620*8ccd4a63SDavid du Colombier 	rv = auth_rpc(rpc, "write", p, strlen(p));
1621*8ccd4a63SDavid du Colombier 	free(p);
1622*8ccd4a63SDavid du Colombier 	if(rv != ARok || auth_rpc(rpc, "read", nil, 0) != ARok)
1623*8ccd4a63SDavid du Colombier 		return nil;
1624*8ccd4a63SDavid du Colombier 	mpfree(cipher);
1625*8ccd4a63SDavid du Colombier 	return strtomp(rpc->arg, nil, 16, nil);
1626*8ccd4a63SDavid du Colombier }
1627*8ccd4a63SDavid du Colombier 
1628*8ccd4a63SDavid du Colombier static void
1629*8ccd4a63SDavid du Colombier factotum_rsa_close(AuthRpc*rpc)
1630*8ccd4a63SDavid du Colombier {
1631*8ccd4a63SDavid du Colombier 	if(!rpc)
1632*8ccd4a63SDavid du Colombier 		return;
1633*8ccd4a63SDavid du Colombier 	close(rpc->afd);
1634*8ccd4a63SDavid du Colombier 	auth_freerpc(rpc);
1635*8ccd4a63SDavid du Colombier }
1636*8ccd4a63SDavid du Colombier 
1637*8ccd4a63SDavid du Colombier static void
1638*8ccd4a63SDavid du Colombier tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
1639*8ccd4a63SDavid du Colombier {
1640*8ccd4a63SDavid du Colombier 	uchar ai[MD5dlen], tmp[MD5dlen];
1641*8ccd4a63SDavid du Colombier 	int i, n;
1642*8ccd4a63SDavid du Colombier 	MD5state *s;
1643*8ccd4a63SDavid du Colombier 
1644*8ccd4a63SDavid du Colombier 	// generate a1
1645*8ccd4a63SDavid du Colombier 	s = hmac_md5(label, nlabel, key, nkey, nil, nil);
1646*8ccd4a63SDavid du Colombier 	s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
1647*8ccd4a63SDavid du Colombier 	hmac_md5(seed1, nseed1, key, nkey, ai, s);
1648*8ccd4a63SDavid du Colombier 
1649*8ccd4a63SDavid du Colombier 	while(nbuf > 0) {
1650*8ccd4a63SDavid du Colombier 		s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil);
1651*8ccd4a63SDavid du Colombier 		s = hmac_md5(label, nlabel, key, nkey, nil, s);
1652*8ccd4a63SDavid du Colombier 		s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
1653*8ccd4a63SDavid du Colombier 		hmac_md5(seed1, nseed1, key, nkey, tmp, s);
1654*8ccd4a63SDavid du Colombier 		n = MD5dlen;
1655*8ccd4a63SDavid du Colombier 		if(n > nbuf)
1656*8ccd4a63SDavid du Colombier 			n = nbuf;
1657*8ccd4a63SDavid du Colombier 		for(i = 0; i < n; i++)
1658*8ccd4a63SDavid du Colombier 			buf[i] ^= tmp[i];
1659*8ccd4a63SDavid du Colombier 		buf += n;
1660*8ccd4a63SDavid du Colombier 		nbuf -= n;
1661*8ccd4a63SDavid du Colombier 		hmac_md5(ai, MD5dlen, key, nkey, tmp, nil);
1662*8ccd4a63SDavid du Colombier 		memmove(ai, tmp, MD5dlen);
1663*8ccd4a63SDavid du Colombier 	}
1664*8ccd4a63SDavid du Colombier }
1665*8ccd4a63SDavid du Colombier 
1666*8ccd4a63SDavid du Colombier static void
1667*8ccd4a63SDavid du Colombier tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
1668*8ccd4a63SDavid du Colombier {
1669*8ccd4a63SDavid du Colombier 	uchar ai[SHA1dlen], tmp[SHA1dlen];
1670*8ccd4a63SDavid du Colombier 	int i, n;
1671*8ccd4a63SDavid du Colombier 	SHAstate *s;
1672*8ccd4a63SDavid du Colombier 
1673*8ccd4a63SDavid du Colombier 	// generate a1
1674*8ccd4a63SDavid du Colombier 	s = hmac_sha1(label, nlabel, key, nkey, nil, nil);
1675*8ccd4a63SDavid du Colombier 	s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
1676*8ccd4a63SDavid du Colombier 	hmac_sha1(seed1, nseed1, key, nkey, ai, s);
1677*8ccd4a63SDavid du Colombier 
1678*8ccd4a63SDavid du Colombier 	while(nbuf > 0) {
1679*8ccd4a63SDavid du Colombier 		s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil);
1680*8ccd4a63SDavid du Colombier 		s = hmac_sha1(label, nlabel, key, nkey, nil, s);
1681*8ccd4a63SDavid du Colombier 		s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
1682*8ccd4a63SDavid du Colombier 		hmac_sha1(seed1, nseed1, key, nkey, tmp, s);
1683*8ccd4a63SDavid du Colombier 		n = SHA1dlen;
1684*8ccd4a63SDavid du Colombier 		if(n > nbuf)
1685*8ccd4a63SDavid du Colombier 			n = nbuf;
1686*8ccd4a63SDavid du Colombier 		for(i = 0; i < n; i++)
1687*8ccd4a63SDavid du Colombier 			buf[i] ^= tmp[i];
1688*8ccd4a63SDavid du Colombier 		buf += n;
1689*8ccd4a63SDavid du Colombier 		nbuf -= n;
1690*8ccd4a63SDavid du Colombier 		hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil);
1691*8ccd4a63SDavid du Colombier 		memmove(ai, tmp, SHA1dlen);
1692*8ccd4a63SDavid du Colombier 	}
1693*8ccd4a63SDavid du Colombier }
1694*8ccd4a63SDavid du Colombier 
1695*8ccd4a63SDavid du Colombier // fill buf with md5(args)^sha1(args)
1696*8ccd4a63SDavid du Colombier static void
1697*8ccd4a63SDavid du Colombier tlsPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
1698*8ccd4a63SDavid du Colombier {
1699*8ccd4a63SDavid du Colombier 	int i;
1700*8ccd4a63SDavid du Colombier 	int nlabel = strlen(label);
1701*8ccd4a63SDavid du Colombier 	int n = (nkey + 1) >> 1;
1702*8ccd4a63SDavid du Colombier 
1703*8ccd4a63SDavid du Colombier 	for(i = 0; i < nbuf; i++)
1704*8ccd4a63SDavid du Colombier 		buf[i] = 0;
1705*8ccd4a63SDavid du Colombier 	tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
1706*8ccd4a63SDavid du Colombier 	tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
1707*8ccd4a63SDavid du Colombier }
1708*8ccd4a63SDavid du Colombier 
1709*8ccd4a63SDavid du Colombier /*
1710*8ccd4a63SDavid du Colombier  * for setting server session id's
1711*8ccd4a63SDavid du Colombier  */
1712*8ccd4a63SDavid du Colombier static Lock	sidLock;
1713*8ccd4a63SDavid du Colombier static long	maxSid = 1;
1714*8ccd4a63SDavid du Colombier 
1715*8ccd4a63SDavid du Colombier /* the keys are verified to have the same public components
1716*8ccd4a63SDavid du Colombier  * and to function correctly with pkcs 1 encryption and decryption. */
1717*8ccd4a63SDavid du Colombier static TlsSec*
1718*8ccd4a63SDavid du Colombier tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom)
1719*8ccd4a63SDavid du Colombier {
1720*8ccd4a63SDavid du Colombier 	TlsSec *sec = emalloc(sizeof(*sec));
1721*8ccd4a63SDavid du Colombier 
1722*8ccd4a63SDavid du Colombier 	USED(csid); USED(ncsid);  // ignore csid for now
1723*8ccd4a63SDavid du Colombier 
1724*8ccd4a63SDavid du Colombier 	memmove(sec->crandom, crandom, RandomSize);
1725*8ccd4a63SDavid du Colombier 	sec->clientVers = cvers;
1726*8ccd4a63SDavid du Colombier 
1727*8ccd4a63SDavid du Colombier 	put32(sec->srandom, time(0));
1728*8ccd4a63SDavid du Colombier 	genrandom(sec->srandom+4, RandomSize-4);
1729*8ccd4a63SDavid du Colombier 	memmove(srandom, sec->srandom, RandomSize);
1730*8ccd4a63SDavid du Colombier 
1731*8ccd4a63SDavid du Colombier 	/*
1732*8ccd4a63SDavid du Colombier 	 * make up a unique sid: use our pid, and and incrementing id
1733*8ccd4a63SDavid du Colombier 	 * can signal no sid by setting nssid to 0.
1734*8ccd4a63SDavid du Colombier 	 */
1735*8ccd4a63SDavid du Colombier 	memset(ssid, 0, SidSize);
1736*8ccd4a63SDavid du Colombier 	put32(ssid, getpid());
1737*8ccd4a63SDavid du Colombier 	lock(&sidLock);
1738*8ccd4a63SDavid du Colombier 	put32(ssid+4, maxSid++);
1739*8ccd4a63SDavid du Colombier 	unlock(&sidLock);
1740*8ccd4a63SDavid du Colombier 	*nssid = SidSize;
1741*8ccd4a63SDavid du Colombier 	return sec;
1742*8ccd4a63SDavid du Colombier }
1743*8ccd4a63SDavid du Colombier 
1744*8ccd4a63SDavid du Colombier static int
1745*8ccd4a63SDavid du Colombier tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd)
1746*8ccd4a63SDavid du Colombier {
1747*8ccd4a63SDavid du Colombier 	if(epm != nil){
1748*8ccd4a63SDavid du Colombier 		if(setVers(sec, vers) < 0)
1749*8ccd4a63SDavid du Colombier 			goto Err;
1750*8ccd4a63SDavid du Colombier 		serverMasterSecret(sec, epm, nepm);
1751*8ccd4a63SDavid du Colombier 	}else if(sec->vers != vers){
1752*8ccd4a63SDavid du Colombier 		werrstr("mismatched session versions");
1753*8ccd4a63SDavid du Colombier 		goto Err;
1754*8ccd4a63SDavid du Colombier 	}
1755*8ccd4a63SDavid du Colombier 	setSecrets(sec, kd, nkd);
1756*8ccd4a63SDavid du Colombier 	return 0;
1757*8ccd4a63SDavid du Colombier Err:
1758*8ccd4a63SDavid du Colombier 	sec->ok = -1;
1759*8ccd4a63SDavid du Colombier 	return -1;
1760*8ccd4a63SDavid du Colombier }
1761*8ccd4a63SDavid du Colombier 
1762*8ccd4a63SDavid du Colombier static TlsSec*
1763*8ccd4a63SDavid du Colombier tlsSecInitc(int cvers, uchar *crandom)
1764*8ccd4a63SDavid du Colombier {
1765*8ccd4a63SDavid du Colombier 	TlsSec *sec = emalloc(sizeof(*sec));
1766*8ccd4a63SDavid du Colombier 	sec->clientVers = cvers;
1767*8ccd4a63SDavid du Colombier 	put32(sec->crandom, time(0));
1768*8ccd4a63SDavid du Colombier 	genrandom(sec->crandom+4, RandomSize-4);
1769*8ccd4a63SDavid du Colombier 	memmove(crandom, sec->crandom, RandomSize);
1770*8ccd4a63SDavid du Colombier 	return sec;
1771*8ccd4a63SDavid du Colombier }
1772*8ccd4a63SDavid du Colombier 
1773*8ccd4a63SDavid du Colombier static int
1774*8ccd4a63SDavid du Colombier tlsSecSecretc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers, uchar **epm, int *nepm, uchar *kd, int nkd)
1775*8ccd4a63SDavid du Colombier {
1776*8ccd4a63SDavid du Colombier 	RSApub *pub;
1777*8ccd4a63SDavid du Colombier 
1778*8ccd4a63SDavid du Colombier 	pub = nil;
1779*8ccd4a63SDavid du Colombier 
1780*8ccd4a63SDavid du Colombier 	USED(sid);
1781*8ccd4a63SDavid du Colombier 	USED(nsid);
1782*8ccd4a63SDavid du Colombier 
1783*8ccd4a63SDavid du Colombier 	memmove(sec->srandom, srandom, RandomSize);
1784*8ccd4a63SDavid du Colombier 
1785*8ccd4a63SDavid du Colombier 	if(setVers(sec, vers) < 0)
1786*8ccd4a63SDavid du Colombier 		goto Err;
1787*8ccd4a63SDavid du Colombier 
1788*8ccd4a63SDavid du Colombier 	pub = X509toRSApub(cert, ncert, nil, 0);
1789*8ccd4a63SDavid du Colombier 	if(pub == nil){
1790*8ccd4a63SDavid du Colombier 		werrstr("invalid x509/rsa certificate");
1791*8ccd4a63SDavid du Colombier 		goto Err;
1792*8ccd4a63SDavid du Colombier 	}
1793*8ccd4a63SDavid du Colombier 	if(clientMasterSecret(sec, pub, epm, nepm) < 0)
1794*8ccd4a63SDavid du Colombier 		goto Err;
1795*8ccd4a63SDavid du Colombier 	rsapubfree(pub);
1796*8ccd4a63SDavid du Colombier 	setSecrets(sec, kd, nkd);
1797*8ccd4a63SDavid du Colombier 	return 0;
1798*8ccd4a63SDavid du Colombier 
1799*8ccd4a63SDavid du Colombier Err:
1800*8ccd4a63SDavid du Colombier 	if(pub != nil)
1801*8ccd4a63SDavid du Colombier 		rsapubfree(pub);
1802*8ccd4a63SDavid du Colombier 	sec->ok = -1;
1803*8ccd4a63SDavid du Colombier 	return -1;
1804*8ccd4a63SDavid du Colombier }
1805*8ccd4a63SDavid du Colombier 
1806*8ccd4a63SDavid du Colombier static int
1807*8ccd4a63SDavid du Colombier tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient)
1808*8ccd4a63SDavid du Colombier {
1809*8ccd4a63SDavid du Colombier 	if(sec->nfin != nfin){
1810*8ccd4a63SDavid du Colombier 		sec->ok = -1;
1811*8ccd4a63SDavid du Colombier 		werrstr("invalid finished exchange");
1812*8ccd4a63SDavid du Colombier 		return -1;
1813*8ccd4a63SDavid du Colombier 	}
1814*8ccd4a63SDavid du Colombier 	md5.malloced = 0;
1815*8ccd4a63SDavid du Colombier 	sha1.malloced = 0;
1816*8ccd4a63SDavid du Colombier 	(*sec->setFinished)(sec, md5, sha1, fin, isclient);
1817*8ccd4a63SDavid du Colombier 	return 1;
1818*8ccd4a63SDavid du Colombier }
1819*8ccd4a63SDavid du Colombier 
1820*8ccd4a63SDavid du Colombier static void
1821*8ccd4a63SDavid du Colombier tlsSecOk(TlsSec *sec)
1822*8ccd4a63SDavid du Colombier {
1823*8ccd4a63SDavid du Colombier 	if(sec->ok == 0)
1824*8ccd4a63SDavid du Colombier 		sec->ok = 1;
1825*8ccd4a63SDavid du Colombier }
1826*8ccd4a63SDavid du Colombier 
1827*8ccd4a63SDavid du Colombier static void
1828*8ccd4a63SDavid du Colombier tlsSecKill(TlsSec *sec)
1829*8ccd4a63SDavid du Colombier {
1830*8ccd4a63SDavid du Colombier 	if(!sec)
1831*8ccd4a63SDavid du Colombier 		return;
1832*8ccd4a63SDavid du Colombier 	factotum_rsa_close(sec->rpc);
1833*8ccd4a63SDavid du Colombier 	sec->ok = -1;
1834*8ccd4a63SDavid du Colombier }
1835*8ccd4a63SDavid du Colombier 
1836*8ccd4a63SDavid du Colombier static void
1837*8ccd4a63SDavid du Colombier tlsSecClose(TlsSec *sec)
1838*8ccd4a63SDavid du Colombier {
1839*8ccd4a63SDavid du Colombier 	if(!sec)
1840*8ccd4a63SDavid du Colombier 		return;
1841*8ccd4a63SDavid du Colombier 	factotum_rsa_close(sec->rpc);
1842*8ccd4a63SDavid du Colombier 	free(sec->server);
1843*8ccd4a63SDavid du Colombier 	free(sec);
1844*8ccd4a63SDavid du Colombier }
1845*8ccd4a63SDavid du Colombier 
1846*8ccd4a63SDavid du Colombier static int
1847*8ccd4a63SDavid du Colombier setVers(TlsSec *sec, int v)
1848*8ccd4a63SDavid du Colombier {
1849*8ccd4a63SDavid du Colombier 	if(v == SSL3Version){
1850*8ccd4a63SDavid du Colombier 		sec->setFinished = sslSetFinished;
1851*8ccd4a63SDavid du Colombier 		sec->nfin = SSL3FinishedLen;
1852*8ccd4a63SDavid du Colombier 		sec->prf = sslPRF;
1853*8ccd4a63SDavid du Colombier 	}else if(v == TLSVersion){
1854*8ccd4a63SDavid du Colombier 		sec->setFinished = tlsSetFinished;
1855*8ccd4a63SDavid du Colombier 		sec->nfin = TLSFinishedLen;
1856*8ccd4a63SDavid du Colombier 		sec->prf = tlsPRF;
1857*8ccd4a63SDavid du Colombier 	}else{
1858*8ccd4a63SDavid du Colombier 		werrstr("invalid version");
1859*8ccd4a63SDavid du Colombier 		return -1;
1860*8ccd4a63SDavid du Colombier 	}
1861*8ccd4a63SDavid du Colombier 	sec->vers = v;
1862*8ccd4a63SDavid du Colombier 	return 0;
1863*8ccd4a63SDavid du Colombier }
1864*8ccd4a63SDavid du Colombier 
1865*8ccd4a63SDavid du Colombier /*
1866*8ccd4a63SDavid du Colombier  * generate secret keys from the master secret.
1867*8ccd4a63SDavid du Colombier  *
1868*8ccd4a63SDavid du Colombier  * different crypto selections will require different amounts
1869*8ccd4a63SDavid du Colombier  * of key expansion and use of key expansion data,
1870*8ccd4a63SDavid du Colombier  * but it's all generated using the same function.
1871*8ccd4a63SDavid du Colombier  */
1872*8ccd4a63SDavid du Colombier static void
1873*8ccd4a63SDavid du Colombier setSecrets(TlsSec *sec, uchar *kd, int nkd)
1874*8ccd4a63SDavid du Colombier {
1875*8ccd4a63SDavid du Colombier 	(*sec->prf)(kd, nkd, sec->sec, MasterSecretSize, "key expansion",
1876*8ccd4a63SDavid du Colombier 			sec->srandom, RandomSize, sec->crandom, RandomSize);
1877*8ccd4a63SDavid du Colombier }
1878*8ccd4a63SDavid du Colombier 
1879*8ccd4a63SDavid du Colombier /*
1880*8ccd4a63SDavid du Colombier  * set the master secret from the pre-master secret.
1881*8ccd4a63SDavid du Colombier  */
1882*8ccd4a63SDavid du Colombier static void
1883*8ccd4a63SDavid du Colombier setMasterSecret(TlsSec *sec, Bytes *pm)
1884*8ccd4a63SDavid du Colombier {
1885*8ccd4a63SDavid du Colombier 	(*sec->prf)(sec->sec, MasterSecretSize, pm->data, MasterSecretSize, "master secret",
1886*8ccd4a63SDavid du Colombier 			sec->crandom, RandomSize, sec->srandom, RandomSize);
1887*8ccd4a63SDavid du Colombier }
1888*8ccd4a63SDavid du Colombier 
1889*8ccd4a63SDavid du Colombier static void
1890*8ccd4a63SDavid du Colombier serverMasterSecret(TlsSec *sec, uchar *epm, int nepm)
1891*8ccd4a63SDavid du Colombier {
1892*8ccd4a63SDavid du Colombier 	Bytes *pm;
1893*8ccd4a63SDavid du Colombier 
1894*8ccd4a63SDavid du Colombier 	pm = pkcs1_decrypt(sec, epm, nepm);
1895*8ccd4a63SDavid du Colombier 
1896*8ccd4a63SDavid du Colombier 	// if the client messed up, just continue as if everything is ok,
1897*8ccd4a63SDavid du Colombier 	// to prevent attacks to check for correctly formatted messages.
1898*8ccd4a63SDavid du Colombier 	// Hence the fprint(2,) can't be replaced by tlsError(), which sends an Alert msg to the client.
1899*8ccd4a63SDavid du Colombier 	if(sec->ok < 0 || pm == nil || get16(pm->data) != sec->clientVers){
1900*8ccd4a63SDavid du Colombier 		fprint(2, "serverMasterSecret failed ok=%d pm=%p pmvers=%x cvers=%x nepm=%d\n",
1901*8ccd4a63SDavid du Colombier 			sec->ok, pm, pm ? get16(pm->data) : -1, sec->clientVers, nepm);
1902*8ccd4a63SDavid du Colombier 		sec->ok = -1;
1903*8ccd4a63SDavid du Colombier 		if(pm != nil)
1904*8ccd4a63SDavid du Colombier 			freebytes(pm);
1905*8ccd4a63SDavid du Colombier 		pm = newbytes(MasterSecretSize);
1906*8ccd4a63SDavid du Colombier 		genrandom(pm->data, MasterSecretSize);
1907*8ccd4a63SDavid du Colombier 	}
1908*8ccd4a63SDavid du Colombier 	setMasterSecret(sec, pm);
1909*8ccd4a63SDavid du Colombier 	memset(pm->data, 0, pm->len);
1910*8ccd4a63SDavid du Colombier 	freebytes(pm);
1911*8ccd4a63SDavid du Colombier }
1912*8ccd4a63SDavid du Colombier 
1913*8ccd4a63SDavid du Colombier static int
1914*8ccd4a63SDavid du Colombier clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm)
1915*8ccd4a63SDavid du Colombier {
1916*8ccd4a63SDavid du Colombier 	Bytes *pm, *key;
1917*8ccd4a63SDavid du Colombier 
1918*8ccd4a63SDavid du Colombier 	pm = newbytes(MasterSecretSize);
1919*8ccd4a63SDavid du Colombier 	put16(pm->data, sec->clientVers);
1920*8ccd4a63SDavid du Colombier 	genrandom(pm->data+2, MasterSecretSize - 2);
1921*8ccd4a63SDavid du Colombier 
1922*8ccd4a63SDavid du Colombier 	setMasterSecret(sec, pm);
1923*8ccd4a63SDavid du Colombier 
1924*8ccd4a63SDavid du Colombier 	key = pkcs1_encrypt(pm, pub, 2);
1925*8ccd4a63SDavid du Colombier 	memset(pm->data, 0, pm->len);
1926*8ccd4a63SDavid du Colombier 	freebytes(pm);
1927*8ccd4a63SDavid du Colombier 	if(key == nil){
1928*8ccd4a63SDavid du Colombier 		werrstr("tls pkcs1_encrypt failed");
1929*8ccd4a63SDavid du Colombier 		return -1;
1930*8ccd4a63SDavid du Colombier 	}
1931*8ccd4a63SDavid du Colombier 
1932*8ccd4a63SDavid du Colombier 	*nepm = key->len;
1933*8ccd4a63SDavid du Colombier 	*epm = malloc(*nepm);
1934*8ccd4a63SDavid du Colombier 	if(*epm == nil){
1935*8ccd4a63SDavid du Colombier 		freebytes(key);
1936*8ccd4a63SDavid du Colombier 		werrstr("out of memory");
1937*8ccd4a63SDavid du Colombier 		return -1;
1938*8ccd4a63SDavid du Colombier 	}
1939*8ccd4a63SDavid du Colombier 	memmove(*epm, key->data, *nepm);
1940*8ccd4a63SDavid du Colombier 
1941*8ccd4a63SDavid du Colombier 	freebytes(key);
1942*8ccd4a63SDavid du Colombier 
1943*8ccd4a63SDavid du Colombier 	return 1;
1944*8ccd4a63SDavid du Colombier }
1945*8ccd4a63SDavid du Colombier 
1946*8ccd4a63SDavid du Colombier static void
1947*8ccd4a63SDavid du Colombier sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
1948*8ccd4a63SDavid du Colombier {
1949*8ccd4a63SDavid du Colombier 	DigestState *s;
1950*8ccd4a63SDavid du Colombier 	uchar h0[MD5dlen], h1[SHA1dlen], pad[48];
1951*8ccd4a63SDavid du Colombier 	char *label;
1952*8ccd4a63SDavid du Colombier 
1953*8ccd4a63SDavid du Colombier 	if(isClient)
1954*8ccd4a63SDavid du Colombier 		label = "CLNT";
1955*8ccd4a63SDavid du Colombier 	else
1956*8ccd4a63SDavid du Colombier 		label = "SRVR";
1957*8ccd4a63SDavid du Colombier 
1958*8ccd4a63SDavid du Colombier 	md5((uchar*)label, 4, nil, &hsmd5);
1959*8ccd4a63SDavid du Colombier 	md5(sec->sec, MasterSecretSize, nil, &hsmd5);
1960*8ccd4a63SDavid du Colombier 	memset(pad, 0x36, 48);
1961*8ccd4a63SDavid du Colombier 	md5(pad, 48, nil, &hsmd5);
1962*8ccd4a63SDavid du Colombier 	md5(nil, 0, h0, &hsmd5);
1963*8ccd4a63SDavid du Colombier 	memset(pad, 0x5C, 48);
1964*8ccd4a63SDavid du Colombier 	s = md5(sec->sec, MasterSecretSize, nil, nil);
1965*8ccd4a63SDavid du Colombier 	s = md5(pad, 48, nil, s);
1966*8ccd4a63SDavid du Colombier 	md5(h0, MD5dlen, finished, s);
1967*8ccd4a63SDavid du Colombier 
1968*8ccd4a63SDavid du Colombier 	sha1((uchar*)label, 4, nil, &hssha1);
1969*8ccd4a63SDavid du Colombier 	sha1(sec->sec, MasterSecretSize, nil, &hssha1);
1970*8ccd4a63SDavid du Colombier 	memset(pad, 0x36, 40);
1971*8ccd4a63SDavid du Colombier 	sha1(pad, 40, nil, &hssha1);
1972*8ccd4a63SDavid du Colombier 	sha1(nil, 0, h1, &hssha1);
1973*8ccd4a63SDavid du Colombier 	memset(pad, 0x5C, 40);
1974*8ccd4a63SDavid du Colombier 	s = sha1(sec->sec, MasterSecretSize, nil, nil);
1975*8ccd4a63SDavid du Colombier 	s = sha1(pad, 40, nil, s);
1976*8ccd4a63SDavid du Colombier 	sha1(h1, SHA1dlen, finished + MD5dlen, s);
1977*8ccd4a63SDavid du Colombier }
1978*8ccd4a63SDavid du Colombier 
1979*8ccd4a63SDavid du Colombier // fill "finished" arg with md5(args)^sha1(args)
1980*8ccd4a63SDavid du Colombier static void
1981*8ccd4a63SDavid du Colombier tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
1982*8ccd4a63SDavid du Colombier {
1983*8ccd4a63SDavid du Colombier 	uchar h0[MD5dlen], h1[SHA1dlen];
1984*8ccd4a63SDavid du Colombier 	char *label;
1985*8ccd4a63SDavid du Colombier 
1986*8ccd4a63SDavid du Colombier 	// get current hash value, but allow further messages to be hashed in
1987*8ccd4a63SDavid du Colombier 	md5(nil, 0, h0, &hsmd5);
1988*8ccd4a63SDavid du Colombier 	sha1(nil, 0, h1, &hssha1);
1989*8ccd4a63SDavid du Colombier 
1990*8ccd4a63SDavid du Colombier 	if(isClient)
1991*8ccd4a63SDavid du Colombier 		label = "client finished";
1992*8ccd4a63SDavid du Colombier 	else
1993*8ccd4a63SDavid du Colombier 		label = "server finished";
1994*8ccd4a63SDavid du Colombier 	tlsPRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen);
1995*8ccd4a63SDavid du Colombier }
1996*8ccd4a63SDavid du Colombier 
1997*8ccd4a63SDavid du Colombier static void
1998*8ccd4a63SDavid du Colombier sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
1999*8ccd4a63SDavid du Colombier {
2000*8ccd4a63SDavid du Colombier 	DigestState *s;
2001*8ccd4a63SDavid du Colombier 	uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26];
2002*8ccd4a63SDavid du Colombier 	int i, n, len;
2003*8ccd4a63SDavid du Colombier 
2004*8ccd4a63SDavid du Colombier 	USED(label);
2005*8ccd4a63SDavid du Colombier 	len = 1;
2006*8ccd4a63SDavid du Colombier 	while(nbuf > 0){
2007*8ccd4a63SDavid du Colombier 		if(len > 26)
2008*8ccd4a63SDavid du Colombier 			return;
2009*8ccd4a63SDavid du Colombier 		for(i = 0; i < len; i++)
2010*8ccd4a63SDavid du Colombier 			tmp[i] = 'A' - 1 + len;
2011*8ccd4a63SDavid du Colombier 		s = sha1(tmp, len, nil, nil);
2012*8ccd4a63SDavid du Colombier 		s = sha1(key, nkey, nil, s);
2013*8ccd4a63SDavid du Colombier 		s = sha1(seed0, nseed0, nil, s);
2014*8ccd4a63SDavid du Colombier 		sha1(seed1, nseed1, sha1dig, s);
2015*8ccd4a63SDavid du Colombier 		s = md5(key, nkey, nil, nil);
2016*8ccd4a63SDavid du Colombier 		md5(sha1dig, SHA1dlen, md5dig, s);
2017*8ccd4a63SDavid du Colombier 		n = MD5dlen;
2018*8ccd4a63SDavid du Colombier 		if(n > nbuf)
2019*8ccd4a63SDavid du Colombier 			n = nbuf;
2020*8ccd4a63SDavid du Colombier 		memmove(buf, md5dig, n);
2021*8ccd4a63SDavid du Colombier 		buf += n;
2022*8ccd4a63SDavid du Colombier 		nbuf -= n;
2023*8ccd4a63SDavid du Colombier 		len++;
2024*8ccd4a63SDavid du Colombier 	}
2025*8ccd4a63SDavid du Colombier }
2026*8ccd4a63SDavid du Colombier 
2027*8ccd4a63SDavid du Colombier static mpint*
2028*8ccd4a63SDavid du Colombier bytestomp(Bytes* bytes)
2029*8ccd4a63SDavid du Colombier {
2030*8ccd4a63SDavid du Colombier 	mpint* ans;
2031*8ccd4a63SDavid du Colombier 
2032*8ccd4a63SDavid du Colombier 	ans = betomp(bytes->data, bytes->len, nil);
2033*8ccd4a63SDavid du Colombier 	return ans;
2034*8ccd4a63SDavid du Colombier }
2035*8ccd4a63SDavid du Colombier 
2036*8ccd4a63SDavid du Colombier /*
2037*8ccd4a63SDavid du Colombier  * Convert mpint* to Bytes, putting high order byte first.
2038*8ccd4a63SDavid du Colombier  */
2039*8ccd4a63SDavid du Colombier static Bytes*
2040*8ccd4a63SDavid du Colombier mptobytes(mpint* big)
2041*8ccd4a63SDavid du Colombier {
2042*8ccd4a63SDavid du Colombier 	int n, m;
2043*8ccd4a63SDavid du Colombier 	uchar *a;
2044*8ccd4a63SDavid du Colombier 	Bytes* ans;
2045*8ccd4a63SDavid du Colombier 
2046*8ccd4a63SDavid du Colombier 	n = (mpsignif(big)+7)/8;
2047*8ccd4a63SDavid du Colombier 	m = mptobe(big, nil, n, &a);
2048*8ccd4a63SDavid du Colombier 	ans = makebytes(a, m);
2049*8ccd4a63SDavid du Colombier 	return ans;
2050*8ccd4a63SDavid du Colombier }
2051*8ccd4a63SDavid du Colombier 
2052*8ccd4a63SDavid du Colombier // Do RSA computation on block according to key, and pad
2053*8ccd4a63SDavid du Colombier // result on left with zeros to make it modlen long.
2054*8ccd4a63SDavid du Colombier static Bytes*
2055*8ccd4a63SDavid du Colombier rsacomp(Bytes* block, RSApub* key, int modlen)
2056*8ccd4a63SDavid du Colombier {
2057*8ccd4a63SDavid du Colombier 	mpint *x, *y;
2058*8ccd4a63SDavid du Colombier 	Bytes *a, *ybytes;
2059*8ccd4a63SDavid du Colombier 	int ylen;
2060*8ccd4a63SDavid du Colombier 
2061*8ccd4a63SDavid du Colombier 	x = bytestomp(block);
2062*8ccd4a63SDavid du Colombier 	y = rsaencrypt(key, x, nil);
2063*8ccd4a63SDavid du Colombier 	mpfree(x);
2064*8ccd4a63SDavid du Colombier 	ybytes = mptobytes(y);
2065*8ccd4a63SDavid du Colombier 	ylen = ybytes->len;
2066*8ccd4a63SDavid du Colombier 
2067*8ccd4a63SDavid du Colombier 	if(ylen < modlen) {
2068*8ccd4a63SDavid du Colombier 		a = newbytes(modlen);
2069*8ccd4a63SDavid du Colombier 		memset(a->data, 0, modlen-ylen);
2070*8ccd4a63SDavid du Colombier 		memmove(a->data+modlen-ylen, ybytes->data, ylen);
2071*8ccd4a63SDavid du Colombier 		freebytes(ybytes);
2072*8ccd4a63SDavid du Colombier 		ybytes = a;
2073*8ccd4a63SDavid du Colombier 	}
2074*8ccd4a63SDavid du Colombier 	else if(ylen > modlen) {
2075*8ccd4a63SDavid du Colombier 		// assume it has leading zeros (mod should make it so)
2076*8ccd4a63SDavid du Colombier 		a = newbytes(modlen);
2077*8ccd4a63SDavid du Colombier 		memmove(a->data, ybytes->data, modlen);
2078*8ccd4a63SDavid du Colombier 		freebytes(ybytes);
2079*8ccd4a63SDavid du Colombier 		ybytes = a;
2080*8ccd4a63SDavid du Colombier 	}
2081*8ccd4a63SDavid du Colombier 	mpfree(y);
2082*8ccd4a63SDavid du Colombier 	return ybytes;
2083*8ccd4a63SDavid du Colombier }
2084*8ccd4a63SDavid du Colombier 
2085*8ccd4a63SDavid du Colombier // encrypt data according to PKCS#1, /lib/rfc/rfc2437 9.1.2.1
2086*8ccd4a63SDavid du Colombier static Bytes*
2087*8ccd4a63SDavid du Colombier pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype)
2088*8ccd4a63SDavid du Colombier {
2089*8ccd4a63SDavid du Colombier 	Bytes *pad, *eb, *ans;
2090*8ccd4a63SDavid du Colombier 	int i, dlen, padlen, modlen;
2091*8ccd4a63SDavid du Colombier 
2092*8ccd4a63SDavid du Colombier 	modlen = (mpsignif(key->n)+7)/8;
2093*8ccd4a63SDavid du Colombier 	dlen = data->len;
2094*8ccd4a63SDavid du Colombier 	if(modlen < 12 || dlen > modlen - 11)
2095*8ccd4a63SDavid du Colombier 		return nil;
2096*8ccd4a63SDavid du Colombier 	padlen = modlen - 3 - dlen;
2097*8ccd4a63SDavid du Colombier 	pad = newbytes(padlen);
2098*8ccd4a63SDavid du Colombier 	genrandom(pad->data, padlen);
2099*8ccd4a63SDavid du Colombier 	for(i = 0; i < padlen; i++) {
2100*8ccd4a63SDavid du Colombier 		if(blocktype == 0)
2101*8ccd4a63SDavid du Colombier 			pad->data[i] = 0;
2102*8ccd4a63SDavid du Colombier 		else if(blocktype == 1)
2103*8ccd4a63SDavid du Colombier 			pad->data[i] = 255;
2104*8ccd4a63SDavid du Colombier 		else if(pad->data[i] == 0)
2105*8ccd4a63SDavid du Colombier 			pad->data[i] = 1;
2106*8ccd4a63SDavid du Colombier 	}
2107*8ccd4a63SDavid du Colombier 	eb = newbytes(modlen);
2108*8ccd4a63SDavid du Colombier 	eb->data[0] = 0;
2109*8ccd4a63SDavid du Colombier 	eb->data[1] = blocktype;
2110*8ccd4a63SDavid du Colombier 	memmove(eb->data+2, pad->data, padlen);
2111*8ccd4a63SDavid du Colombier 	eb->data[padlen+2] = 0;
2112*8ccd4a63SDavid du Colombier 	memmove(eb->data+padlen+3, data->data, dlen);
2113*8ccd4a63SDavid du Colombier 	ans = rsacomp(eb, key, modlen);
2114*8ccd4a63SDavid du Colombier 	freebytes(eb);
2115*8ccd4a63SDavid du Colombier 	freebytes(pad);
2116*8ccd4a63SDavid du Colombier 	return ans;
2117*8ccd4a63SDavid du Colombier }
2118*8ccd4a63SDavid du Colombier 
2119*8ccd4a63SDavid du Colombier // decrypt data according to PKCS#1, with given key.
2120*8ccd4a63SDavid du Colombier // expect a block type of 2.
2121*8ccd4a63SDavid du Colombier static Bytes*
2122*8ccd4a63SDavid du Colombier pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm)
2123*8ccd4a63SDavid du Colombier {
2124*8ccd4a63SDavid du Colombier 	Bytes *eb, *ans = nil;
2125*8ccd4a63SDavid du Colombier 	int i, modlen;
2126*8ccd4a63SDavid du Colombier 	mpint *x, *y;
2127*8ccd4a63SDavid du Colombier 
2128*8ccd4a63SDavid du Colombier 	modlen = (mpsignif(sec->rsapub->n)+7)/8;
2129*8ccd4a63SDavid du Colombier 	if(nepm != modlen)
2130*8ccd4a63SDavid du Colombier 		return nil;
2131*8ccd4a63SDavid du Colombier 	x = betomp(epm, nepm, nil);
2132*8ccd4a63SDavid du Colombier 	y = factotum_rsa_decrypt(sec->rpc, x);
2133*8ccd4a63SDavid du Colombier 	if(y == nil)
2134*8ccd4a63SDavid du Colombier 		return nil;
2135*8ccd4a63SDavid du Colombier 	eb = mptobytes(y);
2136*8ccd4a63SDavid du Colombier 	if(eb->len < modlen){ // pad on left with zeros
2137*8ccd4a63SDavid du Colombier 		ans = newbytes(modlen);
2138*8ccd4a63SDavid du Colombier 		memset(ans->data, 0, modlen-eb->len);
2139*8ccd4a63SDavid du Colombier 		memmove(ans->data+modlen-eb->len, eb->data, eb->len);
2140*8ccd4a63SDavid du Colombier 		freebytes(eb);
2141*8ccd4a63SDavid du Colombier 		eb = ans;
2142*8ccd4a63SDavid du Colombier 	}
2143*8ccd4a63SDavid du Colombier 	if(eb->data[0] == 0 && eb->data[1] == 2) {
2144*8ccd4a63SDavid du Colombier 		for(i = 2; i < modlen; i++)
2145*8ccd4a63SDavid du Colombier 			if(eb->data[i] == 0)
2146*8ccd4a63SDavid du Colombier 				break;
2147*8ccd4a63SDavid du Colombier 		if(i < modlen - 1)
2148*8ccd4a63SDavid du Colombier 			ans = makebytes(eb->data+i+1, modlen-(i+1));
2149*8ccd4a63SDavid du Colombier 	}
2150*8ccd4a63SDavid du Colombier 	freebytes(eb);
2151*8ccd4a63SDavid du Colombier 	return ans;
2152*8ccd4a63SDavid du Colombier }
2153*8ccd4a63SDavid du Colombier 
2154*8ccd4a63SDavid du Colombier 
2155*8ccd4a63SDavid du Colombier //================= general utility functions ========================
2156*8ccd4a63SDavid du Colombier 
2157*8ccd4a63SDavid du Colombier static void *
2158*8ccd4a63SDavid du Colombier emalloc(int n)
2159*8ccd4a63SDavid du Colombier {
2160*8ccd4a63SDavid du Colombier 	void *p;
2161*8ccd4a63SDavid du Colombier 	if(n==0)
2162*8ccd4a63SDavid du Colombier 		n=1;
2163*8ccd4a63SDavid du Colombier 	p = malloc(n);
2164*8ccd4a63SDavid du Colombier 	if(p == nil){
2165*8ccd4a63SDavid du Colombier 		exits("out of memory");
2166*8ccd4a63SDavid du Colombier 	}
2167*8ccd4a63SDavid du Colombier 	memset(p, 0, n);
2168*8ccd4a63SDavid du Colombier 	return p;
2169*8ccd4a63SDavid du Colombier }
2170*8ccd4a63SDavid du Colombier 
2171*8ccd4a63SDavid du Colombier static void *
2172*8ccd4a63SDavid du Colombier erealloc(void *ReallocP, int ReallocN)
2173*8ccd4a63SDavid du Colombier {
2174*8ccd4a63SDavid du Colombier 	if(ReallocN == 0)
2175*8ccd4a63SDavid du Colombier 		ReallocN = 1;
2176*8ccd4a63SDavid du Colombier 	if(!ReallocP)
2177*8ccd4a63SDavid du Colombier 		ReallocP = emalloc(ReallocN);
2178*8ccd4a63SDavid du Colombier 	else if(!(ReallocP = realloc(ReallocP, ReallocN))){
2179*8ccd4a63SDavid du Colombier 		exits("out of memory");
2180*8ccd4a63SDavid du Colombier 	}
2181*8ccd4a63SDavid du Colombier 	return(ReallocP);
2182*8ccd4a63SDavid du Colombier }
2183*8ccd4a63SDavid du Colombier 
2184*8ccd4a63SDavid du Colombier static void
2185*8ccd4a63SDavid du Colombier put32(uchar *p, u32int x)
2186*8ccd4a63SDavid du Colombier {
2187*8ccd4a63SDavid du Colombier 	p[0] = x>>24;
2188*8ccd4a63SDavid du Colombier 	p[1] = x>>16;
2189*8ccd4a63SDavid du Colombier 	p[2] = x>>8;
2190*8ccd4a63SDavid du Colombier 	p[3] = x;
2191*8ccd4a63SDavid du Colombier }
2192*8ccd4a63SDavid du Colombier 
2193*8ccd4a63SDavid du Colombier static void
2194*8ccd4a63SDavid du Colombier put24(uchar *p, int x)
2195*8ccd4a63SDavid du Colombier {
2196*8ccd4a63SDavid du Colombier 	p[0] = x>>16;
2197*8ccd4a63SDavid du Colombier 	p[1] = x>>8;
2198*8ccd4a63SDavid du Colombier 	p[2] = x;
2199*8ccd4a63SDavid du Colombier }
2200*8ccd4a63SDavid du Colombier 
2201*8ccd4a63SDavid du Colombier static void
2202*8ccd4a63SDavid du Colombier put16(uchar *p, int x)
2203*8ccd4a63SDavid du Colombier {
2204*8ccd4a63SDavid du Colombier 	p[0] = x>>8;
2205*8ccd4a63SDavid du Colombier 	p[1] = x;
2206*8ccd4a63SDavid du Colombier }
2207*8ccd4a63SDavid du Colombier 
2208*8ccd4a63SDavid du Colombier static u32int
2209*8ccd4a63SDavid du Colombier get32(uchar *p)
2210*8ccd4a63SDavid du Colombier {
2211*8ccd4a63SDavid du Colombier 	return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
2212*8ccd4a63SDavid du Colombier }
2213*8ccd4a63SDavid du Colombier 
2214*8ccd4a63SDavid du Colombier static int
2215*8ccd4a63SDavid du Colombier get24(uchar *p)
2216*8ccd4a63SDavid du Colombier {
2217*8ccd4a63SDavid du Colombier 	return (p[0]<<16)|(p[1]<<8)|p[2];
2218*8ccd4a63SDavid du Colombier }
2219*8ccd4a63SDavid du Colombier 
2220*8ccd4a63SDavid du Colombier static int
2221*8ccd4a63SDavid du Colombier get16(uchar *p)
2222*8ccd4a63SDavid du Colombier {
2223*8ccd4a63SDavid du Colombier 	return (p[0]<<8)|p[1];
2224*8ccd4a63SDavid du Colombier }
2225*8ccd4a63SDavid du Colombier 
2226*8ccd4a63SDavid du Colombier /* ANSI offsetof() */
2227*8ccd4a63SDavid du Colombier #define OFFSET(x, s) ((int)(&(((s*)0)->x)))
2228*8ccd4a63SDavid du Colombier 
2229*8ccd4a63SDavid du Colombier /*
2230*8ccd4a63SDavid du Colombier  * malloc and return a new Bytes structure capable of
2231*8ccd4a63SDavid du Colombier  * holding len bytes. (len >= 0)
2232*8ccd4a63SDavid du Colombier  * Used to use crypt_malloc, which aborts if malloc fails.
2233*8ccd4a63SDavid du Colombier  */
2234*8ccd4a63SDavid du Colombier static Bytes*
2235*8ccd4a63SDavid du Colombier newbytes(int len)
2236*8ccd4a63SDavid du Colombier {
2237*8ccd4a63SDavid du Colombier 	Bytes* ans;
2238*8ccd4a63SDavid du Colombier 
2239*8ccd4a63SDavid du Colombier 	ans = (Bytes*)malloc(OFFSET(data[0], Bytes) + len);
2240*8ccd4a63SDavid du Colombier 	ans->len = len;
2241*8ccd4a63SDavid du Colombier 	return ans;
2242*8ccd4a63SDavid du Colombier }
2243*8ccd4a63SDavid du Colombier 
2244*8ccd4a63SDavid du Colombier /*
2245*8ccd4a63SDavid du Colombier  * newbytes(len), with data initialized from buf
2246*8ccd4a63SDavid du Colombier  */
2247*8ccd4a63SDavid du Colombier static Bytes*
2248*8ccd4a63SDavid du Colombier makebytes(uchar* buf, int len)
2249*8ccd4a63SDavid du Colombier {
2250*8ccd4a63SDavid du Colombier 	Bytes* ans;
2251*8ccd4a63SDavid du Colombier 
2252*8ccd4a63SDavid du Colombier 	ans = newbytes(len);
2253*8ccd4a63SDavid du Colombier 	memmove(ans->data, buf, len);
2254*8ccd4a63SDavid du Colombier 	return ans;
2255*8ccd4a63SDavid du Colombier }
2256*8ccd4a63SDavid du Colombier 
2257*8ccd4a63SDavid du Colombier static void
2258*8ccd4a63SDavid du Colombier freebytes(Bytes* b)
2259*8ccd4a63SDavid du Colombier {
2260*8ccd4a63SDavid du Colombier 	if(b != nil)
2261*8ccd4a63SDavid du Colombier 		free(b);
2262*8ccd4a63SDavid du Colombier }
2263*8ccd4a63SDavid du Colombier 
2264*8ccd4a63SDavid du Colombier /* len is number of ints */
2265*8ccd4a63SDavid du Colombier static Ints*
2266*8ccd4a63SDavid du Colombier newints(int len)
2267*8ccd4a63SDavid du Colombier {
2268*8ccd4a63SDavid du Colombier 	Ints* ans;
2269*8ccd4a63SDavid du Colombier 
2270*8ccd4a63SDavid du Colombier 	ans = (Ints*)malloc(OFFSET(data[0], Ints) + len*sizeof(int));
2271*8ccd4a63SDavid du Colombier 	ans->len = len;
2272*8ccd4a63SDavid du Colombier 	return ans;
2273*8ccd4a63SDavid du Colombier }
2274*8ccd4a63SDavid du Colombier 
2275*8ccd4a63SDavid du Colombier static Ints*
2276*8ccd4a63SDavid du Colombier makeints(int* buf, int len)
2277*8ccd4a63SDavid du Colombier {
2278*8ccd4a63SDavid du Colombier 	Ints* ans;
2279*8ccd4a63SDavid du Colombier 
2280*8ccd4a63SDavid du Colombier 	ans = newints(len);
2281*8ccd4a63SDavid du Colombier 	if(len > 0)
2282*8ccd4a63SDavid du Colombier 		memmove(ans->data, buf, len*sizeof(int));
2283*8ccd4a63SDavid du Colombier 	return ans;
2284*8ccd4a63SDavid du Colombier }
2285*8ccd4a63SDavid du Colombier 
2286*8ccd4a63SDavid du Colombier static void
2287*8ccd4a63SDavid du Colombier freeints(Ints* b)
2288*8ccd4a63SDavid du Colombier {
2289*8ccd4a63SDavid du Colombier 	if(b != nil)
2290*8ccd4a63SDavid du Colombier 		free(b);
2291*8ccd4a63SDavid du Colombier }
2292