xref: /plan9/sys/src/cmd/unix/drawterm/libsec/tlshand.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
18ccd4a63SDavid du Colombier #include <u.h>
28ccd4a63SDavid du Colombier #include <libc.h>
38ccd4a63SDavid du Colombier #include <bio.h>
48ccd4a63SDavid du Colombier #include <auth.h>
58ccd4a63SDavid du Colombier #include <mp.h>
68ccd4a63SDavid du Colombier #include <libsec.h>
78ccd4a63SDavid du Colombier 
88ccd4a63SDavid du Colombier // The main groups of functions are:
98ccd4a63SDavid du Colombier //		client/server - main handshake protocol definition
108ccd4a63SDavid du Colombier //		message functions - formating handshake messages
118ccd4a63SDavid du Colombier //		cipher choices - catalog of digest and encrypt algorithms
128ccd4a63SDavid du Colombier //		security functions - PKCS#1, sslHMAC, session keygen
138ccd4a63SDavid du Colombier //		general utility functions - malloc, serialization
148ccd4a63SDavid du Colombier // The handshake protocol builds on the TLS/SSL3 record layer protocol,
158ccd4a63SDavid du Colombier // which is implemented in kernel device #a.  See also /lib/rfc/rfc2246.
168ccd4a63SDavid du Colombier 
178ccd4a63SDavid du Colombier enum {
188ccd4a63SDavid du Colombier 	TLSFinishedLen = 12,
198ccd4a63SDavid du Colombier 	SSL3FinishedLen = MD5dlen+SHA1dlen,
208ccd4a63SDavid du Colombier 	MaxKeyData = 104,	// amount of secret we may need
218ccd4a63SDavid du Colombier 	MaxChunk = 1<<14,
228ccd4a63SDavid du Colombier 	RandomSize = 32,
238ccd4a63SDavid du Colombier 	SidSize = 32,
248ccd4a63SDavid du Colombier 	MasterSecretSize = 48,
258ccd4a63SDavid du Colombier 	AQueue = 0,
268ccd4a63SDavid du Colombier 	AFlush = 1,
278ccd4a63SDavid du Colombier };
288ccd4a63SDavid du Colombier 
298ccd4a63SDavid du Colombier typedef struct TlsSec TlsSec;
308ccd4a63SDavid du Colombier 
318ccd4a63SDavid du Colombier typedef struct Bytes{
328ccd4a63SDavid du Colombier 	int len;
338ccd4a63SDavid du Colombier 	uchar data[1];  // [len]
348ccd4a63SDavid du Colombier } Bytes;
358ccd4a63SDavid du Colombier 
368ccd4a63SDavid du Colombier typedef struct Ints{
378ccd4a63SDavid du Colombier 	int len;
388ccd4a63SDavid du Colombier 	int data[1];  // [len]
398ccd4a63SDavid du Colombier } Ints;
408ccd4a63SDavid du Colombier 
418ccd4a63SDavid du Colombier typedef struct Algs{
428ccd4a63SDavid du Colombier 	char *enc;
438ccd4a63SDavid du Colombier 	char *digest;
448ccd4a63SDavid du Colombier 	int nsecret;
458ccd4a63SDavid du Colombier 	int tlsid;
468ccd4a63SDavid du Colombier 	int ok;
478ccd4a63SDavid du Colombier } Algs;
488ccd4a63SDavid du Colombier 
498ccd4a63SDavid du Colombier typedef struct Finished{
508ccd4a63SDavid du Colombier 	uchar verify[SSL3FinishedLen];
518ccd4a63SDavid du Colombier 	int n;
528ccd4a63SDavid du Colombier } Finished;
538ccd4a63SDavid du Colombier 
548ccd4a63SDavid du Colombier typedef struct TlsConnection{
558ccd4a63SDavid du Colombier 	TlsSec *sec;	// security management goo
568ccd4a63SDavid du Colombier 	int hand, ctl;	// record layer file descriptors
578ccd4a63SDavid du Colombier 	int erred;		// set when tlsError called
588ccd4a63SDavid du Colombier 	int (*trace)(char*fmt, ...); // for debugging
598ccd4a63SDavid du Colombier 	int version;	// protocol we are speaking
608ccd4a63SDavid du Colombier 	int verset;		// version has been set
618ccd4a63SDavid du Colombier 	int ver2hi;		// server got a version 2 hello
628ccd4a63SDavid du Colombier 	int isClient;	// is this the client or server?
638ccd4a63SDavid du Colombier 	Bytes *sid;		// SessionID
648ccd4a63SDavid du Colombier 	Bytes *cert;	// only last - no chain
658ccd4a63SDavid du Colombier 
668ccd4a63SDavid du Colombier 	Lock statelk;
678ccd4a63SDavid du Colombier 	int state;		// must be set using setstate
688ccd4a63SDavid du Colombier 
698ccd4a63SDavid du Colombier 	// input buffer for handshake messages
708ccd4a63SDavid du Colombier 	uchar buf[MaxChunk+2048];
718ccd4a63SDavid du Colombier 	uchar *rp, *ep;
728ccd4a63SDavid du Colombier 
738ccd4a63SDavid du Colombier 	uchar crandom[RandomSize];	// client random
748ccd4a63SDavid du Colombier 	uchar srandom[RandomSize];	// server random
758ccd4a63SDavid du Colombier 	int clientVersion;	// version in ClientHello
768ccd4a63SDavid du Colombier 	char *digest;	// name of digest algorithm to use
778ccd4a63SDavid du Colombier 	char *enc;		// name of encryption algorithm to use
788ccd4a63SDavid du Colombier 	int nsecret;	// amount of secret data to init keys
798ccd4a63SDavid du Colombier 
808ccd4a63SDavid du Colombier 	// for finished messages
818ccd4a63SDavid du Colombier 	MD5state	hsmd5;	// handshake hash
828ccd4a63SDavid du Colombier 	SHAstate	hssha1;	// handshake hash
838ccd4a63SDavid du Colombier 	Finished	finished;
848ccd4a63SDavid du Colombier } TlsConnection;
858ccd4a63SDavid du Colombier 
868ccd4a63SDavid du Colombier typedef struct Msg{
878ccd4a63SDavid du Colombier 	int tag;
888ccd4a63SDavid du Colombier 	union {
898ccd4a63SDavid du Colombier 		struct {
908ccd4a63SDavid du Colombier 			int version;
918ccd4a63SDavid du Colombier 			uchar 	random[RandomSize];
928ccd4a63SDavid du Colombier 			Bytes*	sid;
938ccd4a63SDavid du Colombier 			Ints*	ciphers;
948ccd4a63SDavid du Colombier 			Bytes*	compressors;
958ccd4a63SDavid du Colombier 		} clientHello;
968ccd4a63SDavid du Colombier 		struct {
978ccd4a63SDavid du Colombier 			int version;
988ccd4a63SDavid du Colombier 			uchar 	random[RandomSize];
998ccd4a63SDavid du Colombier 			Bytes*	sid;
1008ccd4a63SDavid du Colombier 			int cipher;
1018ccd4a63SDavid du Colombier 			int compressor;
1028ccd4a63SDavid du Colombier 		} serverHello;
1038ccd4a63SDavid du Colombier 		struct {
1048ccd4a63SDavid du Colombier 			int ncert;
1058ccd4a63SDavid du Colombier 			Bytes **certs;
1068ccd4a63SDavid du Colombier 		} certificate;
1078ccd4a63SDavid du Colombier 		struct {
1088ccd4a63SDavid du Colombier 			Bytes *types;
1098ccd4a63SDavid du Colombier 			int nca;
1108ccd4a63SDavid du Colombier 			Bytes **cas;
1118ccd4a63SDavid du Colombier 		} certificateRequest;
1128ccd4a63SDavid du Colombier 		struct {
1138ccd4a63SDavid du Colombier 			Bytes *key;
1148ccd4a63SDavid du Colombier 		} clientKeyExchange;
1158ccd4a63SDavid du Colombier 		Finished finished;
1168ccd4a63SDavid du Colombier 	} u;
1178ccd4a63SDavid du Colombier } Msg;
1188ccd4a63SDavid du Colombier 
1198ccd4a63SDavid du Colombier typedef struct TlsSec{
1208ccd4a63SDavid du Colombier 	char *server;	// name of remote; nil for server
1218ccd4a63SDavid du Colombier 	int ok;	// <0 killed; ==0 in progress; >0 reusable
1228ccd4a63SDavid du Colombier 	RSApub *rsapub;
1238ccd4a63SDavid du Colombier 	AuthRpc *rpc;	// factotum for rsa private key
1248ccd4a63SDavid du Colombier 	uchar sec[MasterSecretSize];	// master secret
1258ccd4a63SDavid du Colombier 	uchar crandom[RandomSize];	// client random
1268ccd4a63SDavid du Colombier 	uchar srandom[RandomSize];	// server random
1278ccd4a63SDavid du Colombier 	int clientVers;		// version in ClientHello
1288ccd4a63SDavid du Colombier 	int vers;			// final version
1298ccd4a63SDavid du Colombier 	// byte generation and handshake checksum
1308ccd4a63SDavid du Colombier 	void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
1318ccd4a63SDavid du Colombier 	void (*setFinished)(TlsSec*, MD5state, SHAstate, uchar*, int);
1328ccd4a63SDavid du Colombier 	int nfin;
1338ccd4a63SDavid du Colombier } TlsSec;
1348ccd4a63SDavid du Colombier 
1358ccd4a63SDavid du Colombier 
1368ccd4a63SDavid du Colombier enum {
1378ccd4a63SDavid du Colombier 	TLSVersion = 0x0301,
1388ccd4a63SDavid du Colombier 	SSL3Version = 0x0300,
1398ccd4a63SDavid du Colombier 	ProtocolVersion = 0x0301,	// maximum version we speak
1408ccd4a63SDavid du Colombier 	MinProtoVersion = 0x0300,	// limits on version we accept
1418ccd4a63SDavid du Colombier 	MaxProtoVersion	= 0x03ff,
1428ccd4a63SDavid du Colombier };
1438ccd4a63SDavid du Colombier 
1448ccd4a63SDavid du Colombier // handshake type
1458ccd4a63SDavid du Colombier enum {
1468ccd4a63SDavid du Colombier 	HHelloRequest,
1478ccd4a63SDavid du Colombier 	HClientHello,
1488ccd4a63SDavid du Colombier 	HServerHello,
1498ccd4a63SDavid du Colombier 	HSSL2ClientHello = 9,  /* local convention;  see devtls.c */
1508ccd4a63SDavid du Colombier 	HCertificate = 11,
1518ccd4a63SDavid du Colombier 	HServerKeyExchange,
1528ccd4a63SDavid du Colombier 	HCertificateRequest,
1538ccd4a63SDavid du Colombier 	HServerHelloDone,
1548ccd4a63SDavid du Colombier 	HCertificateVerify,
1558ccd4a63SDavid du Colombier 	HClientKeyExchange,
1568ccd4a63SDavid du Colombier 	HFinished = 20,
1578ccd4a63SDavid du Colombier 	HMax
1588ccd4a63SDavid du Colombier };
1598ccd4a63SDavid du Colombier 
1608ccd4a63SDavid du Colombier // alerts
1618ccd4a63SDavid du Colombier enum {
1628ccd4a63SDavid du Colombier 	ECloseNotify = 0,
1638ccd4a63SDavid du Colombier 	EUnexpectedMessage = 10,
1648ccd4a63SDavid du Colombier 	EBadRecordMac = 20,
1658ccd4a63SDavid du Colombier 	EDecryptionFailed = 21,
1668ccd4a63SDavid du Colombier 	ERecordOverflow = 22,
1678ccd4a63SDavid du Colombier 	EDecompressionFailure = 30,
1688ccd4a63SDavid du Colombier 	EHandshakeFailure = 40,
1698ccd4a63SDavid du Colombier 	ENoCertificate = 41,
1708ccd4a63SDavid du Colombier 	EBadCertificate = 42,
1718ccd4a63SDavid du Colombier 	EUnsupportedCertificate = 43,
1728ccd4a63SDavid du Colombier 	ECertificateRevoked = 44,
1738ccd4a63SDavid du Colombier 	ECertificateExpired = 45,
1748ccd4a63SDavid du Colombier 	ECertificateUnknown = 46,
1758ccd4a63SDavid du Colombier 	EIllegalParameter = 47,
1768ccd4a63SDavid du Colombier 	EUnknownCa = 48,
1778ccd4a63SDavid du Colombier 	EAccessDenied = 49,
1788ccd4a63SDavid du Colombier 	EDecodeError = 50,
1798ccd4a63SDavid du Colombier 	EDecryptError = 51,
1808ccd4a63SDavid du Colombier 	EExportRestriction = 60,
1818ccd4a63SDavid du Colombier 	EProtocolVersion = 70,
1828ccd4a63SDavid du Colombier 	EInsufficientSecurity = 71,
1838ccd4a63SDavid du Colombier 	EInternalError = 80,
1848ccd4a63SDavid du Colombier 	EUserCanceled = 90,
1858ccd4a63SDavid du Colombier 	ENoRenegotiation = 100,
1868ccd4a63SDavid du Colombier 	EMax = 256
1878ccd4a63SDavid du Colombier };
1888ccd4a63SDavid du Colombier 
1898ccd4a63SDavid du Colombier // cipher suites
1908ccd4a63SDavid du Colombier enum {
1918ccd4a63SDavid du Colombier 	TLS_NULL_WITH_NULL_NULL	 		= 0x0000,
1928ccd4a63SDavid du Colombier 	TLS_RSA_WITH_NULL_MD5 			= 0x0001,
1938ccd4a63SDavid du Colombier 	TLS_RSA_WITH_NULL_SHA 			= 0x0002,
1948ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_RC4_40_MD5 		= 0x0003,
1958ccd4a63SDavid du Colombier 	TLS_RSA_WITH_RC4_128_MD5 		= 0x0004,
1968ccd4a63SDavid du Colombier 	TLS_RSA_WITH_RC4_128_SHA 		= 0x0005,
1978ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	= 0X0006,
1988ccd4a63SDavid du Colombier 	TLS_RSA_WITH_IDEA_CBC_SHA 		= 0X0007,
1998ccd4a63SDavid du Colombier 	TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0008,
2008ccd4a63SDavid du Colombier 	TLS_RSA_WITH_DES_CBC_SHA		= 0X0009,
2018ccd4a63SDavid du Colombier 	TLS_RSA_WITH_3DES_EDE_CBC_SHA		= 0X000A,
2028ccd4a63SDavid du Colombier 	TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X000B,
2038ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_DES_CBC_SHA		= 0X000C,
2048ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	= 0X000D,
2058ccd4a63SDavid du Colombier 	TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X000E,
2068ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_DES_CBC_SHA		= 0X000F,
2078ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0010,
2088ccd4a63SDavid du Colombier 	TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X0011,
2098ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_DES_CBC_SHA		= 0X0012,
2108ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	= 0X0013,	// ZZZ must be implemented for tls1.0 compliance
2118ccd4a63SDavid du Colombier 	TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0014,
2128ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_DES_CBC_SHA		= 0X0015,
2138ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0016,
2148ccd4a63SDavid du Colombier 	TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	= 0x0017,
2158ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_RC4_128_MD5 		= 0x0018,
2168ccd4a63SDavid du Colombier 	TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	= 0X0019,
2178ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_DES_CBC_SHA		= 0X001A,
2188ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	= 0X001B,
2198ccd4a63SDavid du Colombier 
2208ccd4a63SDavid du Colombier 	TLS_RSA_WITH_AES_128_CBC_SHA		= 0X002f,	// aes, aka rijndael with 128 bit blocks
2218ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_AES_128_CBC_SHA		= 0X0030,
2228ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_AES_128_CBC_SHA		= 0X0031,
2238ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_AES_128_CBC_SHA	= 0X0032,
2248ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_AES_128_CBC_SHA	= 0X0033,
2258ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_AES_128_CBC_SHA	= 0X0034,
2268ccd4a63SDavid du Colombier 	TLS_RSA_WITH_AES_256_CBC_SHA		= 0X0035,
2278ccd4a63SDavid du Colombier 	TLS_DH_DSS_WITH_AES_256_CBC_SHA		= 0X0036,
2288ccd4a63SDavid du Colombier 	TLS_DH_RSA_WITH_AES_256_CBC_SHA		= 0X0037,
2298ccd4a63SDavid du Colombier 	TLS_DHE_DSS_WITH_AES_256_CBC_SHA	= 0X0038,
2308ccd4a63SDavid du Colombier 	TLS_DHE_RSA_WITH_AES_256_CBC_SHA	= 0X0039,
2318ccd4a63SDavid du Colombier 	TLS_DH_anon_WITH_AES_256_CBC_SHA	= 0X003A,
2328ccd4a63SDavid du Colombier 	CipherMax
2338ccd4a63SDavid du Colombier };
2348ccd4a63SDavid du Colombier 
2358ccd4a63SDavid du Colombier // compression methods
2368ccd4a63SDavid du Colombier enum {
2378ccd4a63SDavid du Colombier 	CompressionNull = 0,
2388ccd4a63SDavid du Colombier 	CompressionMax
2398ccd4a63SDavid du Colombier };
2408ccd4a63SDavid du Colombier 
2418ccd4a63SDavid du Colombier static Algs cipherAlgs[] = {
2428ccd4a63SDavid du Colombier 	{"rc4_128", "md5",	2 * (16 + MD5dlen), TLS_RSA_WITH_RC4_128_MD5},
2438ccd4a63SDavid du Colombier 	{"rc4_128", "sha1",	2 * (16 + SHA1dlen), TLS_RSA_WITH_RC4_128_SHA},
2448ccd4a63SDavid du Colombier 	{"3des_ede_cbc","sha1",2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},
2458ccd4a63SDavid du Colombier };
2468ccd4a63SDavid du Colombier 
2478ccd4a63SDavid du Colombier static uchar compressors[] = {
2488ccd4a63SDavid du Colombier 	CompressionNull,
2498ccd4a63SDavid du Colombier };
2508ccd4a63SDavid du Colombier 
2518ccd4a63SDavid du Colombier static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...));
2528ccd4a63SDavid du Colombier static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...));
2538ccd4a63SDavid du Colombier 
2548ccd4a63SDavid du Colombier static void	msgClear(Msg *m);
2558ccd4a63SDavid du Colombier static char* msgPrint(char *buf, int n, Msg *m);
2568ccd4a63SDavid du Colombier static int	msgRecv(TlsConnection *c, Msg *m);
2578ccd4a63SDavid du Colombier static int	msgSend(TlsConnection *c, Msg *m, int act);
2588ccd4a63SDavid du Colombier static void	tlsError(TlsConnection *c, int err, char *msg, ...);
2598ccd4a63SDavid du Colombier #pragma	varargck argpos	tlsError 3
2608ccd4a63SDavid du Colombier static int setVersion(TlsConnection *c, int version);
2618ccd4a63SDavid du Colombier static int finishedMatch(TlsConnection *c, Finished *f);
2628ccd4a63SDavid du Colombier static void tlsConnectionFree(TlsConnection *c);
2638ccd4a63SDavid du Colombier 
2648ccd4a63SDavid du Colombier static int setAlgs(TlsConnection *c, int a);
2658ccd4a63SDavid du Colombier static int okCipher(Ints *cv);
2668ccd4a63SDavid du Colombier static int okCompression(Bytes *cv);
2678ccd4a63SDavid du Colombier static int initCiphers(void);
2688ccd4a63SDavid du Colombier static Ints* makeciphers(void);
2698ccd4a63SDavid du Colombier 
2708ccd4a63SDavid du Colombier static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom);
2718ccd4a63SDavid du Colombier static int	tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd);
2728ccd4a63SDavid du Colombier static TlsSec*	tlsSecInitc(int cvers, uchar *crandom);
2738ccd4a63SDavid 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);
2748ccd4a63SDavid du Colombier static int	tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient);
2758ccd4a63SDavid du Colombier static void	tlsSecOk(TlsSec *sec);
2768ccd4a63SDavid du Colombier static void	tlsSecKill(TlsSec *sec);
2778ccd4a63SDavid du Colombier static void	tlsSecClose(TlsSec *sec);
2788ccd4a63SDavid du Colombier static void	setMasterSecret(TlsSec *sec, Bytes *pm);
2798ccd4a63SDavid du Colombier static void	serverMasterSecret(TlsSec *sec, uchar *epm, int nepm);
2808ccd4a63SDavid du Colombier static void	setSecrets(TlsSec *sec, uchar *kd, int nkd);
2818ccd4a63SDavid du Colombier static int	clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm);
2828ccd4a63SDavid du Colombier static Bytes *pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);
2838ccd4a63SDavid du Colombier static Bytes *pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm);
2848ccd4a63SDavid du Colombier static void	tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
2858ccd4a63SDavid du Colombier static void	sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
2868ccd4a63SDavid du Colombier static void	sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label,
2878ccd4a63SDavid du Colombier 			uchar *seed0, int nseed0, uchar *seed1, int nseed1);
2888ccd4a63SDavid du Colombier static int setVers(TlsSec *sec, int version);
2898ccd4a63SDavid du Colombier 
2908ccd4a63SDavid du Colombier static AuthRpc* factotum_rsa_open(uchar *cert, int certlen);
2918ccd4a63SDavid du Colombier static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);
2928ccd4a63SDavid du Colombier static void factotum_rsa_close(AuthRpc*rpc);
2938ccd4a63SDavid du Colombier 
2948ccd4a63SDavid du Colombier static void* emalloc(int);
2958ccd4a63SDavid du Colombier static void* erealloc(void*, int);
2968ccd4a63SDavid du Colombier static void put32(uchar *p, u32int);
2978ccd4a63SDavid du Colombier static void put24(uchar *p, int);
2988ccd4a63SDavid du Colombier static void put16(uchar *p, int);
2998ccd4a63SDavid du Colombier static u32int get32(uchar *p);
3008ccd4a63SDavid du Colombier static int get24(uchar *p);
3018ccd4a63SDavid du Colombier static int get16(uchar *p);
3028ccd4a63SDavid du Colombier static Bytes* newbytes(int len);
3038ccd4a63SDavid du Colombier static Bytes* makebytes(uchar* buf, int len);
3048ccd4a63SDavid du Colombier static void freebytes(Bytes* b);
3058ccd4a63SDavid du Colombier static Ints* newints(int len);
3068ccd4a63SDavid du Colombier static Ints* makeints(int* buf, int len);
3078ccd4a63SDavid du Colombier static void freeints(Ints* b);
3088ccd4a63SDavid du Colombier 
3098ccd4a63SDavid du Colombier //================= client/server ========================
3108ccd4a63SDavid du Colombier 
3118ccd4a63SDavid du Colombier //	push TLS onto fd, returning new (application) file descriptor
3128ccd4a63SDavid du Colombier //		or -1 if error.
3138ccd4a63SDavid du Colombier int
tlsServer(int fd,TLSconn * conn)3148ccd4a63SDavid du Colombier tlsServer(int fd, TLSconn *conn)
3158ccd4a63SDavid du Colombier {
3168ccd4a63SDavid du Colombier 	char buf[8];
3178ccd4a63SDavid du Colombier 	char dname[64];
3188ccd4a63SDavid du Colombier 	int n, data, ctl, hand;
3198ccd4a63SDavid du Colombier 	TlsConnection *tls;
3208ccd4a63SDavid du Colombier 
3218ccd4a63SDavid du Colombier 	if(conn == nil)
3228ccd4a63SDavid du Colombier 		return -1;
3238ccd4a63SDavid du Colombier 	ctl = open("#a/tls/clone", ORDWR);
3248ccd4a63SDavid du Colombier 	if(ctl < 0)
3258ccd4a63SDavid du Colombier 		return -1;
3268ccd4a63SDavid du Colombier 	n = read(ctl, buf, sizeof(buf)-1);
3278ccd4a63SDavid du Colombier 	if(n < 0){
3288ccd4a63SDavid du Colombier 		close(ctl);
3298ccd4a63SDavid du Colombier 		return -1;
3308ccd4a63SDavid du Colombier 	}
3318ccd4a63SDavid du Colombier 	buf[n] = 0;
3328ccd4a63SDavid du Colombier 	sprint(conn->dir, "#a/tls/%s", buf);
3338ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/hand", buf);
3348ccd4a63SDavid du Colombier 	hand = open(dname, ORDWR);
3358ccd4a63SDavid du Colombier 	if(hand < 0){
3368ccd4a63SDavid du Colombier 		close(ctl);
3378ccd4a63SDavid du Colombier 		return -1;
3388ccd4a63SDavid du Colombier 	}
3398ccd4a63SDavid du Colombier 	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
3408ccd4a63SDavid du Colombier 	tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace);
3418ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/data", buf);
3428ccd4a63SDavid du Colombier 	data = open(dname, ORDWR);
3438ccd4a63SDavid du Colombier 	close(fd);
3448ccd4a63SDavid du Colombier 	close(hand);
3458ccd4a63SDavid du Colombier 	close(ctl);
3468ccd4a63SDavid du Colombier 	if(data < 0){
3478ccd4a63SDavid du Colombier 		return -1;
3488ccd4a63SDavid du Colombier 	}
3498ccd4a63SDavid du Colombier 	if(tls == nil){
3508ccd4a63SDavid du Colombier 		close(data);
3518ccd4a63SDavid du Colombier 		return -1;
3528ccd4a63SDavid du Colombier 	}
3538ccd4a63SDavid du Colombier 	if(conn->cert)
3548ccd4a63SDavid du Colombier 		free(conn->cert);
3558ccd4a63SDavid du Colombier 	conn->cert = 0;  // client certificates are not yet implemented
3568ccd4a63SDavid du Colombier 	conn->certlen = 0;
3578ccd4a63SDavid du Colombier 	conn->sessionIDlen = tls->sid->len;
3588ccd4a63SDavid du Colombier 	conn->sessionID = emalloc(conn->sessionIDlen);
3598ccd4a63SDavid du Colombier 	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
3608ccd4a63SDavid du Colombier 	tlsConnectionFree(tls);
3618ccd4a63SDavid du Colombier 	return data;
3628ccd4a63SDavid du Colombier }
3638ccd4a63SDavid du Colombier 
3648ccd4a63SDavid du Colombier //	push TLS onto fd, returning new (application) file descriptor
3658ccd4a63SDavid du Colombier //		or -1 if error.
3668ccd4a63SDavid du Colombier int
tlsClient(int fd,TLSconn * conn)3678ccd4a63SDavid du Colombier tlsClient(int fd, TLSconn *conn)
3688ccd4a63SDavid du Colombier {
3698ccd4a63SDavid du Colombier 	char buf[8];
3708ccd4a63SDavid du Colombier 	char dname[64];
3718ccd4a63SDavid du Colombier 	int n, data, ctl, hand;
3728ccd4a63SDavid du Colombier 	TlsConnection *tls;
3738ccd4a63SDavid du Colombier 
3748ccd4a63SDavid du Colombier 	if(!conn)
3758ccd4a63SDavid du Colombier 		return -1;
3768ccd4a63SDavid du Colombier 	ctl = open("#a/tls/clone", ORDWR);
3778ccd4a63SDavid du Colombier 	if(ctl < 0)
3788ccd4a63SDavid du Colombier 		return -1;
3798ccd4a63SDavid du Colombier 	n = read(ctl, buf, sizeof(buf)-1);
3808ccd4a63SDavid du Colombier 	if(n < 0){
3818ccd4a63SDavid du Colombier 		close(ctl);
3828ccd4a63SDavid du Colombier 		return -1;
3838ccd4a63SDavid du Colombier 	}
3848ccd4a63SDavid du Colombier 	buf[n] = 0;
3858ccd4a63SDavid du Colombier 	sprint(conn->dir, "#a/tls/%s", buf);
3868ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/hand", buf);
3878ccd4a63SDavid du Colombier 	hand = open(dname, ORDWR);
3888ccd4a63SDavid du Colombier 	if(hand < 0){
3898ccd4a63SDavid du Colombier 		close(ctl);
3908ccd4a63SDavid du Colombier 		return -1;
3918ccd4a63SDavid du Colombier 	}
3928ccd4a63SDavid du Colombier 	sprint(dname, "#a/tls/%s/data", buf);
3938ccd4a63SDavid du Colombier 	data = open(dname, ORDWR);
3948ccd4a63SDavid du Colombier 	if(data < 0)
3958ccd4a63SDavid du Colombier 		return -1;
3968ccd4a63SDavid du Colombier 	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
3978ccd4a63SDavid du Colombier 	tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace);
3988ccd4a63SDavid du Colombier 	close(fd);
3998ccd4a63SDavid du Colombier 	close(hand);
4008ccd4a63SDavid du Colombier 	close(ctl);
4018ccd4a63SDavid du Colombier 	if(tls == nil){
4028ccd4a63SDavid du Colombier 		close(data);
4038ccd4a63SDavid du Colombier 		return -1;
4048ccd4a63SDavid du Colombier 	}
4058ccd4a63SDavid du Colombier 	conn->certlen = tls->cert->len;
4068ccd4a63SDavid du Colombier 	conn->cert = emalloc(conn->certlen);
4078ccd4a63SDavid du Colombier 	memcpy(conn->cert, tls->cert->data, conn->certlen);
4088ccd4a63SDavid du Colombier 	conn->sessionIDlen = tls->sid->len;
4098ccd4a63SDavid du Colombier 	conn->sessionID = emalloc(conn->sessionIDlen);
4108ccd4a63SDavid du Colombier 	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
4118ccd4a63SDavid du Colombier 	tlsConnectionFree(tls);
4128ccd4a63SDavid du Colombier 	return data;
4138ccd4a63SDavid du Colombier }
4148ccd4a63SDavid du Colombier 
4158ccd4a63SDavid du Colombier static TlsConnection *
tlsServer2(int ctl,int hand,uchar * cert,int ncert,int (* trace)(char * fmt,...))4168ccd4a63SDavid du Colombier tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...))
4178ccd4a63SDavid du Colombier {
4188ccd4a63SDavid du Colombier 	TlsConnection *c;
4198ccd4a63SDavid du Colombier 	Msg m;
4208ccd4a63SDavid du Colombier 	Bytes *csid;
4218ccd4a63SDavid du Colombier 	uchar sid[SidSize], kd[MaxKeyData];
4228ccd4a63SDavid du Colombier 	char *secrets;
4238ccd4a63SDavid du Colombier 	int cipher, compressor, nsid, rv;
4248ccd4a63SDavid du Colombier 
4258ccd4a63SDavid du Colombier 	if(trace)
4268ccd4a63SDavid du Colombier 		trace("tlsServer2\n");
4278ccd4a63SDavid du Colombier 	if(!initCiphers())
4288ccd4a63SDavid du Colombier 		return nil;
4298ccd4a63SDavid du Colombier 	c = emalloc(sizeof(TlsConnection));
4308ccd4a63SDavid du Colombier 	c->ctl = ctl;
4318ccd4a63SDavid du Colombier 	c->hand = hand;
4328ccd4a63SDavid du Colombier 	c->trace = trace;
4338ccd4a63SDavid du Colombier 	c->version = ProtocolVersion;
4348ccd4a63SDavid du Colombier 
4358ccd4a63SDavid du Colombier 	memset(&m, 0, sizeof(m));
4368ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m)){
4378ccd4a63SDavid du Colombier 		if(trace)
4388ccd4a63SDavid du Colombier 			trace("initial msgRecv failed\n");
4398ccd4a63SDavid du Colombier 		goto Err;
4408ccd4a63SDavid du Colombier 	}
4418ccd4a63SDavid du Colombier 	if(m.tag != HClientHello) {
4428ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a client hello");
4438ccd4a63SDavid du Colombier 		goto Err;
4448ccd4a63SDavid du Colombier 	}
4458ccd4a63SDavid du Colombier 	c->clientVersion = m.u.clientHello.version;
4468ccd4a63SDavid du Colombier 	if(trace)
4478ccd4a63SDavid du Colombier 		trace("ClientHello version %x\n", c->clientVersion);
4488ccd4a63SDavid du Colombier 	if(setVersion(c, m.u.clientHello.version) < 0) {
4498ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "incompatible version");
4508ccd4a63SDavid du Colombier 		goto Err;
4518ccd4a63SDavid du Colombier 	}
4528ccd4a63SDavid du Colombier 
4538ccd4a63SDavid du Colombier 	memmove(c->crandom, m.u.clientHello.random, RandomSize);
4548ccd4a63SDavid du Colombier 	cipher = okCipher(m.u.clientHello.ciphers);
4558ccd4a63SDavid du Colombier 	if(cipher < 0) {
4568ccd4a63SDavid du Colombier 		// reply with EInsufficientSecurity if we know that's the case
4578ccd4a63SDavid du Colombier 		if(cipher == -2)
4588ccd4a63SDavid du Colombier 			tlsError(c, EInsufficientSecurity, "cipher suites too weak");
4598ccd4a63SDavid du Colombier 		else
4608ccd4a63SDavid du Colombier 			tlsError(c, EHandshakeFailure, "no matching cipher suite");
4618ccd4a63SDavid du Colombier 		goto Err;
4628ccd4a63SDavid du Colombier 	}
4638ccd4a63SDavid du Colombier 	if(!setAlgs(c, cipher)){
4648ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "no matching cipher suite");
4658ccd4a63SDavid du Colombier 		goto Err;
4668ccd4a63SDavid du Colombier 	}
4678ccd4a63SDavid du Colombier 	compressor = okCompression(m.u.clientHello.compressors);
4688ccd4a63SDavid du Colombier 	if(compressor < 0) {
4698ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "no matching compressor");
4708ccd4a63SDavid du Colombier 		goto Err;
4718ccd4a63SDavid du Colombier 	}
4728ccd4a63SDavid du Colombier 
4738ccd4a63SDavid du Colombier 	csid = m.u.clientHello.sid;
4748ccd4a63SDavid du Colombier 	if(trace)
4758ccd4a63SDavid du Colombier 		trace("  cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len);
4768ccd4a63SDavid du Colombier 	c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom);
4778ccd4a63SDavid du Colombier 	if(c->sec == nil){
4788ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't initialize security: %r");
4798ccd4a63SDavid du Colombier 		goto Err;
4808ccd4a63SDavid du Colombier 	}
4818ccd4a63SDavid du Colombier 	c->sec->rpc = factotum_rsa_open(cert, ncert);
4828ccd4a63SDavid du Colombier 	if(c->sec->rpc == nil){
4838ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
4848ccd4a63SDavid du Colombier 		goto Err;
4858ccd4a63SDavid du Colombier 	}
4868ccd4a63SDavid du Colombier 	c->sec->rsapub = X509toRSApub(cert, ncert, nil, 0);
4878ccd4a63SDavid du Colombier 	msgClear(&m);
4888ccd4a63SDavid du Colombier 
4898ccd4a63SDavid du Colombier 	m.tag = HServerHello;
4908ccd4a63SDavid du Colombier 	m.u.serverHello.version = c->version;
4918ccd4a63SDavid du Colombier 	memmove(m.u.serverHello.random, c->srandom, RandomSize);
4928ccd4a63SDavid du Colombier 	m.u.serverHello.cipher = cipher;
4938ccd4a63SDavid du Colombier 	m.u.serverHello.compressor = compressor;
4948ccd4a63SDavid du Colombier 	c->sid = makebytes(sid, nsid);
4958ccd4a63SDavid du Colombier 	m.u.serverHello.sid = makebytes(c->sid->data, c->sid->len);
4968ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AQueue))
4978ccd4a63SDavid du Colombier 		goto Err;
4988ccd4a63SDavid du Colombier 	msgClear(&m);
4998ccd4a63SDavid du Colombier 
5008ccd4a63SDavid du Colombier 	m.tag = HCertificate;
5018ccd4a63SDavid du Colombier 	m.u.certificate.ncert = 1;
5028ccd4a63SDavid du Colombier 	m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes));
5038ccd4a63SDavid du Colombier 	m.u.certificate.certs[0] = makebytes(cert, ncert);
5048ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AQueue))
5058ccd4a63SDavid du Colombier 		goto Err;
5068ccd4a63SDavid du Colombier 	msgClear(&m);
5078ccd4a63SDavid du Colombier 
5088ccd4a63SDavid du Colombier 	m.tag = HServerHelloDone;
5098ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
5108ccd4a63SDavid du Colombier 		goto Err;
5118ccd4a63SDavid du Colombier 	msgClear(&m);
5128ccd4a63SDavid du Colombier 
5138ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
5148ccd4a63SDavid du Colombier 		goto Err;
5158ccd4a63SDavid du Colombier 	if(m.tag != HClientKeyExchange) {
5168ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a client key exchange");
5178ccd4a63SDavid du Colombier 		goto Err;
5188ccd4a63SDavid du Colombier 	}
5198ccd4a63SDavid du Colombier 	if(tlsSecSecrets(c->sec, c->version, m.u.clientKeyExchange.key->data, m.u.clientKeyExchange.key->len, kd, c->nsecret) < 0){
5208ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
5218ccd4a63SDavid du Colombier 		goto Err;
5228ccd4a63SDavid du Colombier 	}
5238ccd4a63SDavid du Colombier 	if(trace)
5248ccd4a63SDavid du Colombier 		trace("tls secrets\n");
5258ccd4a63SDavid du Colombier 	secrets = (char*)emalloc(2*c->nsecret);
5268ccd4a63SDavid du Colombier 	enc64(secrets, 2*c->nsecret, kd, c->nsecret);
5278ccd4a63SDavid du Colombier 	rv = fprint(c->ctl, "secret %s %s 0 %s", c->digest, c->enc, secrets);
5288ccd4a63SDavid du Colombier 	memset(secrets, 0, 2*c->nsecret);
5298ccd4a63SDavid du Colombier 	free(secrets);
5308ccd4a63SDavid du Colombier 	memset(kd, 0, c->nsecret);
5318ccd4a63SDavid du Colombier 	if(rv < 0){
5328ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set keys: %r");
5338ccd4a63SDavid du Colombier 		goto Err;
5348ccd4a63SDavid du Colombier 	}
5358ccd4a63SDavid du Colombier 	msgClear(&m);
5368ccd4a63SDavid du Colombier 
5378ccd4a63SDavid du Colombier 	/* no CertificateVerify; skip to Finished */
5388ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
5398ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished: %r");
5408ccd4a63SDavid du Colombier 		goto Err;
5418ccd4a63SDavid du Colombier 	}
5428ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
5438ccd4a63SDavid du Colombier 		goto Err;
5448ccd4a63SDavid du Colombier 	if(m.tag != HFinished) {
5458ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a finished");
5468ccd4a63SDavid du Colombier 		goto Err;
5478ccd4a63SDavid du Colombier 	}
5488ccd4a63SDavid du Colombier 	if(!finishedMatch(c, &m.u.finished)) {
5498ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "finished verification failed");
5508ccd4a63SDavid du Colombier 		goto Err;
5518ccd4a63SDavid du Colombier 	}
5528ccd4a63SDavid du Colombier 	msgClear(&m);
5538ccd4a63SDavid du Colombier 
5548ccd4a63SDavid du Colombier 	/* change cipher spec */
5558ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "changecipher") < 0){
5568ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't enable cipher: %r");
5578ccd4a63SDavid du Colombier 		goto Err;
5588ccd4a63SDavid du Colombier 	}
5598ccd4a63SDavid du Colombier 
5608ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
5618ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished: %r");
5628ccd4a63SDavid du Colombier 		goto Err;
5638ccd4a63SDavid du Colombier 	}
5648ccd4a63SDavid du Colombier 	m.tag = HFinished;
5658ccd4a63SDavid du Colombier 	m.u.finished = c->finished;
5668ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
5678ccd4a63SDavid du Colombier 		goto Err;
5688ccd4a63SDavid du Colombier 	msgClear(&m);
5698ccd4a63SDavid du Colombier 	if(trace)
5708ccd4a63SDavid du Colombier 		trace("tls finished\n");
5718ccd4a63SDavid du Colombier 
5728ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "opened") < 0)
5738ccd4a63SDavid du Colombier 		goto Err;
5748ccd4a63SDavid du Colombier 	tlsSecOk(c->sec);
5758ccd4a63SDavid du Colombier 	return c;
5768ccd4a63SDavid du Colombier 
5778ccd4a63SDavid du Colombier Err:
5788ccd4a63SDavid du Colombier 	msgClear(&m);
5798ccd4a63SDavid du Colombier 	tlsConnectionFree(c);
5808ccd4a63SDavid du Colombier 	return 0;
5818ccd4a63SDavid du Colombier }
5828ccd4a63SDavid du Colombier 
5838ccd4a63SDavid du Colombier static TlsConnection *
tlsClient2(int ctl,int hand,uchar * csid,int ncsid,int (* trace)(char * fmt,...))5848ccd4a63SDavid du Colombier tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...))
5858ccd4a63SDavid du Colombier {
5868ccd4a63SDavid du Colombier 	TlsConnection *c;
5878ccd4a63SDavid du Colombier 	Msg m;
5888ccd4a63SDavid du Colombier 	uchar kd[MaxKeyData], *epm;
5898ccd4a63SDavid du Colombier 	char *secrets;
5908ccd4a63SDavid du Colombier 	int creq, nepm, rv;
5918ccd4a63SDavid du Colombier 
5928ccd4a63SDavid du Colombier 	if(!initCiphers())
5938ccd4a63SDavid du Colombier 		return nil;
5948ccd4a63SDavid du Colombier 	epm = nil;
5958ccd4a63SDavid du Colombier 	c = emalloc(sizeof(TlsConnection));
5968ccd4a63SDavid du Colombier 	c->version = ProtocolVersion;
5978ccd4a63SDavid du Colombier 	c->ctl = ctl;
5988ccd4a63SDavid du Colombier 	c->hand = hand;
5998ccd4a63SDavid du Colombier 	c->trace = trace;
6008ccd4a63SDavid du Colombier 	c->isClient = 1;
6018ccd4a63SDavid du Colombier 	c->clientVersion = c->version;
6028ccd4a63SDavid du Colombier 
6038ccd4a63SDavid du Colombier 	c->sec = tlsSecInitc(c->clientVersion, c->crandom);
6048ccd4a63SDavid du Colombier 	if(c->sec == nil)
6058ccd4a63SDavid du Colombier 		goto Err;
6068ccd4a63SDavid du Colombier 
6078ccd4a63SDavid du Colombier 	/* client hello */
6088ccd4a63SDavid du Colombier 	memset(&m, 0, sizeof(m));
6098ccd4a63SDavid du Colombier 	m.tag = HClientHello;
6108ccd4a63SDavid du Colombier 	m.u.clientHello.version = c->clientVersion;
6118ccd4a63SDavid du Colombier 	memmove(m.u.clientHello.random, c->crandom, RandomSize);
6128ccd4a63SDavid du Colombier 	m.u.clientHello.sid = makebytes(csid, ncsid);
6138ccd4a63SDavid du Colombier 	m.u.clientHello.ciphers = makeciphers();
6148ccd4a63SDavid du Colombier 	m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors));
6158ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
6168ccd4a63SDavid du Colombier 		goto Err;
6178ccd4a63SDavid du Colombier 	msgClear(&m);
6188ccd4a63SDavid du Colombier 
6198ccd4a63SDavid du Colombier 	/* server hello */
6208ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
6218ccd4a63SDavid du Colombier 		goto Err;
6228ccd4a63SDavid du Colombier 	if(m.tag != HServerHello) {
6238ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a server hello");
6248ccd4a63SDavid du Colombier 		goto Err;
6258ccd4a63SDavid du Colombier 	}
6268ccd4a63SDavid du Colombier 	if(setVersion(c, m.u.serverHello.version) < 0) {
6278ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "incompatible version %r");
6288ccd4a63SDavid du Colombier 		goto Err;
6298ccd4a63SDavid du Colombier 	}
6308ccd4a63SDavid du Colombier 	memmove(c->srandom, m.u.serverHello.random, RandomSize);
6318ccd4a63SDavid du Colombier 	c->sid = makebytes(m.u.serverHello.sid->data, m.u.serverHello.sid->len);
6328ccd4a63SDavid du Colombier 	if(c->sid->len != 0 && c->sid->len != SidSize) {
6338ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid server session identifier");
6348ccd4a63SDavid du Colombier 		goto Err;
6358ccd4a63SDavid du Colombier 	}
6368ccd4a63SDavid du Colombier 	if(!setAlgs(c, m.u.serverHello.cipher)) {
6378ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid cipher suite");
6388ccd4a63SDavid du Colombier 		goto Err;
6398ccd4a63SDavid du Colombier 	}
6408ccd4a63SDavid du Colombier 	if(m.u.serverHello.compressor != CompressionNull) {
6418ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "invalid compression");
6428ccd4a63SDavid du Colombier 		goto Err;
6438ccd4a63SDavid du Colombier 	}
6448ccd4a63SDavid du Colombier 	msgClear(&m);
6458ccd4a63SDavid du Colombier 
6468ccd4a63SDavid du Colombier 	/* certificate */
6478ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m) || m.tag != HCertificate) {
6488ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a certificate");
6498ccd4a63SDavid du Colombier 		goto Err;
6508ccd4a63SDavid du Colombier 	}
6518ccd4a63SDavid du Colombier 	if(m.u.certificate.ncert < 1) {
6528ccd4a63SDavid du Colombier 		tlsError(c, EIllegalParameter, "runt certificate");
6538ccd4a63SDavid du Colombier 		goto Err;
6548ccd4a63SDavid du Colombier 	}
6558ccd4a63SDavid du Colombier 	c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
6568ccd4a63SDavid du Colombier 	msgClear(&m);
6578ccd4a63SDavid du Colombier 
6588ccd4a63SDavid du Colombier 	/* server key exchange (optional) */
6598ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m))
6608ccd4a63SDavid du Colombier 		goto Err;
6618ccd4a63SDavid du Colombier 	if(m.tag == HServerKeyExchange) {
6628ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "got an server key exchange");
6638ccd4a63SDavid du Colombier 		goto Err;
6648ccd4a63SDavid du Colombier 		// If implementing this later, watch out for rollback attack
6658ccd4a63SDavid du Colombier 		// described in Wagner Schneier 1996, section 4.4.
6668ccd4a63SDavid du Colombier 	}
6678ccd4a63SDavid du Colombier 
6688ccd4a63SDavid du Colombier 	/* certificate request (optional) */
6698ccd4a63SDavid du Colombier 	creq = 0;
6708ccd4a63SDavid du Colombier 	if(m.tag == HCertificateRequest) {
6718ccd4a63SDavid du Colombier 		creq = 1;
6728ccd4a63SDavid du Colombier 		msgClear(&m);
6738ccd4a63SDavid du Colombier 		if(!msgRecv(c, &m))
6748ccd4a63SDavid du Colombier 			goto Err;
6758ccd4a63SDavid du Colombier 	}
6768ccd4a63SDavid du Colombier 
6778ccd4a63SDavid du Colombier 	if(m.tag != HServerHelloDone) {
6788ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a server hello done");
6798ccd4a63SDavid du Colombier 		goto Err;
6808ccd4a63SDavid du Colombier 	}
6818ccd4a63SDavid du Colombier 	msgClear(&m);
6828ccd4a63SDavid du Colombier 
6838ccd4a63SDavid du Colombier 	if(tlsSecSecretc(c->sec, c->sid->data, c->sid->len, c->srandom,
6848ccd4a63SDavid du Colombier 			c->cert->data, c->cert->len, c->version, &epm, &nepm,
6858ccd4a63SDavid du Colombier 			kd, c->nsecret) < 0){
6868ccd4a63SDavid du Colombier 		tlsError(c, EBadCertificate, "invalid x509/rsa certificate");
6878ccd4a63SDavid du Colombier 		goto Err;
6888ccd4a63SDavid du Colombier 	}
6898ccd4a63SDavid du Colombier 	secrets = (char*)emalloc(2*c->nsecret);
6908ccd4a63SDavid du Colombier 	enc64(secrets, 2*c->nsecret, kd, c->nsecret);
6918ccd4a63SDavid du Colombier 	rv = fprint(c->ctl, "secret %s %s 1 %s", c->digest, c->enc, secrets);
6928ccd4a63SDavid du Colombier 	memset(secrets, 0, 2*c->nsecret);
6938ccd4a63SDavid du Colombier 	free(secrets);
6948ccd4a63SDavid du Colombier 	memset(kd, 0, c->nsecret);
6958ccd4a63SDavid du Colombier 	if(rv < 0){
6968ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set keys: %r");
6978ccd4a63SDavid du Colombier 		goto Err;
6988ccd4a63SDavid du Colombier 	}
6998ccd4a63SDavid du Colombier 
7008ccd4a63SDavid du Colombier 	if(creq) {
7018ccd4a63SDavid du Colombier 		/* send a zero length certificate */
7028ccd4a63SDavid du Colombier 		m.tag = HCertificate;
7038ccd4a63SDavid du Colombier 		if(!msgSend(c, &m, AFlush))
7048ccd4a63SDavid du Colombier 			goto Err;
7058ccd4a63SDavid du Colombier 		msgClear(&m);
7068ccd4a63SDavid du Colombier 	}
7078ccd4a63SDavid du Colombier 
7088ccd4a63SDavid du Colombier 	/* client key exchange */
7098ccd4a63SDavid du Colombier 	m.tag = HClientKeyExchange;
7108ccd4a63SDavid du Colombier 	m.u.clientKeyExchange.key = makebytes(epm, nepm);
7118ccd4a63SDavid du Colombier 	free(epm);
7128ccd4a63SDavid du Colombier 	epm = nil;
7138ccd4a63SDavid du Colombier 	if(m.u.clientKeyExchange.key == nil) {
7148ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "can't set secret: %r");
7158ccd4a63SDavid du Colombier 		goto Err;
7168ccd4a63SDavid du Colombier 	}
7178ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush))
7188ccd4a63SDavid du Colombier 		goto Err;
7198ccd4a63SDavid du Colombier 	msgClear(&m);
7208ccd4a63SDavid du Colombier 
7218ccd4a63SDavid du Colombier 	/* change cipher spec */
7228ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "changecipher") < 0){
7238ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't enable cipher: %r");
7248ccd4a63SDavid du Colombier 		goto Err;
7258ccd4a63SDavid du Colombier 	}
7268ccd4a63SDavid du Colombier 
7278ccd4a63SDavid du Colombier 	// Cipherchange must occur immediately before Finished to avoid
7288ccd4a63SDavid du Colombier 	// potential hole;  see section 4.3 of Wagner Schneier 1996.
7298ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
7308ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished 1: %r");
7318ccd4a63SDavid du Colombier 		goto Err;
7328ccd4a63SDavid du Colombier 	}
7338ccd4a63SDavid du Colombier 	m.tag = HFinished;
7348ccd4a63SDavid du Colombier 	m.u.finished = c->finished;
7358ccd4a63SDavid du Colombier 
7368ccd4a63SDavid du Colombier 	if(!msgSend(c, &m, AFlush)) {
7378ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
7388ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't flush after client Finished: %r");
7398ccd4a63SDavid du Colombier 		goto Err;
7408ccd4a63SDavid du Colombier 	}
7418ccd4a63SDavid du Colombier 	msgClear(&m);
7428ccd4a63SDavid du Colombier 
7438ccd4a63SDavid du Colombier 	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
7448ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
7458ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't set finished 0: %r");
7468ccd4a63SDavid du Colombier 		goto Err;
7478ccd4a63SDavid du Colombier 	}
7488ccd4a63SDavid du Colombier 	if(!msgRecv(c, &m)) {
7498ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
7508ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't read server Finished: %r");
7518ccd4a63SDavid du Colombier 		goto Err;
7528ccd4a63SDavid du Colombier 	}
7538ccd4a63SDavid du Colombier 	if(m.tag != HFinished) {
7548ccd4a63SDavid du Colombier 		fprint(2, "tlsClient nepm=%d\n", nepm);
7558ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "expected a Finished msg from server");
7568ccd4a63SDavid du Colombier 		goto Err;
7578ccd4a63SDavid du Colombier 	}
7588ccd4a63SDavid du Colombier 
7598ccd4a63SDavid du Colombier 	if(!finishedMatch(c, &m.u.finished)) {
7608ccd4a63SDavid du Colombier 		tlsError(c, EHandshakeFailure, "finished verification failed");
7618ccd4a63SDavid du Colombier 		goto Err;
7628ccd4a63SDavid du Colombier 	}
7638ccd4a63SDavid du Colombier 	msgClear(&m);
7648ccd4a63SDavid du Colombier 
7658ccd4a63SDavid du Colombier 	if(fprint(c->ctl, "opened") < 0){
7668ccd4a63SDavid du Colombier 		if(trace)
7678ccd4a63SDavid du Colombier 			trace("unable to do final open: %r\n");
7688ccd4a63SDavid du Colombier 		goto Err;
7698ccd4a63SDavid du Colombier 	}
7708ccd4a63SDavid du Colombier 	tlsSecOk(c->sec);
7718ccd4a63SDavid du Colombier 	return c;
7728ccd4a63SDavid du Colombier 
7738ccd4a63SDavid du Colombier Err:
7748ccd4a63SDavid du Colombier 	free(epm);
7758ccd4a63SDavid du Colombier 	msgClear(&m);
7768ccd4a63SDavid du Colombier 	tlsConnectionFree(c);
7778ccd4a63SDavid du Colombier 	return 0;
7788ccd4a63SDavid du Colombier }
7798ccd4a63SDavid du Colombier 
7808ccd4a63SDavid du Colombier 
7818ccd4a63SDavid du Colombier //================= message functions ========================
7828ccd4a63SDavid du Colombier 
7838ccd4a63SDavid du Colombier static uchar sendbuf[9000], *sendp;
7848ccd4a63SDavid du Colombier 
7858ccd4a63SDavid du Colombier static int
msgSend(TlsConnection * c,Msg * m,int act)7868ccd4a63SDavid du Colombier msgSend(TlsConnection *c, Msg *m, int act)
7878ccd4a63SDavid du Colombier {
7888ccd4a63SDavid du Colombier 	uchar *p; // sendp = start of new message;  p = write pointer
7898ccd4a63SDavid du Colombier 	int nn, n, i;
7908ccd4a63SDavid du Colombier 
7918ccd4a63SDavid du Colombier 	if(sendp == nil)
7928ccd4a63SDavid du Colombier 		sendp = sendbuf;
7938ccd4a63SDavid du Colombier 	p = sendp;
7948ccd4a63SDavid du Colombier 	if(c->trace)
7958ccd4a63SDavid du Colombier 		c->trace("send %s", msgPrint((char*)p, (sizeof sendbuf) - (p-sendbuf), m));
7968ccd4a63SDavid du Colombier 
7978ccd4a63SDavid du Colombier 	p[0] = m->tag;	// header - fill in size later
7988ccd4a63SDavid du Colombier 	p += 4;
7998ccd4a63SDavid du Colombier 
8008ccd4a63SDavid du Colombier 	switch(m->tag) {
8018ccd4a63SDavid du Colombier 	default:
8028ccd4a63SDavid du Colombier 		tlsError(c, EInternalError, "can't encode a %d", m->tag);
8038ccd4a63SDavid du Colombier 		goto Err;
8048ccd4a63SDavid du Colombier 	case HClientHello:
8058ccd4a63SDavid du Colombier 		// version
8068ccd4a63SDavid du Colombier 		put16(p, m->u.clientHello.version);
8078ccd4a63SDavid du Colombier 		p += 2;
8088ccd4a63SDavid du Colombier 
8098ccd4a63SDavid du Colombier 		// random
8108ccd4a63SDavid du Colombier 		memmove(p, m->u.clientHello.random, RandomSize);
8118ccd4a63SDavid du Colombier 		p += RandomSize;
8128ccd4a63SDavid du Colombier 
8138ccd4a63SDavid du Colombier 		// sid
8148ccd4a63SDavid du Colombier 		n = m->u.clientHello.sid->len;
8158ccd4a63SDavid du Colombier 		assert(n < 256);
8168ccd4a63SDavid du Colombier 		p[0] = n;
8178ccd4a63SDavid du Colombier 		memmove(p+1, m->u.clientHello.sid->data, n);
8188ccd4a63SDavid du Colombier 		p += n+1;
8198ccd4a63SDavid du Colombier 
8208ccd4a63SDavid du Colombier 		n = m->u.clientHello.ciphers->len;
8218ccd4a63SDavid du Colombier 		assert(n > 0 && n < 200);
8228ccd4a63SDavid du Colombier 		put16(p, n*2);
8238ccd4a63SDavid du Colombier 		p += 2;
8248ccd4a63SDavid du Colombier 		for(i=0; i<n; i++) {
8258ccd4a63SDavid du Colombier 			put16(p, m->u.clientHello.ciphers->data[i]);
8268ccd4a63SDavid du Colombier 			p += 2;
8278ccd4a63SDavid du Colombier 		}
8288ccd4a63SDavid du Colombier 
8298ccd4a63SDavid du Colombier 		n = m->u.clientHello.compressors->len;
8308ccd4a63SDavid du Colombier 		assert(n > 0);
8318ccd4a63SDavid du Colombier 		p[0] = n;
8328ccd4a63SDavid du Colombier 		memmove(p+1, m->u.clientHello.compressors->data, n);
8338ccd4a63SDavid du Colombier 		p += n+1;
8348ccd4a63SDavid du Colombier 		break;
8358ccd4a63SDavid du Colombier 	case HServerHello:
8368ccd4a63SDavid du Colombier 		put16(p, m->u.serverHello.version);
8378ccd4a63SDavid du Colombier 		p += 2;
8388ccd4a63SDavid du Colombier 
8398ccd4a63SDavid du Colombier 		// random
8408ccd4a63SDavid du Colombier 		memmove(p, m->u.serverHello.random, RandomSize);
8418ccd4a63SDavid du Colombier 		p += RandomSize;
8428ccd4a63SDavid du Colombier 
8438ccd4a63SDavid du Colombier 		// sid
8448ccd4a63SDavid du Colombier 		n = m->u.serverHello.sid->len;
8458ccd4a63SDavid du Colombier 		assert(n < 256);
8468ccd4a63SDavid du Colombier 		p[0] = n;
8478ccd4a63SDavid du Colombier 		memmove(p+1, m->u.serverHello.sid->data, n);
8488ccd4a63SDavid du Colombier 		p += n+1;
8498ccd4a63SDavid du Colombier 
8508ccd4a63SDavid du Colombier 		put16(p, m->u.serverHello.cipher);
8518ccd4a63SDavid du Colombier 		p += 2;
8528ccd4a63SDavid du Colombier 		p[0] = m->u.serverHello.compressor;
8538ccd4a63SDavid du Colombier 		p += 1;
8548ccd4a63SDavid du Colombier 		break;
8558ccd4a63SDavid du Colombier 	case HServerHelloDone:
8568ccd4a63SDavid du Colombier 		break;
8578ccd4a63SDavid du Colombier 	case HCertificate:
8588ccd4a63SDavid du Colombier 		nn = 0;
8598ccd4a63SDavid du Colombier 		for(i = 0; i < m->u.certificate.ncert; i++)
8608ccd4a63SDavid du Colombier 			nn += 3 + m->u.certificate.certs[i]->len;
8618ccd4a63SDavid du Colombier 		if(p + 3 + nn - sendbuf > sizeof(sendbuf)) {
8628ccd4a63SDavid du Colombier 			tlsError(c, EInternalError, "output buffer too small for certificate");
8638ccd4a63SDavid du Colombier 			goto Err;
8648ccd4a63SDavid du Colombier 		}
8658ccd4a63SDavid du Colombier 		put24(p, nn);
8668ccd4a63SDavid du Colombier 		p += 3;
8678ccd4a63SDavid du Colombier 		for(i = 0; i < m->u.certificate.ncert; i++){
8688ccd4a63SDavid du Colombier 			put24(p, m->u.certificate.certs[i]->len);
8698ccd4a63SDavid du Colombier 			p += 3;
8708ccd4a63SDavid du Colombier 			memmove(p, m->u.certificate.certs[i]->data, m->u.certificate.certs[i]->len);
8718ccd4a63SDavid du Colombier 			p += m->u.certificate.certs[i]->len;
8728ccd4a63SDavid du Colombier 		}
8738ccd4a63SDavid du Colombier 		break;
8748ccd4a63SDavid du Colombier 	case HClientKeyExchange:
8758ccd4a63SDavid du Colombier 		n = m->u.clientKeyExchange.key->len;
8768ccd4a63SDavid du Colombier 		if(c->version != SSL3Version){
8778ccd4a63SDavid du Colombier 			put16(p, n);
8788ccd4a63SDavid du Colombier 			p += 2;
8798ccd4a63SDavid du Colombier 		}
8808ccd4a63SDavid du Colombier 		memmove(p, m->u.clientKeyExchange.key->data, n);
8818ccd4a63SDavid du Colombier 		p += n;
8828ccd4a63SDavid du Colombier 		break;
8838ccd4a63SDavid du Colombier 	case HFinished:
8848ccd4a63SDavid du Colombier 		memmove(p, m->u.finished.verify, m->u.finished.n);
8858ccd4a63SDavid du Colombier 		p += m->u.finished.n;
8868ccd4a63SDavid du Colombier 		break;
8878ccd4a63SDavid du Colombier 	}
8888ccd4a63SDavid du Colombier 
8898ccd4a63SDavid du Colombier 	// go back and fill in size
8908ccd4a63SDavid du Colombier 	n = p-sendp;
8918ccd4a63SDavid du Colombier 	assert(p <= sendbuf+sizeof(sendbuf));
8928ccd4a63SDavid du Colombier 	put24(sendp+1, n-4);
8938ccd4a63SDavid du Colombier 
8948ccd4a63SDavid du Colombier 	// remember hash of Handshake messages
8958ccd4a63SDavid du Colombier 	if(m->tag != HHelloRequest) {
8968ccd4a63SDavid du Colombier 		md5(sendp, n, 0, &c->hsmd5);
8978ccd4a63SDavid du Colombier 		sha1(sendp, n, 0, &c->hssha1);
8988ccd4a63SDavid du Colombier 	}
8998ccd4a63SDavid du Colombier 
9008ccd4a63SDavid du Colombier 	sendp = p;
9018ccd4a63SDavid du Colombier 	if(act == AFlush){
9028ccd4a63SDavid du Colombier 		sendp = sendbuf;
9038ccd4a63SDavid du Colombier 		if(write(c->hand, sendbuf, p-sendbuf) < 0){
9048ccd4a63SDavid du Colombier 			fprint(2, "write error: %r\n");
9058ccd4a63SDavid du Colombier 			goto Err;
9068ccd4a63SDavid du Colombier 		}
9078ccd4a63SDavid du Colombier 	}
9088ccd4a63SDavid du Colombier 	msgClear(m);
9098ccd4a63SDavid du Colombier 	return 1;
9108ccd4a63SDavid du Colombier Err:
9118ccd4a63SDavid du Colombier 	msgClear(m);
9128ccd4a63SDavid du Colombier 	return 0;
9138ccd4a63SDavid du Colombier }
9148ccd4a63SDavid du Colombier 
9158ccd4a63SDavid du Colombier static uchar*
tlsReadN(TlsConnection * c,int n)9168ccd4a63SDavid du Colombier tlsReadN(TlsConnection *c, int n)
9178ccd4a63SDavid du Colombier {
9188ccd4a63SDavid du Colombier 	uchar *p;
9198ccd4a63SDavid du Colombier 	int nn, nr;
9208ccd4a63SDavid du Colombier 
9218ccd4a63SDavid du Colombier 	nn = c->ep - c->rp;
9228ccd4a63SDavid du Colombier 	if(nn < n){
9238ccd4a63SDavid du Colombier 		if(c->rp != c->buf){
9248ccd4a63SDavid du Colombier 			memmove(c->buf, c->rp, nn);
9258ccd4a63SDavid du Colombier 			c->rp = c->buf;
9268ccd4a63SDavid du Colombier 			c->ep = &c->buf[nn];
9278ccd4a63SDavid du Colombier 		}
9288ccd4a63SDavid du Colombier 		for(; nn < n; nn += nr) {
9298ccd4a63SDavid du Colombier 			nr = read(c->hand, &c->rp[nn], n - nn);
9308ccd4a63SDavid du Colombier 			if(nr <= 0)
9318ccd4a63SDavid du Colombier 				return nil;
9328ccd4a63SDavid du Colombier 			c->ep += nr;
9338ccd4a63SDavid du Colombier 		}
9348ccd4a63SDavid du Colombier 	}
9358ccd4a63SDavid du Colombier 	p = c->rp;
9368ccd4a63SDavid du Colombier 	c->rp += n;
9378ccd4a63SDavid du Colombier 	return p;
9388ccd4a63SDavid du Colombier }
9398ccd4a63SDavid du Colombier 
9408ccd4a63SDavid du Colombier static int
msgRecv(TlsConnection * c,Msg * m)9418ccd4a63SDavid du Colombier msgRecv(TlsConnection *c, Msg *m)
9428ccd4a63SDavid du Colombier {
9438ccd4a63SDavid du Colombier 	uchar *p;
9448ccd4a63SDavid du Colombier 	int type, n, nn, i, nsid, nrandom, nciph;
9458ccd4a63SDavid du Colombier 
9468ccd4a63SDavid du Colombier 	for(;;) {
9478ccd4a63SDavid du Colombier 		p = tlsReadN(c, 4);
9488ccd4a63SDavid du Colombier 		if(p == nil)
9498ccd4a63SDavid du Colombier 			return 0;
9508ccd4a63SDavid du Colombier 		type = p[0];
9518ccd4a63SDavid du Colombier 		n = get24(p+1);
9528ccd4a63SDavid du Colombier 
9538ccd4a63SDavid du Colombier 		if(type != HHelloRequest)
9548ccd4a63SDavid du Colombier 			break;
9558ccd4a63SDavid du Colombier 		if(n != 0) {
9568ccd4a63SDavid du Colombier 			tlsError(c, EDecodeError, "invalid hello request during handshake");
9578ccd4a63SDavid du Colombier 			return 0;
9588ccd4a63SDavid du Colombier 		}
9598ccd4a63SDavid du Colombier 	}
9608ccd4a63SDavid du Colombier 
9618ccd4a63SDavid du Colombier 	if(n > sizeof(c->buf)) {
9628ccd4a63SDavid du Colombier 		tlsError(c, EDecodeError, "handshake message too long %d %d", n, sizeof(c->buf));
9638ccd4a63SDavid du Colombier 		return 0;
9648ccd4a63SDavid du Colombier 	}
9658ccd4a63SDavid du Colombier 
9668ccd4a63SDavid du Colombier 	if(type == HSSL2ClientHello){
9678ccd4a63SDavid du Colombier 		/* Cope with an SSL3 ClientHello expressed in SSL2 record format.
9688ccd4a63SDavid du Colombier 			This is sent by some clients that we must interoperate
9698ccd4a63SDavid du Colombier 			with, such as Java's JSSE and Microsoft's Internet Explorer. */
9708ccd4a63SDavid du Colombier 		p = tlsReadN(c, n);
9718ccd4a63SDavid du Colombier 		if(p == nil)
9728ccd4a63SDavid du Colombier 			return 0;
9738ccd4a63SDavid du Colombier 		md5(p, n, 0, &c->hsmd5);
9748ccd4a63SDavid du Colombier 		sha1(p, n, 0, &c->hssha1);
9758ccd4a63SDavid du Colombier 		m->tag = HClientHello;
9768ccd4a63SDavid du Colombier 		if(n < 22)
9778ccd4a63SDavid du Colombier 			goto Short;
9788ccd4a63SDavid du Colombier 		m->u.clientHello.version = get16(p+1);
9798ccd4a63SDavid du Colombier 		p += 3;
9808ccd4a63SDavid du Colombier 		n -= 3;
9818ccd4a63SDavid du Colombier 		nn = get16(p); /* cipher_spec_len */
9828ccd4a63SDavid du Colombier 		nsid = get16(p + 2);
9838ccd4a63SDavid du Colombier 		nrandom = get16(p + 4);
9848ccd4a63SDavid du Colombier 		p += 6;
9858ccd4a63SDavid du Colombier 		n -= 6;
9868ccd4a63SDavid du Colombier 		if(nsid != 0 	/* no sid's, since shouldn't restart using ssl2 header */
9878ccd4a63SDavid du Colombier 				|| nrandom < 16 || nn % 3)
9888ccd4a63SDavid du Colombier 			goto Err;
9898ccd4a63SDavid du Colombier 		if(c->trace && (n - nrandom != nn))
9908ccd4a63SDavid du Colombier 			c->trace("n-nrandom!=nn: n=%d nrandom=%d nn=%d\n", n, nrandom, nn);
9918ccd4a63SDavid du Colombier 		/* ignore ssl2 ciphers and look for {0x00, ssl3 cipher} */
9928ccd4a63SDavid du Colombier 		nciph = 0;
9938ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 3)
9948ccd4a63SDavid du Colombier 			if(p[i] == 0)
9958ccd4a63SDavid du Colombier 				nciph++;
9968ccd4a63SDavid du Colombier 		m->u.clientHello.ciphers = newints(nciph);
9978ccd4a63SDavid du Colombier 		nciph = 0;
9988ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 3)
9998ccd4a63SDavid du Colombier 			if(p[i] == 0)
10008ccd4a63SDavid du Colombier 				m->u.clientHello.ciphers->data[nciph++] = get16(&p[i + 1]);
10018ccd4a63SDavid du Colombier 		p += nn;
10028ccd4a63SDavid du Colombier 		m->u.clientHello.sid = makebytes(nil, 0);
10038ccd4a63SDavid du Colombier 		if(nrandom > RandomSize)
10048ccd4a63SDavid du Colombier 			nrandom = RandomSize;
10058ccd4a63SDavid du Colombier 		memset(m->u.clientHello.random, 0, RandomSize - nrandom);
10068ccd4a63SDavid du Colombier 		memmove(&m->u.clientHello.random[RandomSize - nrandom], p, nrandom);
10078ccd4a63SDavid du Colombier 		m->u.clientHello.compressors = newbytes(1);
10088ccd4a63SDavid du Colombier 		m->u.clientHello.compressors->data[0] = CompressionNull;
10098ccd4a63SDavid du Colombier 		goto Ok;
10108ccd4a63SDavid du Colombier 	}
10118ccd4a63SDavid du Colombier 
10128ccd4a63SDavid du Colombier 	md5(p, 4, 0, &c->hsmd5);
10138ccd4a63SDavid du Colombier 	sha1(p, 4, 0, &c->hssha1);
10148ccd4a63SDavid du Colombier 
10158ccd4a63SDavid du Colombier 	p = tlsReadN(c, n);
10168ccd4a63SDavid du Colombier 	if(p == nil)
10178ccd4a63SDavid du Colombier 		return 0;
10188ccd4a63SDavid du Colombier 
10198ccd4a63SDavid du Colombier 	md5(p, n, 0, &c->hsmd5);
10208ccd4a63SDavid du Colombier 	sha1(p, n, 0, &c->hssha1);
10218ccd4a63SDavid du Colombier 
10228ccd4a63SDavid du Colombier 	m->tag = type;
10238ccd4a63SDavid du Colombier 
10248ccd4a63SDavid du Colombier 	switch(type) {
10258ccd4a63SDavid du Colombier 	default:
10268ccd4a63SDavid du Colombier 		tlsError(c, EUnexpectedMessage, "can't decode a %d", type);
10278ccd4a63SDavid du Colombier 		goto Err;
10288ccd4a63SDavid du Colombier 	case HClientHello:
10298ccd4a63SDavid du Colombier 		if(n < 2)
10308ccd4a63SDavid du Colombier 			goto Short;
10318ccd4a63SDavid du Colombier 		m->u.clientHello.version = get16(p);
10328ccd4a63SDavid du Colombier 		p += 2;
10338ccd4a63SDavid du Colombier 		n -= 2;
10348ccd4a63SDavid du Colombier 
10358ccd4a63SDavid du Colombier 		if(n < RandomSize)
10368ccd4a63SDavid du Colombier 			goto Short;
10378ccd4a63SDavid du Colombier 		memmove(m->u.clientHello.random, p, RandomSize);
10388ccd4a63SDavid du Colombier 		p += RandomSize;
10398ccd4a63SDavid du Colombier 		n -= RandomSize;
10408ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1)
10418ccd4a63SDavid du Colombier 			goto Short;
10428ccd4a63SDavid du Colombier 		m->u.clientHello.sid = makebytes(p+1, p[0]);
10438ccd4a63SDavid du Colombier 		p += m->u.clientHello.sid->len+1;
10448ccd4a63SDavid du Colombier 		n -= m->u.clientHello.sid->len+1;
10458ccd4a63SDavid du Colombier 
10468ccd4a63SDavid du Colombier 		if(n < 2)
10478ccd4a63SDavid du Colombier 			goto Short;
10488ccd4a63SDavid du Colombier 		nn = get16(p);
10498ccd4a63SDavid du Colombier 		p += 2;
10508ccd4a63SDavid du Colombier 		n -= 2;
10518ccd4a63SDavid du Colombier 
10528ccd4a63SDavid du Colombier 		if((nn & 1) || n < nn || nn < 2)
10538ccd4a63SDavid du Colombier 			goto Short;
10548ccd4a63SDavid du Colombier 		m->u.clientHello.ciphers = newints(nn >> 1);
10558ccd4a63SDavid du Colombier 		for(i = 0; i < nn; i += 2)
10568ccd4a63SDavid du Colombier 			m->u.clientHello.ciphers->data[i >> 1] = get16(&p[i]);
10578ccd4a63SDavid du Colombier 		p += nn;
10588ccd4a63SDavid du Colombier 		n -= nn;
10598ccd4a63SDavid du Colombier 
10608ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1 || p[0] == 0)
10618ccd4a63SDavid du Colombier 			goto Short;
10628ccd4a63SDavid du Colombier 		nn = p[0];
10638ccd4a63SDavid du Colombier 		m->u.clientHello.compressors = newbytes(nn);
10648ccd4a63SDavid du Colombier 		memmove(m->u.clientHello.compressors->data, p+1, nn);
10658ccd4a63SDavid du Colombier 		n -= nn + 1;
10668ccd4a63SDavid du Colombier 		break;
10678ccd4a63SDavid du Colombier 	case HServerHello:
10688ccd4a63SDavid du Colombier 		if(n < 2)
10698ccd4a63SDavid du Colombier 			goto Short;
10708ccd4a63SDavid du Colombier 		m->u.serverHello.version = get16(p);
10718ccd4a63SDavid du Colombier 		p += 2;
10728ccd4a63SDavid du Colombier 		n -= 2;
10738ccd4a63SDavid du Colombier 
10748ccd4a63SDavid du Colombier 		if(n < RandomSize)
10758ccd4a63SDavid du Colombier 			goto Short;
10768ccd4a63SDavid du Colombier 		memmove(m->u.serverHello.random, p, RandomSize);
10778ccd4a63SDavid du Colombier 		p += RandomSize;
10788ccd4a63SDavid du Colombier 		n -= RandomSize;
10798ccd4a63SDavid du Colombier 
10808ccd4a63SDavid du Colombier 		if(n < 1 || n < p[0]+1)
10818ccd4a63SDavid du Colombier 			goto Short;
10828ccd4a63SDavid du Colombier 		m->u.serverHello.sid = makebytes(p+1, p[0]);
10838ccd4a63SDavid du Colombier 		p += m->u.serverHello.sid->len+1;
10848ccd4a63SDavid du Colombier 		n -= m->u.serverHello.sid->len+1;
10858ccd4a63SDavid du Colombier 
10868ccd4a63SDavid du Colombier 		if(n < 3)
10878ccd4a63SDavid du Colombier 			goto Short;
10888ccd4a63SDavid du Colombier 		m->u.serverHello.cipher = get16(p);
10898ccd4a63SDavid du Colombier 		m->u.serverHello.compressor = p[2];
10908ccd4a63SDavid du Colombier 		n -= 3;
10918ccd4a63SDavid du Colombier 		break;
10928ccd4a63SDavid du Colombier 	case HCertificate:
10938ccd4a63SDavid du Colombier 		if(n < 3)
10948ccd4a63SDavid du Colombier 			goto Short;
10958ccd4a63SDavid du Colombier 		nn = get24(p);
10968ccd4a63SDavid du Colombier 		p += 3;
10978ccd4a63SDavid du Colombier 		n -= 3;
10988ccd4a63SDavid du Colombier 		if(n != nn)
10998ccd4a63SDavid du Colombier 			goto Short;
11008ccd4a63SDavid du Colombier 		/* certs */
11018ccd4a63SDavid du Colombier 		i = 0;
11028ccd4a63SDavid du Colombier 		while(n > 0) {
11038ccd4a63SDavid du Colombier 			if(n < 3)
11048ccd4a63SDavid du Colombier 				goto Short;
11058ccd4a63SDavid du Colombier 			nn = get24(p);
11068ccd4a63SDavid du Colombier 			p += 3;
11078ccd4a63SDavid du Colombier 			n -= 3;
11088ccd4a63SDavid du Colombier 			if(nn > n)
11098ccd4a63SDavid du Colombier 				goto Short;
11108ccd4a63SDavid du Colombier 			m->u.certificate.ncert = i+1;
11118ccd4a63SDavid du Colombier 			m->u.certificate.certs = erealloc(m->u.certificate.certs, (i+1)*sizeof(Bytes));
11128ccd4a63SDavid du Colombier 			m->u.certificate.certs[i] = makebytes(p, nn);
11138ccd4a63SDavid du Colombier 			p += nn;
11148ccd4a63SDavid du Colombier 			n -= nn;
11158ccd4a63SDavid du Colombier 			i++;
11168ccd4a63SDavid du Colombier 		}
11178ccd4a63SDavid du Colombier 		break;
11188ccd4a63SDavid du Colombier 	case HCertificateRequest:
11198ccd4a63SDavid du Colombier 		if(n < 2)
11208ccd4a63SDavid du Colombier 			goto Short;
11218ccd4a63SDavid du Colombier 		nn = get16(p);
11228ccd4a63SDavid du Colombier 		p += 2;
11238ccd4a63SDavid du Colombier 		n -= 2;
11248ccd4a63SDavid du Colombier 		if(nn < 1 || nn > n)
11258ccd4a63SDavid du Colombier 			goto Short;
11268ccd4a63SDavid du Colombier 		m->u.certificateRequest.types = makebytes(p, nn);
11278ccd4a63SDavid du Colombier 		nn = get24(p);
11288ccd4a63SDavid du Colombier 		p += 3;
11298ccd4a63SDavid du Colombier 		n -= 3;
11308ccd4a63SDavid du Colombier 		if(nn == 0 || n != nn)
11318ccd4a63SDavid du Colombier 			goto Short;
11328ccd4a63SDavid du Colombier 		/* cas */
11338ccd4a63SDavid du Colombier 		i = 0;
11348ccd4a63SDavid du Colombier 		while(n > 0) {
11358ccd4a63SDavid du Colombier 			if(n < 2)
11368ccd4a63SDavid du Colombier 				goto Short;
11378ccd4a63SDavid du Colombier 			nn = get16(p);
11388ccd4a63SDavid du Colombier 			p += 2;
11398ccd4a63SDavid du Colombier 			n -= 2;
11408ccd4a63SDavid du Colombier 			if(nn < 1 || nn > n)
11418ccd4a63SDavid du Colombier 				goto Short;
11428ccd4a63SDavid du Colombier 			m->u.certificateRequest.nca = i+1;
11438ccd4a63SDavid du Colombier 			m->u.certificateRequest.cas = erealloc(m->u.certificateRequest.cas, (i+1)*sizeof(Bytes));
11448ccd4a63SDavid du Colombier 			m->u.certificateRequest.cas[i] = makebytes(p, nn);
11458ccd4a63SDavid du Colombier 			p += nn;
11468ccd4a63SDavid du Colombier 			n -= nn;
11478ccd4a63SDavid du Colombier 			i++;
11488ccd4a63SDavid du Colombier 		}
11498ccd4a63SDavid du Colombier 		break;
11508ccd4a63SDavid du Colombier 	case HServerHelloDone:
11518ccd4a63SDavid du Colombier 		break;
11528ccd4a63SDavid du Colombier 	case HClientKeyExchange:
11538ccd4a63SDavid du Colombier 		/*
11548ccd4a63SDavid du Colombier 		 * this message depends upon the encryption selected
11558ccd4a63SDavid du Colombier 		 * assume rsa.
11568ccd4a63SDavid du Colombier 		 */
11578ccd4a63SDavid du Colombier 		if(c->version == SSL3Version)
11588ccd4a63SDavid du Colombier 			nn = n;
11598ccd4a63SDavid du Colombier 		else{
11608ccd4a63SDavid du Colombier 			if(n < 2)
11618ccd4a63SDavid du Colombier 				goto Short;
11628ccd4a63SDavid du Colombier 			nn = get16(p);
11638ccd4a63SDavid du Colombier 			p += 2;
11648ccd4a63SDavid du Colombier 			n -= 2;
11658ccd4a63SDavid du Colombier 		}
11668ccd4a63SDavid du Colombier 		if(n < nn)
11678ccd4a63SDavid du Colombier 			goto Short;
11688ccd4a63SDavid du Colombier 		m->u.clientKeyExchange.key = makebytes(p, nn);
11698ccd4a63SDavid du Colombier 		n -= nn;
11708ccd4a63SDavid du Colombier 		break;
11718ccd4a63SDavid du Colombier 	case HFinished:
11728ccd4a63SDavid du Colombier 		m->u.finished.n = c->finished.n;
11738ccd4a63SDavid du Colombier 		if(n < m->u.finished.n)
11748ccd4a63SDavid du Colombier 			goto Short;
11758ccd4a63SDavid du Colombier 		memmove(m->u.finished.verify, p, m->u.finished.n);
11768ccd4a63SDavid du Colombier 		n -= m->u.finished.n;
11778ccd4a63SDavid du Colombier 		break;
11788ccd4a63SDavid du Colombier 	}
11798ccd4a63SDavid du Colombier 
11808ccd4a63SDavid du Colombier 	if(type != HClientHello && n != 0)
11818ccd4a63SDavid du Colombier 		goto Short;
11828ccd4a63SDavid du Colombier Ok:
11838ccd4a63SDavid du Colombier 	if(c->trace){
11848ccd4a63SDavid du Colombier 		char buf[8000];
11858ccd4a63SDavid du Colombier 		c->trace("recv %s", msgPrint(buf, sizeof buf, m));
11868ccd4a63SDavid du Colombier 	}
11878ccd4a63SDavid du Colombier 	return 1;
11888ccd4a63SDavid du Colombier Short:
11898ccd4a63SDavid du Colombier 	tlsError(c, EDecodeError, "handshake message has invalid length");
11908ccd4a63SDavid du Colombier Err:
11918ccd4a63SDavid du Colombier 	msgClear(m);
11928ccd4a63SDavid du Colombier 	return 0;
11938ccd4a63SDavid du Colombier }
11948ccd4a63SDavid du Colombier 
11958ccd4a63SDavid du Colombier static void
msgClear(Msg * m)11968ccd4a63SDavid du Colombier msgClear(Msg *m)
11978ccd4a63SDavid du Colombier {
11988ccd4a63SDavid du Colombier 	int i;
11998ccd4a63SDavid du Colombier 
12008ccd4a63SDavid du Colombier 	switch(m->tag) {
12018ccd4a63SDavid du Colombier 	default:
1202*14cc0f53SDavid du Colombier 		sysfatal("msgClear: unknown message type: %d", m->tag);
12038ccd4a63SDavid du Colombier 	case HHelloRequest:
12048ccd4a63SDavid du Colombier 		break;
12058ccd4a63SDavid du Colombier 	case HClientHello:
12068ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.sid);
12078ccd4a63SDavid du Colombier 		freeints(m->u.clientHello.ciphers);
12088ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.compressors);
12098ccd4a63SDavid du Colombier 		break;
12108ccd4a63SDavid du Colombier 	case HServerHello:
12118ccd4a63SDavid du Colombier 		freebytes(m->u.clientHello.sid);
12128ccd4a63SDavid du Colombier 		break;
12138ccd4a63SDavid du Colombier 	case HCertificate:
12148ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificate.ncert; i++)
12158ccd4a63SDavid du Colombier 			freebytes(m->u.certificate.certs[i]);
12168ccd4a63SDavid du Colombier 		free(m->u.certificate.certs);
12178ccd4a63SDavid du Colombier 		break;
12188ccd4a63SDavid du Colombier 	case HCertificateRequest:
12198ccd4a63SDavid du Colombier 		freebytes(m->u.certificateRequest.types);
12208ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificateRequest.nca; i++)
12218ccd4a63SDavid du Colombier 			freebytes(m->u.certificateRequest.cas[i]);
12228ccd4a63SDavid du Colombier 		free(m->u.certificateRequest.cas);
12238ccd4a63SDavid du Colombier 		break;
12248ccd4a63SDavid du Colombier 	case HServerHelloDone:
12258ccd4a63SDavid du Colombier 		break;
12268ccd4a63SDavid du Colombier 	case HClientKeyExchange:
12278ccd4a63SDavid du Colombier 		freebytes(m->u.clientKeyExchange.key);
12288ccd4a63SDavid du Colombier 		break;
12298ccd4a63SDavid du Colombier 	case HFinished:
12308ccd4a63SDavid du Colombier 		break;
12318ccd4a63SDavid du Colombier 	}
12328ccd4a63SDavid du Colombier 	memset(m, 0, sizeof(Msg));
12338ccd4a63SDavid du Colombier }
12348ccd4a63SDavid du Colombier 
12358ccd4a63SDavid du Colombier static char *
bytesPrint(char * bs,char * be,char * s0,Bytes * b,char * s1)12368ccd4a63SDavid du Colombier bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1)
12378ccd4a63SDavid du Colombier {
12388ccd4a63SDavid du Colombier 	int i;
12398ccd4a63SDavid du Colombier 
12408ccd4a63SDavid du Colombier 	if(s0)
12418ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s0);
12428ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "[");
12438ccd4a63SDavid du Colombier 	if(b == nil)
12448ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "nil");
12458ccd4a63SDavid du Colombier 	else
12468ccd4a63SDavid du Colombier 		for(i=0; i<b->len; i++)
12478ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x ", b->data[i]);
12488ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "]");
12498ccd4a63SDavid du Colombier 	if(s1)
12508ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s1);
12518ccd4a63SDavid du Colombier 	return bs;
12528ccd4a63SDavid du Colombier }
12538ccd4a63SDavid du Colombier 
12548ccd4a63SDavid du Colombier static char *
intsPrint(char * bs,char * be,char * s0,Ints * b,char * s1)12558ccd4a63SDavid du Colombier intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1)
12568ccd4a63SDavid du Colombier {
12578ccd4a63SDavid du Colombier 	int i;
12588ccd4a63SDavid du Colombier 
12598ccd4a63SDavid du Colombier 	if(s0)
12608ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s0);
12618ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "[");
12628ccd4a63SDavid du Colombier 	if(b == nil)
12638ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "nil");
12648ccd4a63SDavid du Colombier 	else
12658ccd4a63SDavid du Colombier 		for(i=0; i<b->len; i++)
12668ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%x ", b->data[i]);
12678ccd4a63SDavid du Colombier 	bs = seprint(bs, be, "]");
12688ccd4a63SDavid du Colombier 	if(s1)
12698ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "%s", s1);
12708ccd4a63SDavid du Colombier 	return bs;
12718ccd4a63SDavid du Colombier }
12728ccd4a63SDavid du Colombier 
12738ccd4a63SDavid du Colombier static char*
msgPrint(char * buf,int n,Msg * m)12748ccd4a63SDavid du Colombier msgPrint(char *buf, int n, Msg *m)
12758ccd4a63SDavid du Colombier {
12768ccd4a63SDavid du Colombier 	int i;
12778ccd4a63SDavid du Colombier 	char *bs = buf, *be = buf+n;
12788ccd4a63SDavid du Colombier 
12798ccd4a63SDavid du Colombier 	switch(m->tag) {
12808ccd4a63SDavid du Colombier 	default:
12818ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "unknown %d\n", m->tag);
12828ccd4a63SDavid du Colombier 		break;
12838ccd4a63SDavid du Colombier 	case HClientHello:
12848ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ClientHello\n");
12858ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tversion: %.4x\n", m->u.clientHello.version);
12868ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\trandom: ");
12878ccd4a63SDavid du Colombier 		for(i=0; i<RandomSize; i++)
12888ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.clientHello.random[i]);
12898ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
12908ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tsid: ", m->u.clientHello.sid, "\n");
12918ccd4a63SDavid du Colombier 		bs = intsPrint(bs, be, "\tciphers: ", m->u.clientHello.ciphers, "\n");
12928ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tcompressors: ", m->u.clientHello.compressors, "\n");
12938ccd4a63SDavid du Colombier 		break;
12948ccd4a63SDavid du Colombier 	case HServerHello:
12958ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ServerHello\n");
12968ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tversion: %.4x\n", m->u.serverHello.version);
12978ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\trandom: ");
12988ccd4a63SDavid du Colombier 		for(i=0; i<RandomSize; i++)
12998ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.serverHello.random[i]);
13008ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
13018ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tsid: ", m->u.serverHello.sid, "\n");
13028ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcipher: %.4x\n", m->u.serverHello.cipher);
13038ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcompressor: %.2x\n", m->u.serverHello.compressor);
13048ccd4a63SDavid du Colombier 		break;
13058ccd4a63SDavid du Colombier 	case HCertificate:
13068ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "Certificate\n");
13078ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificate.ncert; i++)
13088ccd4a63SDavid du Colombier 			bs = bytesPrint(bs, be, "\t", m->u.certificate.certs[i], "\n");
13098ccd4a63SDavid du Colombier 		break;
13108ccd4a63SDavid du Colombier 	case HCertificateRequest:
13118ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "CertificateRequest\n");
13128ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n");
13138ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\tcertificateauthorities\n");
13148ccd4a63SDavid du Colombier 		for(i=0; i<m->u.certificateRequest.nca; i++)
13158ccd4a63SDavid du Colombier 			bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
13168ccd4a63SDavid du Colombier 		break;
13178ccd4a63SDavid du Colombier 	case HServerHelloDone:
13188ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "ServerHelloDone\n");
13198ccd4a63SDavid du Colombier 		break;
13208ccd4a63SDavid du Colombier 	case HClientKeyExchange:
13218ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "HClientKeyExchange\n");
13228ccd4a63SDavid du Colombier 		bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n");
13238ccd4a63SDavid du Colombier 		break;
13248ccd4a63SDavid du Colombier 	case HFinished:
13258ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "HFinished\n");
13268ccd4a63SDavid du Colombier 		for(i=0; i<m->u.finished.n; i++)
13278ccd4a63SDavid du Colombier 			bs = seprint(bs, be, "%.2x", m->u.finished.verify[i]);
13288ccd4a63SDavid du Colombier 		bs = seprint(bs, be, "\n");
13298ccd4a63SDavid du Colombier 		break;
13308ccd4a63SDavid du Colombier 	}
13318ccd4a63SDavid du Colombier 	USED(bs);
13328ccd4a63SDavid du Colombier 	return buf;
13338ccd4a63SDavid du Colombier }
13348ccd4a63SDavid du Colombier 
13358ccd4a63SDavid du Colombier static void
tlsError(TlsConnection * c,int err,char * fmt,...)13368ccd4a63SDavid du Colombier tlsError(TlsConnection *c, int err, char *fmt, ...)
13378ccd4a63SDavid du Colombier {
13388ccd4a63SDavid du Colombier 	char msg[512];
13398ccd4a63SDavid du Colombier 	va_list arg;
13408ccd4a63SDavid du Colombier 
13418ccd4a63SDavid du Colombier 	va_start(arg, fmt);
13428ccd4a63SDavid du Colombier 	vseprint(msg, msg+sizeof(msg), fmt, arg);
13438ccd4a63SDavid du Colombier 	va_end(arg);
13448ccd4a63SDavid du Colombier 	if(c->trace)
13458ccd4a63SDavid du Colombier 		c->trace("tlsError: %s\n", msg);
13468ccd4a63SDavid du Colombier 	else if(c->erred)
13478ccd4a63SDavid du Colombier 		fprint(2, "double error: %r, %s", msg);
13488ccd4a63SDavid du Colombier 	else
13498ccd4a63SDavid du Colombier 		werrstr("tls: local %s", msg);
13508ccd4a63SDavid du Colombier 	c->erred = 1;
13518ccd4a63SDavid du Colombier 	fprint(c->ctl, "alert %d", err);
13528ccd4a63SDavid du Colombier }
13538ccd4a63SDavid du Colombier 
13548ccd4a63SDavid du Colombier // commit to specific version number
13558ccd4a63SDavid du Colombier static int
setVersion(TlsConnection * c,int version)13568ccd4a63SDavid du Colombier setVersion(TlsConnection *c, int version)
13578ccd4a63SDavid du Colombier {
13588ccd4a63SDavid du Colombier 	if(c->verset || version > MaxProtoVersion || version < MinProtoVersion)
13598ccd4a63SDavid du Colombier 		return -1;
13608ccd4a63SDavid du Colombier 	if(version > c->version)
13618ccd4a63SDavid du Colombier 		version = c->version;
13628ccd4a63SDavid du Colombier 	if(version == SSL3Version) {
13638ccd4a63SDavid du Colombier 		c->version = version;
13648ccd4a63SDavid du Colombier 		c->finished.n = SSL3FinishedLen;
13658ccd4a63SDavid du Colombier 	}else if(version == TLSVersion){
13668ccd4a63SDavid du Colombier 		c->version = version;
13678ccd4a63SDavid du Colombier 		c->finished.n = TLSFinishedLen;
13688ccd4a63SDavid du Colombier 	}else
13698ccd4a63SDavid du Colombier 		return -1;
13708ccd4a63SDavid du Colombier 	c->verset = 1;
13718ccd4a63SDavid du Colombier 	return fprint(c->ctl, "version 0x%x", version);
13728ccd4a63SDavid du Colombier }
13738ccd4a63SDavid du Colombier 
13748ccd4a63SDavid du Colombier // confirm that received Finished message matches the expected value
13758ccd4a63SDavid du Colombier static int
finishedMatch(TlsConnection * c,Finished * f)13768ccd4a63SDavid du Colombier finishedMatch(TlsConnection *c, Finished *f)
13778ccd4a63SDavid du Colombier {
13788ccd4a63SDavid du Colombier 	return memcmp(f->verify, c->finished.verify, f->n) == 0;
13798ccd4a63SDavid du Colombier }
13808ccd4a63SDavid du Colombier 
13818ccd4a63SDavid du Colombier // free memory associated with TlsConnection struct
13828ccd4a63SDavid du Colombier //		(but don't close the TLS channel itself)
13838ccd4a63SDavid du Colombier static void
tlsConnectionFree(TlsConnection * c)13848ccd4a63SDavid du Colombier tlsConnectionFree(TlsConnection *c)
13858ccd4a63SDavid du Colombier {
13868ccd4a63SDavid du Colombier 	tlsSecClose(c->sec);
13878ccd4a63SDavid du Colombier 	freebytes(c->sid);
13888ccd4a63SDavid du Colombier 	freebytes(c->cert);
13898ccd4a63SDavid du Colombier 	memset(c, 0, sizeof(c));
13908ccd4a63SDavid du Colombier 	free(c);
13918ccd4a63SDavid du Colombier }
13928ccd4a63SDavid du Colombier 
13938ccd4a63SDavid du Colombier 
13948ccd4a63SDavid du Colombier //================= cipher choices ========================
13958ccd4a63SDavid du Colombier 
13968ccd4a63SDavid du Colombier static int weakCipher[CipherMax] =
13978ccd4a63SDavid du Colombier {
13988ccd4a63SDavid du Colombier 	1,	/* TLS_NULL_WITH_NULL_NULL */
13998ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_WITH_NULL_MD5 */
14008ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_WITH_NULL_SHA */
14018ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */
14028ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_RC4_128_MD5 */
14038ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_RC4_128_SHA */
14048ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */
14058ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_IDEA_CBC_SHA */
14068ccd4a63SDavid du Colombier 	1,	/* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */
14078ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_DES_CBC_SHA */
14088ccd4a63SDavid du Colombier 	0,	/* TLS_RSA_WITH_3DES_EDE_CBC_SHA */
14098ccd4a63SDavid du Colombier 	1,	/* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */
14108ccd4a63SDavid du Colombier 	0,	/* TLS_DH_DSS_WITH_DES_CBC_SHA */
14118ccd4a63SDavid du Colombier 	0,	/* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */
14128ccd4a63SDavid du Colombier 	1,	/* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */
14138ccd4a63SDavid du Colombier 	0,	/* TLS_DH_RSA_WITH_DES_CBC_SHA */
14148ccd4a63SDavid du Colombier 	0,	/* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */
14158ccd4a63SDavid du Colombier 	1,	/* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */
14168ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_DSS_WITH_DES_CBC_SHA */
14178ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */
14188ccd4a63SDavid du Colombier 	1,	/* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */
14198ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_RSA_WITH_DES_CBC_SHA */
14208ccd4a63SDavid du Colombier 	0,	/* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */
14218ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */
14228ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_RC4_128_MD5 */
14238ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */
14248ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_DES_CBC_SHA */
14258ccd4a63SDavid du Colombier 	1,	/* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */
14268ccd4a63SDavid du Colombier };
14278ccd4a63SDavid du Colombier 
14288ccd4a63SDavid du Colombier static int
setAlgs(TlsConnection * c,int a)14298ccd4a63SDavid du Colombier setAlgs(TlsConnection *c, int a)
14308ccd4a63SDavid du Colombier {
14318ccd4a63SDavid du Colombier 	int i;
14328ccd4a63SDavid du Colombier 
14338ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
14348ccd4a63SDavid du Colombier 		if(cipherAlgs[i].tlsid == a){
14358ccd4a63SDavid du Colombier 			c->enc = cipherAlgs[i].enc;
14368ccd4a63SDavid du Colombier 			c->digest = cipherAlgs[i].digest;
14378ccd4a63SDavid du Colombier 			c->nsecret = cipherAlgs[i].nsecret;
14388ccd4a63SDavid du Colombier 			if(c->nsecret > MaxKeyData)
14398ccd4a63SDavid du Colombier 				return 0;
14408ccd4a63SDavid du Colombier 			return 1;
14418ccd4a63SDavid du Colombier 		}
14428ccd4a63SDavid du Colombier 	}
14438ccd4a63SDavid du Colombier 	return 0;
14448ccd4a63SDavid du Colombier }
14458ccd4a63SDavid du Colombier 
14468ccd4a63SDavid du Colombier static int
okCipher(Ints * cv)14478ccd4a63SDavid du Colombier okCipher(Ints *cv)
14488ccd4a63SDavid du Colombier {
14498ccd4a63SDavid du Colombier 	int weak, i, j, c;
14508ccd4a63SDavid du Colombier 
14518ccd4a63SDavid du Colombier 	weak = 1;
14528ccd4a63SDavid du Colombier 	for(i = 0; i < cv->len; i++) {
14538ccd4a63SDavid du Colombier 		c = cv->data[i];
14548ccd4a63SDavid du Colombier 		if(c >= CipherMax)
14558ccd4a63SDavid du Colombier 			weak = 0;
14568ccd4a63SDavid du Colombier 		else
14578ccd4a63SDavid du Colombier 			weak &= weakCipher[c];
14588ccd4a63SDavid du Colombier 		for(j = 0; j < nelem(cipherAlgs); j++)
14598ccd4a63SDavid du Colombier 			if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
14608ccd4a63SDavid du Colombier 				return c;
14618ccd4a63SDavid du Colombier 	}
14628ccd4a63SDavid du Colombier 	if(weak)
14638ccd4a63SDavid du Colombier 		return -2;
14648ccd4a63SDavid du Colombier 	return -1;
14658ccd4a63SDavid du Colombier }
14668ccd4a63SDavid du Colombier 
14678ccd4a63SDavid du Colombier static int
okCompression(Bytes * cv)14688ccd4a63SDavid du Colombier okCompression(Bytes *cv)
14698ccd4a63SDavid du Colombier {
14708ccd4a63SDavid du Colombier 	int i, j, c;
14718ccd4a63SDavid du Colombier 
14728ccd4a63SDavid du Colombier 	for(i = 0; i < cv->len; i++) {
14738ccd4a63SDavid du Colombier 		c = cv->data[i];
14748ccd4a63SDavid du Colombier 		for(j = 0; j < nelem(compressors); j++) {
14758ccd4a63SDavid du Colombier 			if(compressors[j] == c)
14768ccd4a63SDavid du Colombier 				return c;
14778ccd4a63SDavid du Colombier 		}
14788ccd4a63SDavid du Colombier 	}
14798ccd4a63SDavid du Colombier 	return -1;
14808ccd4a63SDavid du Colombier }
14818ccd4a63SDavid du Colombier 
14828ccd4a63SDavid du Colombier static Lock	ciphLock;
14838ccd4a63SDavid du Colombier static int	nciphers;
14848ccd4a63SDavid du Colombier 
14858ccd4a63SDavid du Colombier static int
initCiphers(void)14868ccd4a63SDavid du Colombier initCiphers(void)
14878ccd4a63SDavid du Colombier {
14888ccd4a63SDavid du Colombier 	enum {MaxAlgF = 1024, MaxAlgs = 10};
14898ccd4a63SDavid du Colombier 	char s[MaxAlgF], *flds[MaxAlgs];
14908ccd4a63SDavid du Colombier 	int i, j, n, ok;
14918ccd4a63SDavid du Colombier 
14928ccd4a63SDavid du Colombier 	lock(&ciphLock);
14938ccd4a63SDavid du Colombier 	if(nciphers){
14948ccd4a63SDavid du Colombier 		unlock(&ciphLock);
14958ccd4a63SDavid du Colombier 		return nciphers;
14968ccd4a63SDavid du Colombier 	}
14978ccd4a63SDavid du Colombier 	j = open("#a/tls/encalgs", OREAD);
14988ccd4a63SDavid du Colombier 	if(j < 0){
14998ccd4a63SDavid du Colombier 		werrstr("can't open #a/tls/encalgs: %r");
15008ccd4a63SDavid du Colombier 		return 0;
15018ccd4a63SDavid du Colombier 	}
15028ccd4a63SDavid du Colombier 	n = read(j, s, MaxAlgF-1);
15038ccd4a63SDavid du Colombier 	close(j);
15048ccd4a63SDavid du Colombier 	if(n <= 0){
15058ccd4a63SDavid du Colombier 		werrstr("nothing in #a/tls/encalgs: %r");
15068ccd4a63SDavid du Colombier 		return 0;
15078ccd4a63SDavid du Colombier 	}
15088ccd4a63SDavid du Colombier 	s[n] = 0;
15098ccd4a63SDavid du Colombier 	n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
15108ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
15118ccd4a63SDavid du Colombier 		ok = 0;
15128ccd4a63SDavid du Colombier 		for(j = 0; j < n; j++){
15138ccd4a63SDavid du Colombier 			if(strcmp(cipherAlgs[i].enc, flds[j]) == 0){
15148ccd4a63SDavid du Colombier 				ok = 1;
15158ccd4a63SDavid du Colombier 				break;
15168ccd4a63SDavid du Colombier 			}
15178ccd4a63SDavid du Colombier 		}
15188ccd4a63SDavid du Colombier 		cipherAlgs[i].ok = ok;
15198ccd4a63SDavid du Colombier 	}
15208ccd4a63SDavid du Colombier 
15218ccd4a63SDavid du Colombier 	j = open("#a/tls/hashalgs", OREAD);
15228ccd4a63SDavid du Colombier 	if(j < 0){
15238ccd4a63SDavid du Colombier 		werrstr("can't open #a/tls/hashalgs: %r");
15248ccd4a63SDavid du Colombier 		return 0;
15258ccd4a63SDavid du Colombier 	}
15268ccd4a63SDavid du Colombier 	n = read(j, s, MaxAlgF-1);
15278ccd4a63SDavid du Colombier 	close(j);
15288ccd4a63SDavid du Colombier 	if(n <= 0){
15298ccd4a63SDavid du Colombier 		werrstr("nothing in #a/tls/hashalgs: %r");
15308ccd4a63SDavid du Colombier 		return 0;
15318ccd4a63SDavid du Colombier 	}
15328ccd4a63SDavid du Colombier 	s[n] = 0;
15338ccd4a63SDavid du Colombier 	n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
15348ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
15358ccd4a63SDavid du Colombier 		ok = 0;
15368ccd4a63SDavid du Colombier 		for(j = 0; j < n; j++){
15378ccd4a63SDavid du Colombier 			if(strcmp(cipherAlgs[i].digest, flds[j]) == 0){
15388ccd4a63SDavid du Colombier 				ok = 1;
15398ccd4a63SDavid du Colombier 				break;
15408ccd4a63SDavid du Colombier 			}
15418ccd4a63SDavid du Colombier 		}
15428ccd4a63SDavid du Colombier 		cipherAlgs[i].ok &= ok;
15438ccd4a63SDavid du Colombier 		if(cipherAlgs[i].ok)
15448ccd4a63SDavid du Colombier 			nciphers++;
15458ccd4a63SDavid du Colombier 	}
15468ccd4a63SDavid du Colombier 	unlock(&ciphLock);
15478ccd4a63SDavid du Colombier 	return nciphers;
15488ccd4a63SDavid du Colombier }
15498ccd4a63SDavid du Colombier 
15508ccd4a63SDavid du Colombier static Ints*
makeciphers(void)15518ccd4a63SDavid du Colombier makeciphers(void)
15528ccd4a63SDavid du Colombier {
15538ccd4a63SDavid du Colombier 	Ints *is;
15548ccd4a63SDavid du Colombier 	int i, j;
15558ccd4a63SDavid du Colombier 
15568ccd4a63SDavid du Colombier 	is = newints(nciphers);
15578ccd4a63SDavid du Colombier 	j = 0;
15588ccd4a63SDavid du Colombier 	for(i = 0; i < nelem(cipherAlgs); i++){
15598ccd4a63SDavid du Colombier 		if(cipherAlgs[i].ok)
15608ccd4a63SDavid du Colombier 			is->data[j++] = cipherAlgs[i].tlsid;
15618ccd4a63SDavid du Colombier 	}
15628ccd4a63SDavid du Colombier 	return is;
15638ccd4a63SDavid du Colombier }
15648ccd4a63SDavid du Colombier 
15658ccd4a63SDavid du Colombier 
15668ccd4a63SDavid du Colombier 
15678ccd4a63SDavid du Colombier //================= security functions ========================
15688ccd4a63SDavid du Colombier 
15698ccd4a63SDavid du Colombier // given X.509 certificate, set up connection to factotum
15708ccd4a63SDavid du Colombier //	for using corresponding private key
15718ccd4a63SDavid du Colombier static AuthRpc*
factotum_rsa_open(uchar * cert,int certlen)15728ccd4a63SDavid du Colombier factotum_rsa_open(uchar *cert, int certlen)
15738ccd4a63SDavid du Colombier {
15748ccd4a63SDavid du Colombier 	int afd;
15758ccd4a63SDavid du Colombier 	char *s;
15768ccd4a63SDavid du Colombier 	mpint *pub = nil;
15778ccd4a63SDavid du Colombier 	RSApub *rsapub;
15788ccd4a63SDavid du Colombier 	AuthRpc *rpc;
15798ccd4a63SDavid du Colombier 
15808ccd4a63SDavid du Colombier 	// start talking to factotum
15818ccd4a63SDavid du Colombier 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
15828ccd4a63SDavid du Colombier 		return nil;
15838ccd4a63SDavid du Colombier 	if((rpc = auth_allocrpc(afd)) == nil){
15848ccd4a63SDavid du Colombier 		close(afd);
15858ccd4a63SDavid du Colombier 		return nil;
15868ccd4a63SDavid du Colombier 	}
15878ccd4a63SDavid du Colombier 	s = "proto=rsa service=tls role=client";
15888ccd4a63SDavid du Colombier 	if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
15898ccd4a63SDavid du Colombier 		factotum_rsa_close(rpc);
15908ccd4a63SDavid du Colombier 		return nil;
15918ccd4a63SDavid du Colombier 	}
15928ccd4a63SDavid du Colombier 
15938ccd4a63SDavid du Colombier 	// roll factotum keyring around to match certificate
15948ccd4a63SDavid du Colombier 	rsapub = X509toRSApub(cert, certlen, nil, 0);
15958ccd4a63SDavid du Colombier 	while(1){
15968ccd4a63SDavid du Colombier 		if(auth_rpc(rpc, "read", nil, 0) != ARok){
15978ccd4a63SDavid du Colombier 			factotum_rsa_close(rpc);
15988ccd4a63SDavid du Colombier 			rpc = nil;
15998ccd4a63SDavid du Colombier 			goto done;
16008ccd4a63SDavid du Colombier 		}
16018ccd4a63SDavid du Colombier 		pub = strtomp(rpc->arg, nil, 16, nil);
16028ccd4a63SDavid du Colombier 		assert(pub != nil);
16038ccd4a63SDavid du Colombier 		if(mpcmp(pub,rsapub->n) == 0)
16048ccd4a63SDavid du Colombier 			break;
16058ccd4a63SDavid du Colombier 	}
16068ccd4a63SDavid du Colombier done:
16078ccd4a63SDavid du Colombier 	mpfree(pub);
16088ccd4a63SDavid du Colombier 	rsapubfree(rsapub);
16098ccd4a63SDavid du Colombier 	return rpc;
16108ccd4a63SDavid du Colombier }
16118ccd4a63SDavid du Colombier 
16128ccd4a63SDavid du Colombier static mpint*
factotum_rsa_decrypt(AuthRpc * rpc,mpint * cipher)16138ccd4a63SDavid du Colombier factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher)
16148ccd4a63SDavid du Colombier {
16158ccd4a63SDavid du Colombier 	char *p;
16168ccd4a63SDavid du Colombier 	int rv;
16178ccd4a63SDavid du Colombier 
16188ccd4a63SDavid du Colombier 	if((p = mptoa(cipher, 16, nil, 0)) == nil)
16198ccd4a63SDavid du Colombier 		return nil;
16208ccd4a63SDavid du Colombier 	rv = auth_rpc(rpc, "write", p, strlen(p));
16218ccd4a63SDavid du Colombier 	free(p);
16228ccd4a63SDavid du Colombier 	if(rv != ARok || auth_rpc(rpc, "read", nil, 0) != ARok)
16238ccd4a63SDavid du Colombier 		return nil;
16248ccd4a63SDavid du Colombier 	mpfree(cipher);
16258ccd4a63SDavid du Colombier 	return strtomp(rpc->arg, nil, 16, nil);
16268ccd4a63SDavid du Colombier }
16278ccd4a63SDavid du Colombier 
16288ccd4a63SDavid du Colombier static void
factotum_rsa_close(AuthRpc * rpc)16298ccd4a63SDavid du Colombier factotum_rsa_close(AuthRpc*rpc)
16308ccd4a63SDavid du Colombier {
16318ccd4a63SDavid du Colombier 	if(!rpc)
16328ccd4a63SDavid du Colombier 		return;
16338ccd4a63SDavid du Colombier 	close(rpc->afd);
16348ccd4a63SDavid du Colombier 	auth_freerpc(rpc);
16358ccd4a63SDavid du Colombier }
16368ccd4a63SDavid du Colombier 
16378ccd4a63SDavid du Colombier static void
tlsPmd5(uchar * buf,int nbuf,uchar * key,int nkey,uchar * label,int nlabel,uchar * seed0,int nseed0,uchar * seed1,int nseed1)16388ccd4a63SDavid du Colombier tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
16398ccd4a63SDavid du Colombier {
16408ccd4a63SDavid du Colombier 	uchar ai[MD5dlen], tmp[MD5dlen];
16418ccd4a63SDavid du Colombier 	int i, n;
16428ccd4a63SDavid du Colombier 	MD5state *s;
16438ccd4a63SDavid du Colombier 
16448ccd4a63SDavid du Colombier 	// generate a1
16458ccd4a63SDavid du Colombier 	s = hmac_md5(label, nlabel, key, nkey, nil, nil);
16468ccd4a63SDavid du Colombier 	s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
16478ccd4a63SDavid du Colombier 	hmac_md5(seed1, nseed1, key, nkey, ai, s);
16488ccd4a63SDavid du Colombier 
16498ccd4a63SDavid du Colombier 	while(nbuf > 0) {
16508ccd4a63SDavid du Colombier 		s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil);
16518ccd4a63SDavid du Colombier 		s = hmac_md5(label, nlabel, key, nkey, nil, s);
16528ccd4a63SDavid du Colombier 		s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
16538ccd4a63SDavid du Colombier 		hmac_md5(seed1, nseed1, key, nkey, tmp, s);
16548ccd4a63SDavid du Colombier 		n = MD5dlen;
16558ccd4a63SDavid du Colombier 		if(n > nbuf)
16568ccd4a63SDavid du Colombier 			n = nbuf;
16578ccd4a63SDavid du Colombier 		for(i = 0; i < n; i++)
16588ccd4a63SDavid du Colombier 			buf[i] ^= tmp[i];
16598ccd4a63SDavid du Colombier 		buf += n;
16608ccd4a63SDavid du Colombier 		nbuf -= n;
16618ccd4a63SDavid du Colombier 		hmac_md5(ai, MD5dlen, key, nkey, tmp, nil);
16628ccd4a63SDavid du Colombier 		memmove(ai, tmp, MD5dlen);
16638ccd4a63SDavid du Colombier 	}
16648ccd4a63SDavid du Colombier }
16658ccd4a63SDavid du Colombier 
16668ccd4a63SDavid du Colombier static void
tlsPsha1(uchar * buf,int nbuf,uchar * key,int nkey,uchar * label,int nlabel,uchar * seed0,int nseed0,uchar * seed1,int nseed1)16678ccd4a63SDavid du Colombier tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
16688ccd4a63SDavid du Colombier {
16698ccd4a63SDavid du Colombier 	uchar ai[SHA1dlen], tmp[SHA1dlen];
16708ccd4a63SDavid du Colombier 	int i, n;
16718ccd4a63SDavid du Colombier 	SHAstate *s;
16728ccd4a63SDavid du Colombier 
16738ccd4a63SDavid du Colombier 	// generate a1
16748ccd4a63SDavid du Colombier 	s = hmac_sha1(label, nlabel, key, nkey, nil, nil);
16758ccd4a63SDavid du Colombier 	s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
16768ccd4a63SDavid du Colombier 	hmac_sha1(seed1, nseed1, key, nkey, ai, s);
16778ccd4a63SDavid du Colombier 
16788ccd4a63SDavid du Colombier 	while(nbuf > 0) {
16798ccd4a63SDavid du Colombier 		s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil);
16808ccd4a63SDavid du Colombier 		s = hmac_sha1(label, nlabel, key, nkey, nil, s);
16818ccd4a63SDavid du Colombier 		s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
16828ccd4a63SDavid du Colombier 		hmac_sha1(seed1, nseed1, key, nkey, tmp, s);
16838ccd4a63SDavid du Colombier 		n = SHA1dlen;
16848ccd4a63SDavid du Colombier 		if(n > nbuf)
16858ccd4a63SDavid du Colombier 			n = nbuf;
16868ccd4a63SDavid du Colombier 		for(i = 0; i < n; i++)
16878ccd4a63SDavid du Colombier 			buf[i] ^= tmp[i];
16888ccd4a63SDavid du Colombier 		buf += n;
16898ccd4a63SDavid du Colombier 		nbuf -= n;
16908ccd4a63SDavid du Colombier 		hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil);
16918ccd4a63SDavid du Colombier 		memmove(ai, tmp, SHA1dlen);
16928ccd4a63SDavid du Colombier 	}
16938ccd4a63SDavid du Colombier }
16948ccd4a63SDavid du Colombier 
16958ccd4a63SDavid du Colombier // fill buf with md5(args)^sha1(args)
16968ccd4a63SDavid du Colombier static void
tlsPRF(uchar * buf,int nbuf,uchar * key,int nkey,char * label,uchar * seed0,int nseed0,uchar * seed1,int nseed1)16978ccd4a63SDavid du Colombier tlsPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
16988ccd4a63SDavid du Colombier {
16998ccd4a63SDavid du Colombier 	int i;
17008ccd4a63SDavid du Colombier 	int nlabel = strlen(label);
17018ccd4a63SDavid du Colombier 	int n = (nkey + 1) >> 1;
17028ccd4a63SDavid du Colombier 
17038ccd4a63SDavid du Colombier 	for(i = 0; i < nbuf; i++)
17048ccd4a63SDavid du Colombier 		buf[i] = 0;
17058ccd4a63SDavid du Colombier 	tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
17068ccd4a63SDavid du Colombier 	tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
17078ccd4a63SDavid du Colombier }
17088ccd4a63SDavid du Colombier 
17098ccd4a63SDavid du Colombier /*
17108ccd4a63SDavid du Colombier  * for setting server session id's
17118ccd4a63SDavid du Colombier  */
17128ccd4a63SDavid du Colombier static Lock	sidLock;
17138ccd4a63SDavid du Colombier static long	maxSid = 1;
17148ccd4a63SDavid du Colombier 
17158ccd4a63SDavid du Colombier /* the keys are verified to have the same public components
17168ccd4a63SDavid du Colombier  * and to function correctly with pkcs 1 encryption and decryption. */
17178ccd4a63SDavid du Colombier static TlsSec*
tlsSecInits(int cvers,uchar * csid,int ncsid,uchar * crandom,uchar * ssid,int * nssid,uchar * srandom)17188ccd4a63SDavid du Colombier tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom)
17198ccd4a63SDavid du Colombier {
17208ccd4a63SDavid du Colombier 	TlsSec *sec = emalloc(sizeof(*sec));
17218ccd4a63SDavid du Colombier 
17228ccd4a63SDavid du Colombier 	USED(csid); USED(ncsid);  // ignore csid for now
17238ccd4a63SDavid du Colombier 
17248ccd4a63SDavid du Colombier 	memmove(sec->crandom, crandom, RandomSize);
17258ccd4a63SDavid du Colombier 	sec->clientVers = cvers;
17268ccd4a63SDavid du Colombier 
17278ccd4a63SDavid du Colombier 	put32(sec->srandom, time(0));
17288ccd4a63SDavid du Colombier 	genrandom(sec->srandom+4, RandomSize-4);
17298ccd4a63SDavid du Colombier 	memmove(srandom, sec->srandom, RandomSize);
17308ccd4a63SDavid du Colombier 
17318ccd4a63SDavid du Colombier 	/*
17328ccd4a63SDavid du Colombier 	 * make up a unique sid: use our pid, and and incrementing id
17338ccd4a63SDavid du Colombier 	 * can signal no sid by setting nssid to 0.
17348ccd4a63SDavid du Colombier 	 */
17358ccd4a63SDavid du Colombier 	memset(ssid, 0, SidSize);
17368ccd4a63SDavid du Colombier 	put32(ssid, getpid());
17378ccd4a63SDavid du Colombier 	lock(&sidLock);
17388ccd4a63SDavid du Colombier 	put32(ssid+4, maxSid++);
17398ccd4a63SDavid du Colombier 	unlock(&sidLock);
17408ccd4a63SDavid du Colombier 	*nssid = SidSize;
17418ccd4a63SDavid du Colombier 	return sec;
17428ccd4a63SDavid du Colombier }
17438ccd4a63SDavid du Colombier 
17448ccd4a63SDavid du Colombier static int
tlsSecSecrets(TlsSec * sec,int vers,uchar * epm,int nepm,uchar * kd,int nkd)17458ccd4a63SDavid du Colombier tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd)
17468ccd4a63SDavid du Colombier {
17478ccd4a63SDavid du Colombier 	if(epm != nil){
17488ccd4a63SDavid du Colombier 		if(setVers(sec, vers) < 0)
17498ccd4a63SDavid du Colombier 			goto Err;
17508ccd4a63SDavid du Colombier 		serverMasterSecret(sec, epm, nepm);
17518ccd4a63SDavid du Colombier 	}else if(sec->vers != vers){
17528ccd4a63SDavid du Colombier 		werrstr("mismatched session versions");
17538ccd4a63SDavid du Colombier 		goto Err;
17548ccd4a63SDavid du Colombier 	}
17558ccd4a63SDavid du Colombier 	setSecrets(sec, kd, nkd);
17568ccd4a63SDavid du Colombier 	return 0;
17578ccd4a63SDavid du Colombier Err:
17588ccd4a63SDavid du Colombier 	sec->ok = -1;
17598ccd4a63SDavid du Colombier 	return -1;
17608ccd4a63SDavid du Colombier }
17618ccd4a63SDavid du Colombier 
17628ccd4a63SDavid du Colombier static TlsSec*
tlsSecInitc(int cvers,uchar * crandom)17638ccd4a63SDavid du Colombier tlsSecInitc(int cvers, uchar *crandom)
17648ccd4a63SDavid du Colombier {
17658ccd4a63SDavid du Colombier 	TlsSec *sec = emalloc(sizeof(*sec));
17668ccd4a63SDavid du Colombier 	sec->clientVers = cvers;
17678ccd4a63SDavid du Colombier 	put32(sec->crandom, time(0));
17688ccd4a63SDavid du Colombier 	genrandom(sec->crandom+4, RandomSize-4);
17698ccd4a63SDavid du Colombier 	memmove(crandom, sec->crandom, RandomSize);
17708ccd4a63SDavid du Colombier 	return sec;
17718ccd4a63SDavid du Colombier }
17728ccd4a63SDavid du Colombier 
17738ccd4a63SDavid 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)17748ccd4a63SDavid 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)
17758ccd4a63SDavid du Colombier {
17768ccd4a63SDavid du Colombier 	RSApub *pub;
17778ccd4a63SDavid du Colombier 
17788ccd4a63SDavid du Colombier 	pub = nil;
17798ccd4a63SDavid du Colombier 
17808ccd4a63SDavid du Colombier 	USED(sid);
17818ccd4a63SDavid du Colombier 	USED(nsid);
17828ccd4a63SDavid du Colombier 
17838ccd4a63SDavid du Colombier 	memmove(sec->srandom, srandom, RandomSize);
17848ccd4a63SDavid du Colombier 
17858ccd4a63SDavid du Colombier 	if(setVers(sec, vers) < 0)
17868ccd4a63SDavid du Colombier 		goto Err;
17878ccd4a63SDavid du Colombier 
17888ccd4a63SDavid du Colombier 	pub = X509toRSApub(cert, ncert, nil, 0);
17898ccd4a63SDavid du Colombier 	if(pub == nil){
17908ccd4a63SDavid du Colombier 		werrstr("invalid x509/rsa certificate");
17918ccd4a63SDavid du Colombier 		goto Err;
17928ccd4a63SDavid du Colombier 	}
17938ccd4a63SDavid du Colombier 	if(clientMasterSecret(sec, pub, epm, nepm) < 0)
17948ccd4a63SDavid du Colombier 		goto Err;
17958ccd4a63SDavid du Colombier 	rsapubfree(pub);
17968ccd4a63SDavid du Colombier 	setSecrets(sec, kd, nkd);
17978ccd4a63SDavid du Colombier 	return 0;
17988ccd4a63SDavid du Colombier 
17998ccd4a63SDavid du Colombier Err:
18008ccd4a63SDavid du Colombier 	if(pub != nil)
18018ccd4a63SDavid du Colombier 		rsapubfree(pub);
18028ccd4a63SDavid du Colombier 	sec->ok = -1;
18038ccd4a63SDavid du Colombier 	return -1;
18048ccd4a63SDavid du Colombier }
18058ccd4a63SDavid du Colombier 
18068ccd4a63SDavid du Colombier static int
tlsSecFinished(TlsSec * sec,MD5state md5,SHAstate sha1,uchar * fin,int nfin,int isclient)18078ccd4a63SDavid du Colombier tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient)
18088ccd4a63SDavid du Colombier {
18098ccd4a63SDavid du Colombier 	if(sec->nfin != nfin){
18108ccd4a63SDavid du Colombier 		sec->ok = -1;
18118ccd4a63SDavid du Colombier 		werrstr("invalid finished exchange");
18128ccd4a63SDavid du Colombier 		return -1;
18138ccd4a63SDavid du Colombier 	}
18148ccd4a63SDavid du Colombier 	md5.malloced = 0;
18158ccd4a63SDavid du Colombier 	sha1.malloced = 0;
18168ccd4a63SDavid du Colombier 	(*sec->setFinished)(sec, md5, sha1, fin, isclient);
18178ccd4a63SDavid du Colombier 	return 1;
18188ccd4a63SDavid du Colombier }
18198ccd4a63SDavid du Colombier 
18208ccd4a63SDavid du Colombier static void
tlsSecOk(TlsSec * sec)18218ccd4a63SDavid du Colombier tlsSecOk(TlsSec *sec)
18228ccd4a63SDavid du Colombier {
18238ccd4a63SDavid du Colombier 	if(sec->ok == 0)
18248ccd4a63SDavid du Colombier 		sec->ok = 1;
18258ccd4a63SDavid du Colombier }
18268ccd4a63SDavid du Colombier 
18278ccd4a63SDavid du Colombier static void
tlsSecKill(TlsSec * sec)18288ccd4a63SDavid du Colombier tlsSecKill(TlsSec *sec)
18298ccd4a63SDavid du Colombier {
18308ccd4a63SDavid du Colombier 	if(!sec)
18318ccd4a63SDavid du Colombier 		return;
18328ccd4a63SDavid du Colombier 	factotum_rsa_close(sec->rpc);
18338ccd4a63SDavid du Colombier 	sec->ok = -1;
18348ccd4a63SDavid du Colombier }
18358ccd4a63SDavid du Colombier 
18368ccd4a63SDavid du Colombier static void
tlsSecClose(TlsSec * sec)18378ccd4a63SDavid du Colombier tlsSecClose(TlsSec *sec)
18388ccd4a63SDavid du Colombier {
18398ccd4a63SDavid du Colombier 	if(!sec)
18408ccd4a63SDavid du Colombier 		return;
18418ccd4a63SDavid du Colombier 	factotum_rsa_close(sec->rpc);
18428ccd4a63SDavid du Colombier 	free(sec->server);
18438ccd4a63SDavid du Colombier 	free(sec);
18448ccd4a63SDavid du Colombier }
18458ccd4a63SDavid du Colombier 
18468ccd4a63SDavid du Colombier static int
setVers(TlsSec * sec,int v)18478ccd4a63SDavid du Colombier setVers(TlsSec *sec, int v)
18488ccd4a63SDavid du Colombier {
18498ccd4a63SDavid du Colombier 	if(v == SSL3Version){
18508ccd4a63SDavid du Colombier 		sec->setFinished = sslSetFinished;
18518ccd4a63SDavid du Colombier 		sec->nfin = SSL3FinishedLen;
18528ccd4a63SDavid du Colombier 		sec->prf = sslPRF;
18538ccd4a63SDavid du Colombier 	}else if(v == TLSVersion){
18548ccd4a63SDavid du Colombier 		sec->setFinished = tlsSetFinished;
18558ccd4a63SDavid du Colombier 		sec->nfin = TLSFinishedLen;
18568ccd4a63SDavid du Colombier 		sec->prf = tlsPRF;
18578ccd4a63SDavid du Colombier 	}else{
18588ccd4a63SDavid du Colombier 		werrstr("invalid version");
18598ccd4a63SDavid du Colombier 		return -1;
18608ccd4a63SDavid du Colombier 	}
18618ccd4a63SDavid du Colombier 	sec->vers = v;
18628ccd4a63SDavid du Colombier 	return 0;
18638ccd4a63SDavid du Colombier }
18648ccd4a63SDavid du Colombier 
18658ccd4a63SDavid du Colombier /*
18668ccd4a63SDavid du Colombier  * generate secret keys from the master secret.
18678ccd4a63SDavid du Colombier  *
18688ccd4a63SDavid du Colombier  * different crypto selections will require different amounts
18698ccd4a63SDavid du Colombier  * of key expansion and use of key expansion data,
18708ccd4a63SDavid du Colombier  * but it's all generated using the same function.
18718ccd4a63SDavid du Colombier  */
18728ccd4a63SDavid du Colombier static void
setSecrets(TlsSec * sec,uchar * kd,int nkd)18738ccd4a63SDavid du Colombier setSecrets(TlsSec *sec, uchar *kd, int nkd)
18748ccd4a63SDavid du Colombier {
18758ccd4a63SDavid du Colombier 	(*sec->prf)(kd, nkd, sec->sec, MasterSecretSize, "key expansion",
18768ccd4a63SDavid du Colombier 			sec->srandom, RandomSize, sec->crandom, RandomSize);
18778ccd4a63SDavid du Colombier }
18788ccd4a63SDavid du Colombier 
18798ccd4a63SDavid du Colombier /*
18808ccd4a63SDavid du Colombier  * set the master secret from the pre-master secret.
18818ccd4a63SDavid du Colombier  */
18828ccd4a63SDavid du Colombier static void
setMasterSecret(TlsSec * sec,Bytes * pm)18838ccd4a63SDavid du Colombier setMasterSecret(TlsSec *sec, Bytes *pm)
18848ccd4a63SDavid du Colombier {
18858ccd4a63SDavid du Colombier 	(*sec->prf)(sec->sec, MasterSecretSize, pm->data, MasterSecretSize, "master secret",
18868ccd4a63SDavid du Colombier 			sec->crandom, RandomSize, sec->srandom, RandomSize);
18878ccd4a63SDavid du Colombier }
18888ccd4a63SDavid du Colombier 
18898ccd4a63SDavid du Colombier static void
serverMasterSecret(TlsSec * sec,uchar * epm,int nepm)18908ccd4a63SDavid du Colombier serverMasterSecret(TlsSec *sec, uchar *epm, int nepm)
18918ccd4a63SDavid du Colombier {
18928ccd4a63SDavid du Colombier 	Bytes *pm;
18938ccd4a63SDavid du Colombier 
18948ccd4a63SDavid du Colombier 	pm = pkcs1_decrypt(sec, epm, nepm);
18958ccd4a63SDavid du Colombier 
18968ccd4a63SDavid du Colombier 	// if the client messed up, just continue as if everything is ok,
18978ccd4a63SDavid du Colombier 	// to prevent attacks to check for correctly formatted messages.
18988ccd4a63SDavid du Colombier 	// Hence the fprint(2,) can't be replaced by tlsError(), which sends an Alert msg to the client.
18998ccd4a63SDavid du Colombier 	if(sec->ok < 0 || pm == nil || get16(pm->data) != sec->clientVers){
19008ccd4a63SDavid du Colombier 		fprint(2, "serverMasterSecret failed ok=%d pm=%p pmvers=%x cvers=%x nepm=%d\n",
19018ccd4a63SDavid du Colombier 			sec->ok, pm, pm ? get16(pm->data) : -1, sec->clientVers, nepm);
19028ccd4a63SDavid du Colombier 		sec->ok = -1;
19038ccd4a63SDavid du Colombier 		if(pm != nil)
19048ccd4a63SDavid du Colombier 			freebytes(pm);
19058ccd4a63SDavid du Colombier 		pm = newbytes(MasterSecretSize);
19068ccd4a63SDavid du Colombier 		genrandom(pm->data, MasterSecretSize);
19078ccd4a63SDavid du Colombier 	}
19088ccd4a63SDavid du Colombier 	setMasterSecret(sec, pm);
19098ccd4a63SDavid du Colombier 	memset(pm->data, 0, pm->len);
19108ccd4a63SDavid du Colombier 	freebytes(pm);
19118ccd4a63SDavid du Colombier }
19128ccd4a63SDavid du Colombier 
19138ccd4a63SDavid du Colombier static int
clientMasterSecret(TlsSec * sec,RSApub * pub,uchar ** epm,int * nepm)19148ccd4a63SDavid du Colombier clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm)
19158ccd4a63SDavid du Colombier {
19168ccd4a63SDavid du Colombier 	Bytes *pm, *key;
19178ccd4a63SDavid du Colombier 
19188ccd4a63SDavid du Colombier 	pm = newbytes(MasterSecretSize);
19198ccd4a63SDavid du Colombier 	put16(pm->data, sec->clientVers);
19208ccd4a63SDavid du Colombier 	genrandom(pm->data+2, MasterSecretSize - 2);
19218ccd4a63SDavid du Colombier 
19228ccd4a63SDavid du Colombier 	setMasterSecret(sec, pm);
19238ccd4a63SDavid du Colombier 
19248ccd4a63SDavid du Colombier 	key = pkcs1_encrypt(pm, pub, 2);
19258ccd4a63SDavid du Colombier 	memset(pm->data, 0, pm->len);
19268ccd4a63SDavid du Colombier 	freebytes(pm);
19278ccd4a63SDavid du Colombier 	if(key == nil){
19288ccd4a63SDavid du Colombier 		werrstr("tls pkcs1_encrypt failed");
19298ccd4a63SDavid du Colombier 		return -1;
19308ccd4a63SDavid du Colombier 	}
19318ccd4a63SDavid du Colombier 
19328ccd4a63SDavid du Colombier 	*nepm = key->len;
19338ccd4a63SDavid du Colombier 	*epm = malloc(*nepm);
19348ccd4a63SDavid du Colombier 	if(*epm == nil){
19358ccd4a63SDavid du Colombier 		freebytes(key);
19368ccd4a63SDavid du Colombier 		werrstr("out of memory");
19378ccd4a63SDavid du Colombier 		return -1;
19388ccd4a63SDavid du Colombier 	}
19398ccd4a63SDavid du Colombier 	memmove(*epm, key->data, *nepm);
19408ccd4a63SDavid du Colombier 
19418ccd4a63SDavid du Colombier 	freebytes(key);
19428ccd4a63SDavid du Colombier 
19438ccd4a63SDavid du Colombier 	return 1;
19448ccd4a63SDavid du Colombier }
19458ccd4a63SDavid du Colombier 
19468ccd4a63SDavid du Colombier static void
sslSetFinished(TlsSec * sec,MD5state hsmd5,SHAstate hssha1,uchar * finished,int isClient)19478ccd4a63SDavid du Colombier sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
19488ccd4a63SDavid du Colombier {
19498ccd4a63SDavid du Colombier 	DigestState *s;
19508ccd4a63SDavid du Colombier 	uchar h0[MD5dlen], h1[SHA1dlen], pad[48];
19518ccd4a63SDavid du Colombier 	char *label;
19528ccd4a63SDavid du Colombier 
19538ccd4a63SDavid du Colombier 	if(isClient)
19548ccd4a63SDavid du Colombier 		label = "CLNT";
19558ccd4a63SDavid du Colombier 	else
19568ccd4a63SDavid du Colombier 		label = "SRVR";
19578ccd4a63SDavid du Colombier 
19588ccd4a63SDavid du Colombier 	md5((uchar*)label, 4, nil, &hsmd5);
19598ccd4a63SDavid du Colombier 	md5(sec->sec, MasterSecretSize, nil, &hsmd5);
19608ccd4a63SDavid du Colombier 	memset(pad, 0x36, 48);
19618ccd4a63SDavid du Colombier 	md5(pad, 48, nil, &hsmd5);
19628ccd4a63SDavid du Colombier 	md5(nil, 0, h0, &hsmd5);
19638ccd4a63SDavid du Colombier 	memset(pad, 0x5C, 48);
19648ccd4a63SDavid du Colombier 	s = md5(sec->sec, MasterSecretSize, nil, nil);
19658ccd4a63SDavid du Colombier 	s = md5(pad, 48, nil, s);
19668ccd4a63SDavid du Colombier 	md5(h0, MD5dlen, finished, s);
19678ccd4a63SDavid du Colombier 
19688ccd4a63SDavid du Colombier 	sha1((uchar*)label, 4, nil, &hssha1);
19698ccd4a63SDavid du Colombier 	sha1(sec->sec, MasterSecretSize, nil, &hssha1);
19708ccd4a63SDavid du Colombier 	memset(pad, 0x36, 40);
19718ccd4a63SDavid du Colombier 	sha1(pad, 40, nil, &hssha1);
19728ccd4a63SDavid du Colombier 	sha1(nil, 0, h1, &hssha1);
19738ccd4a63SDavid du Colombier 	memset(pad, 0x5C, 40);
19748ccd4a63SDavid du Colombier 	s = sha1(sec->sec, MasterSecretSize, nil, nil);
19758ccd4a63SDavid du Colombier 	s = sha1(pad, 40, nil, s);
19768ccd4a63SDavid du Colombier 	sha1(h1, SHA1dlen, finished + MD5dlen, s);
19778ccd4a63SDavid du Colombier }
19788ccd4a63SDavid du Colombier 
19798ccd4a63SDavid du Colombier // fill "finished" arg with md5(args)^sha1(args)
19808ccd4a63SDavid du Colombier static void
tlsSetFinished(TlsSec * sec,MD5state hsmd5,SHAstate hssha1,uchar * finished,int isClient)19818ccd4a63SDavid du Colombier tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
19828ccd4a63SDavid du Colombier {
19838ccd4a63SDavid du Colombier 	uchar h0[MD5dlen], h1[SHA1dlen];
19848ccd4a63SDavid du Colombier 	char *label;
19858ccd4a63SDavid du Colombier 
19868ccd4a63SDavid du Colombier 	// get current hash value, but allow further messages to be hashed in
19878ccd4a63SDavid du Colombier 	md5(nil, 0, h0, &hsmd5);
19888ccd4a63SDavid du Colombier 	sha1(nil, 0, h1, &hssha1);
19898ccd4a63SDavid du Colombier 
19908ccd4a63SDavid du Colombier 	if(isClient)
19918ccd4a63SDavid du Colombier 		label = "client finished";
19928ccd4a63SDavid du Colombier 	else
19938ccd4a63SDavid du Colombier 		label = "server finished";
19948ccd4a63SDavid du Colombier 	tlsPRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen);
19958ccd4a63SDavid du Colombier }
19968ccd4a63SDavid du Colombier 
19978ccd4a63SDavid du Colombier static void
sslPRF(uchar * buf,int nbuf,uchar * key,int nkey,char * label,uchar * seed0,int nseed0,uchar * seed1,int nseed1)19988ccd4a63SDavid du Colombier sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
19998ccd4a63SDavid du Colombier {
20008ccd4a63SDavid du Colombier 	DigestState *s;
20018ccd4a63SDavid du Colombier 	uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26];
20028ccd4a63SDavid du Colombier 	int i, n, len;
20038ccd4a63SDavid du Colombier 
20048ccd4a63SDavid du Colombier 	USED(label);
20058ccd4a63SDavid du Colombier 	len = 1;
20068ccd4a63SDavid du Colombier 	while(nbuf > 0){
20078ccd4a63SDavid du Colombier 		if(len > 26)
20088ccd4a63SDavid du Colombier 			return;
20098ccd4a63SDavid du Colombier 		for(i = 0; i < len; i++)
20108ccd4a63SDavid du Colombier 			tmp[i] = 'A' - 1 + len;
20118ccd4a63SDavid du Colombier 		s = sha1(tmp, len, nil, nil);
20128ccd4a63SDavid du Colombier 		s = sha1(key, nkey, nil, s);
20138ccd4a63SDavid du Colombier 		s = sha1(seed0, nseed0, nil, s);
20148ccd4a63SDavid du Colombier 		sha1(seed1, nseed1, sha1dig, s);
20158ccd4a63SDavid du Colombier 		s = md5(key, nkey, nil, nil);
20168ccd4a63SDavid du Colombier 		md5(sha1dig, SHA1dlen, md5dig, s);
20178ccd4a63SDavid du Colombier 		n = MD5dlen;
20188ccd4a63SDavid du Colombier 		if(n > nbuf)
20198ccd4a63SDavid du Colombier 			n = nbuf;
20208ccd4a63SDavid du Colombier 		memmove(buf, md5dig, n);
20218ccd4a63SDavid du Colombier 		buf += n;
20228ccd4a63SDavid du Colombier 		nbuf -= n;
20238ccd4a63SDavid du Colombier 		len++;
20248ccd4a63SDavid du Colombier 	}
20258ccd4a63SDavid du Colombier }
20268ccd4a63SDavid du Colombier 
20278ccd4a63SDavid du Colombier static mpint*
bytestomp(Bytes * bytes)20288ccd4a63SDavid du Colombier bytestomp(Bytes* bytes)
20298ccd4a63SDavid du Colombier {
20308ccd4a63SDavid du Colombier 	mpint* ans;
20318ccd4a63SDavid du Colombier 
20328ccd4a63SDavid du Colombier 	ans = betomp(bytes->data, bytes->len, nil);
20338ccd4a63SDavid du Colombier 	return ans;
20348ccd4a63SDavid du Colombier }
20358ccd4a63SDavid du Colombier 
20368ccd4a63SDavid du Colombier /*
20378ccd4a63SDavid du Colombier  * Convert mpint* to Bytes, putting high order byte first.
20388ccd4a63SDavid du Colombier  */
20398ccd4a63SDavid du Colombier static Bytes*
mptobytes(mpint * big)20408ccd4a63SDavid du Colombier mptobytes(mpint* big)
20418ccd4a63SDavid du Colombier {
20428ccd4a63SDavid du Colombier 	int n, m;
20438ccd4a63SDavid du Colombier 	uchar *a;
20448ccd4a63SDavid du Colombier 	Bytes* ans;
20458ccd4a63SDavid du Colombier 
20468ccd4a63SDavid du Colombier 	n = (mpsignif(big)+7)/8;
20478ccd4a63SDavid du Colombier 	m = mptobe(big, nil, n, &a);
20488ccd4a63SDavid du Colombier 	ans = makebytes(a, m);
20498ccd4a63SDavid du Colombier 	return ans;
20508ccd4a63SDavid du Colombier }
20518ccd4a63SDavid du Colombier 
20528ccd4a63SDavid du Colombier // Do RSA computation on block according to key, and pad
20538ccd4a63SDavid du Colombier // result on left with zeros to make it modlen long.
20548ccd4a63SDavid du Colombier static Bytes*
rsacomp(Bytes * block,RSApub * key,int modlen)20558ccd4a63SDavid du Colombier rsacomp(Bytes* block, RSApub* key, int modlen)
20568ccd4a63SDavid du Colombier {
20578ccd4a63SDavid du Colombier 	mpint *x, *y;
20588ccd4a63SDavid du Colombier 	Bytes *a, *ybytes;
20598ccd4a63SDavid du Colombier 	int ylen;
20608ccd4a63SDavid du Colombier 
20618ccd4a63SDavid du Colombier 	x = bytestomp(block);
20628ccd4a63SDavid du Colombier 	y = rsaencrypt(key, x, nil);
20638ccd4a63SDavid du Colombier 	mpfree(x);
20648ccd4a63SDavid du Colombier 	ybytes = mptobytes(y);
20658ccd4a63SDavid du Colombier 	ylen = ybytes->len;
20668ccd4a63SDavid du Colombier 
20678ccd4a63SDavid du Colombier 	if(ylen < modlen) {
20688ccd4a63SDavid du Colombier 		a = newbytes(modlen);
20698ccd4a63SDavid du Colombier 		memset(a->data, 0, modlen-ylen);
20708ccd4a63SDavid du Colombier 		memmove(a->data+modlen-ylen, ybytes->data, ylen);
20718ccd4a63SDavid du Colombier 		freebytes(ybytes);
20728ccd4a63SDavid du Colombier 		ybytes = a;
20738ccd4a63SDavid du Colombier 	}
20748ccd4a63SDavid du Colombier 	else if(ylen > modlen) {
20758ccd4a63SDavid du Colombier 		// assume it has leading zeros (mod should make it so)
20768ccd4a63SDavid du Colombier 		a = newbytes(modlen);
20778ccd4a63SDavid du Colombier 		memmove(a->data, ybytes->data, modlen);
20788ccd4a63SDavid du Colombier 		freebytes(ybytes);
20798ccd4a63SDavid du Colombier 		ybytes = a;
20808ccd4a63SDavid du Colombier 	}
20818ccd4a63SDavid du Colombier 	mpfree(y);
20828ccd4a63SDavid du Colombier 	return ybytes;
20838ccd4a63SDavid du Colombier }
20848ccd4a63SDavid du Colombier 
20858ccd4a63SDavid du Colombier // encrypt data according to PKCS#1, /lib/rfc/rfc2437 9.1.2.1
20868ccd4a63SDavid du Colombier static Bytes*
pkcs1_encrypt(Bytes * data,RSApub * key,int blocktype)20878ccd4a63SDavid du Colombier pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype)
20888ccd4a63SDavid du Colombier {
20898ccd4a63SDavid du Colombier 	Bytes *pad, *eb, *ans;
20908ccd4a63SDavid du Colombier 	int i, dlen, padlen, modlen;
20918ccd4a63SDavid du Colombier 
20928ccd4a63SDavid du Colombier 	modlen = (mpsignif(key->n)+7)/8;
20938ccd4a63SDavid du Colombier 	dlen = data->len;
20948ccd4a63SDavid du Colombier 	if(modlen < 12 || dlen > modlen - 11)
20958ccd4a63SDavid du Colombier 		return nil;
20968ccd4a63SDavid du Colombier 	padlen = modlen - 3 - dlen;
20978ccd4a63SDavid du Colombier 	pad = newbytes(padlen);
20988ccd4a63SDavid du Colombier 	genrandom(pad->data, padlen);
20998ccd4a63SDavid du Colombier 	for(i = 0; i < padlen; i++) {
21008ccd4a63SDavid du Colombier 		if(blocktype == 0)
21018ccd4a63SDavid du Colombier 			pad->data[i] = 0;
21028ccd4a63SDavid du Colombier 		else if(blocktype == 1)
21038ccd4a63SDavid du Colombier 			pad->data[i] = 255;
21048ccd4a63SDavid du Colombier 		else if(pad->data[i] == 0)
21058ccd4a63SDavid du Colombier 			pad->data[i] = 1;
21068ccd4a63SDavid du Colombier 	}
21078ccd4a63SDavid du Colombier 	eb = newbytes(modlen);
21088ccd4a63SDavid du Colombier 	eb->data[0] = 0;
21098ccd4a63SDavid du Colombier 	eb->data[1] = blocktype;
21108ccd4a63SDavid du Colombier 	memmove(eb->data+2, pad->data, padlen);
21118ccd4a63SDavid du Colombier 	eb->data[padlen+2] = 0;
21128ccd4a63SDavid du Colombier 	memmove(eb->data+padlen+3, data->data, dlen);
21138ccd4a63SDavid du Colombier 	ans = rsacomp(eb, key, modlen);
21148ccd4a63SDavid du Colombier 	freebytes(eb);
21158ccd4a63SDavid du Colombier 	freebytes(pad);
21168ccd4a63SDavid du Colombier 	return ans;
21178ccd4a63SDavid du Colombier }
21188ccd4a63SDavid du Colombier 
21198ccd4a63SDavid du Colombier // decrypt data according to PKCS#1, with given key.
21208ccd4a63SDavid du Colombier // expect a block type of 2.
21218ccd4a63SDavid du Colombier static Bytes*
pkcs1_decrypt(TlsSec * sec,uchar * epm,int nepm)21228ccd4a63SDavid du Colombier pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm)
21238ccd4a63SDavid du Colombier {
21248ccd4a63SDavid du Colombier 	Bytes *eb, *ans = nil;
21258ccd4a63SDavid du Colombier 	int i, modlen;
21268ccd4a63SDavid du Colombier 	mpint *x, *y;
21278ccd4a63SDavid du Colombier 
21288ccd4a63SDavid du Colombier 	modlen = (mpsignif(sec->rsapub->n)+7)/8;
21298ccd4a63SDavid du Colombier 	if(nepm != modlen)
21308ccd4a63SDavid du Colombier 		return nil;
21318ccd4a63SDavid du Colombier 	x = betomp(epm, nepm, nil);
21328ccd4a63SDavid du Colombier 	y = factotum_rsa_decrypt(sec->rpc, x);
21338ccd4a63SDavid du Colombier 	if(y == nil)
21348ccd4a63SDavid du Colombier 		return nil;
21358ccd4a63SDavid du Colombier 	eb = mptobytes(y);
21368ccd4a63SDavid du Colombier 	if(eb->len < modlen){ // pad on left with zeros
21378ccd4a63SDavid du Colombier 		ans = newbytes(modlen);
21388ccd4a63SDavid du Colombier 		memset(ans->data, 0, modlen-eb->len);
21398ccd4a63SDavid du Colombier 		memmove(ans->data+modlen-eb->len, eb->data, eb->len);
21408ccd4a63SDavid du Colombier 		freebytes(eb);
21418ccd4a63SDavid du Colombier 		eb = ans;
21428ccd4a63SDavid du Colombier 	}
21438ccd4a63SDavid du Colombier 	if(eb->data[0] == 0 && eb->data[1] == 2) {
21448ccd4a63SDavid du Colombier 		for(i = 2; i < modlen; i++)
21458ccd4a63SDavid du Colombier 			if(eb->data[i] == 0)
21468ccd4a63SDavid du Colombier 				break;
21478ccd4a63SDavid du Colombier 		if(i < modlen - 1)
21488ccd4a63SDavid du Colombier 			ans = makebytes(eb->data+i+1, modlen-(i+1));
21498ccd4a63SDavid du Colombier 	}
21508ccd4a63SDavid du Colombier 	freebytes(eb);
21518ccd4a63SDavid du Colombier 	return ans;
21528ccd4a63SDavid du Colombier }
21538ccd4a63SDavid du Colombier 
21548ccd4a63SDavid du Colombier 
21558ccd4a63SDavid du Colombier //================= general utility functions ========================
21568ccd4a63SDavid du Colombier 
21578ccd4a63SDavid du Colombier static void *
emalloc(int n)21588ccd4a63SDavid du Colombier emalloc(int n)
21598ccd4a63SDavid du Colombier {
21608ccd4a63SDavid du Colombier 	void *p;
21618ccd4a63SDavid du Colombier 	if(n==0)
21628ccd4a63SDavid du Colombier 		n=1;
21638ccd4a63SDavid du Colombier 	p = malloc(n);
21648ccd4a63SDavid du Colombier 	if(p == nil){
21658ccd4a63SDavid du Colombier 		exits("out of memory");
21668ccd4a63SDavid du Colombier 	}
21678ccd4a63SDavid du Colombier 	memset(p, 0, n);
21688ccd4a63SDavid du Colombier 	return p;
21698ccd4a63SDavid du Colombier }
21708ccd4a63SDavid du Colombier 
21718ccd4a63SDavid du Colombier static void *
erealloc(void * ReallocP,int ReallocN)21728ccd4a63SDavid du Colombier erealloc(void *ReallocP, int ReallocN)
21738ccd4a63SDavid du Colombier {
21748ccd4a63SDavid du Colombier 	if(ReallocN == 0)
21758ccd4a63SDavid du Colombier 		ReallocN = 1;
21768ccd4a63SDavid du Colombier 	if(!ReallocP)
21778ccd4a63SDavid du Colombier 		ReallocP = emalloc(ReallocN);
21788ccd4a63SDavid du Colombier 	else if(!(ReallocP = realloc(ReallocP, ReallocN))){
21798ccd4a63SDavid du Colombier 		exits("out of memory");
21808ccd4a63SDavid du Colombier 	}
21818ccd4a63SDavid du Colombier 	return(ReallocP);
21828ccd4a63SDavid du Colombier }
21838ccd4a63SDavid du Colombier 
21848ccd4a63SDavid du Colombier static void
put32(uchar * p,u32int x)21858ccd4a63SDavid du Colombier put32(uchar *p, u32int x)
21868ccd4a63SDavid du Colombier {
21878ccd4a63SDavid du Colombier 	p[0] = x>>24;
21888ccd4a63SDavid du Colombier 	p[1] = x>>16;
21898ccd4a63SDavid du Colombier 	p[2] = x>>8;
21908ccd4a63SDavid du Colombier 	p[3] = x;
21918ccd4a63SDavid du Colombier }
21928ccd4a63SDavid du Colombier 
21938ccd4a63SDavid du Colombier static void
put24(uchar * p,int x)21948ccd4a63SDavid du Colombier put24(uchar *p, int x)
21958ccd4a63SDavid du Colombier {
21968ccd4a63SDavid du Colombier 	p[0] = x>>16;
21978ccd4a63SDavid du Colombier 	p[1] = x>>8;
21988ccd4a63SDavid du Colombier 	p[2] = x;
21998ccd4a63SDavid du Colombier }
22008ccd4a63SDavid du Colombier 
22018ccd4a63SDavid du Colombier static void
put16(uchar * p,int x)22028ccd4a63SDavid du Colombier put16(uchar *p, int x)
22038ccd4a63SDavid du Colombier {
22048ccd4a63SDavid du Colombier 	p[0] = x>>8;
22058ccd4a63SDavid du Colombier 	p[1] = x;
22068ccd4a63SDavid du Colombier }
22078ccd4a63SDavid du Colombier 
22088ccd4a63SDavid du Colombier static u32int
get32(uchar * p)22098ccd4a63SDavid du Colombier get32(uchar *p)
22108ccd4a63SDavid du Colombier {
22118ccd4a63SDavid du Colombier 	return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
22128ccd4a63SDavid du Colombier }
22138ccd4a63SDavid du Colombier 
22148ccd4a63SDavid du Colombier static int
get24(uchar * p)22158ccd4a63SDavid du Colombier get24(uchar *p)
22168ccd4a63SDavid du Colombier {
22178ccd4a63SDavid du Colombier 	return (p[0]<<16)|(p[1]<<8)|p[2];
22188ccd4a63SDavid du Colombier }
22198ccd4a63SDavid du Colombier 
22208ccd4a63SDavid du Colombier static int
get16(uchar * p)22218ccd4a63SDavid du Colombier get16(uchar *p)
22228ccd4a63SDavid du Colombier {
22238ccd4a63SDavid du Colombier 	return (p[0]<<8)|p[1];
22248ccd4a63SDavid du Colombier }
22258ccd4a63SDavid du Colombier 
22268ccd4a63SDavid du Colombier /* ANSI offsetof() */
22278ccd4a63SDavid du Colombier #define OFFSET(x, s) ((int)(&(((s*)0)->x)))
22288ccd4a63SDavid du Colombier 
22298ccd4a63SDavid du Colombier /*
22308ccd4a63SDavid du Colombier  * malloc and return a new Bytes structure capable of
22318ccd4a63SDavid du Colombier  * holding len bytes. (len >= 0)
22328ccd4a63SDavid du Colombier  * Used to use crypt_malloc, which aborts if malloc fails.
22338ccd4a63SDavid du Colombier  */
22348ccd4a63SDavid du Colombier static Bytes*
newbytes(int len)22358ccd4a63SDavid du Colombier newbytes(int len)
22368ccd4a63SDavid du Colombier {
22378ccd4a63SDavid du Colombier 	Bytes* ans;
22388ccd4a63SDavid du Colombier 
22398ccd4a63SDavid du Colombier 	ans = (Bytes*)malloc(OFFSET(data[0], Bytes) + len);
22408ccd4a63SDavid du Colombier 	ans->len = len;
22418ccd4a63SDavid du Colombier 	return ans;
22428ccd4a63SDavid du Colombier }
22438ccd4a63SDavid du Colombier 
22448ccd4a63SDavid du Colombier /*
22458ccd4a63SDavid du Colombier  * newbytes(len), with data initialized from buf
22468ccd4a63SDavid du Colombier  */
22478ccd4a63SDavid du Colombier static Bytes*
makebytes(uchar * buf,int len)22488ccd4a63SDavid du Colombier makebytes(uchar* buf, int len)
22498ccd4a63SDavid du Colombier {
22508ccd4a63SDavid du Colombier 	Bytes* ans;
22518ccd4a63SDavid du Colombier 
22528ccd4a63SDavid du Colombier 	ans = newbytes(len);
22538ccd4a63SDavid du Colombier 	memmove(ans->data, buf, len);
22548ccd4a63SDavid du Colombier 	return ans;
22558ccd4a63SDavid du Colombier }
22568ccd4a63SDavid du Colombier 
22578ccd4a63SDavid du Colombier static void
freebytes(Bytes * b)22588ccd4a63SDavid du Colombier freebytes(Bytes* b)
22598ccd4a63SDavid du Colombier {
22608ccd4a63SDavid du Colombier 	if(b != nil)
22618ccd4a63SDavid du Colombier 		free(b);
22628ccd4a63SDavid du Colombier }
22638ccd4a63SDavid du Colombier 
22648ccd4a63SDavid du Colombier /* len is number of ints */
22658ccd4a63SDavid du Colombier static Ints*
newints(int len)22668ccd4a63SDavid du Colombier newints(int len)
22678ccd4a63SDavid du Colombier {
22688ccd4a63SDavid du Colombier 	Ints* ans;
22698ccd4a63SDavid du Colombier 
22708ccd4a63SDavid du Colombier 	ans = (Ints*)malloc(OFFSET(data[0], Ints) + len*sizeof(int));
22718ccd4a63SDavid du Colombier 	ans->len = len;
22728ccd4a63SDavid du Colombier 	return ans;
22738ccd4a63SDavid du Colombier }
22748ccd4a63SDavid du Colombier 
22758ccd4a63SDavid du Colombier static Ints*
makeints(int * buf,int len)22768ccd4a63SDavid du Colombier makeints(int* buf, int len)
22778ccd4a63SDavid du Colombier {
22788ccd4a63SDavid du Colombier 	Ints* ans;
22798ccd4a63SDavid du Colombier 
22808ccd4a63SDavid du Colombier 	ans = newints(len);
22818ccd4a63SDavid du Colombier 	if(len > 0)
22828ccd4a63SDavid du Colombier 		memmove(ans->data, buf, len*sizeof(int));
22838ccd4a63SDavid du Colombier 	return ans;
22848ccd4a63SDavid du Colombier }
22858ccd4a63SDavid du Colombier 
22868ccd4a63SDavid du Colombier static void
freeints(Ints * b)22878ccd4a63SDavid du Colombier freeints(Ints* b)
22888ccd4a63SDavid du Colombier {
22898ccd4a63SDavid du Colombier 	if(b != nil)
22908ccd4a63SDavid du Colombier 		free(b);
22918ccd4a63SDavid du Colombier }
2292