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