19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
59a747e4fSDavid du Colombier #include <mp.h>
69a747e4fSDavid du Colombier #include <libsec.h>
79a747e4fSDavid du Colombier
89a747e4fSDavid du Colombier // The main groups of functions are:
99a747e4fSDavid du Colombier // client/server - main handshake protocol definition
109a747e4fSDavid du Colombier // message functions - formating handshake messages
119a747e4fSDavid du Colombier // cipher choices - catalog of digest and encrypt algorithms
129a747e4fSDavid du Colombier // security functions - PKCS#1, sslHMAC, session keygen
139a747e4fSDavid du Colombier // general utility functions - malloc, serialization
149a747e4fSDavid du Colombier // The handshake protocol builds on the TLS/SSL3 record layer protocol,
159a747e4fSDavid du Colombier // which is implemented in kernel device #a. See also /lib/rfc/rfc2246.
169a747e4fSDavid du Colombier
179a747e4fSDavid du Colombier enum {
189a747e4fSDavid du Colombier TLSFinishedLen = 12,
199a747e4fSDavid du Colombier SSL3FinishedLen = MD5dlen+SHA1dlen,
20*ad6ca847SDavid du Colombier MaxKeyData = 136, // amount of secret we may need
219a747e4fSDavid du Colombier MaxChunk = 1<<14,
229a747e4fSDavid du Colombier RandomSize = 32,
239a747e4fSDavid du Colombier SidSize = 32,
249a747e4fSDavid du Colombier MasterSecretSize = 48,
259a747e4fSDavid du Colombier AQueue = 0,
269a747e4fSDavid du Colombier AFlush = 1,
279a747e4fSDavid du Colombier };
289a747e4fSDavid du Colombier
299a747e4fSDavid du Colombier typedef struct TlsSec TlsSec;
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier typedef struct Bytes{
329a747e4fSDavid du Colombier int len;
339a747e4fSDavid du Colombier uchar data[1]; // [len]
349a747e4fSDavid du Colombier } Bytes;
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier typedef struct Ints{
379a747e4fSDavid du Colombier int len;
389a747e4fSDavid du Colombier int data[1]; // [len]
399a747e4fSDavid du Colombier } Ints;
409a747e4fSDavid du Colombier
419a747e4fSDavid du Colombier typedef struct Algs{
429a747e4fSDavid du Colombier char *enc;
439a747e4fSDavid du Colombier char *digest;
449a747e4fSDavid du Colombier int nsecret;
459a747e4fSDavid du Colombier int tlsid;
469a747e4fSDavid du Colombier int ok;
479a747e4fSDavid du Colombier } Algs;
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier typedef struct Finished{
509a747e4fSDavid du Colombier uchar verify[SSL3FinishedLen];
519a747e4fSDavid du Colombier int n;
529a747e4fSDavid du Colombier } Finished;
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier typedef struct TlsConnection{
559a747e4fSDavid du Colombier TlsSec *sec; // security management goo
569a747e4fSDavid du Colombier int hand, ctl; // record layer file descriptors
579a747e4fSDavid du Colombier int erred; // set when tlsError called
589a747e4fSDavid du Colombier int (*trace)(char*fmt, ...); // for debugging
599a747e4fSDavid du Colombier int version; // protocol we are speaking
609a747e4fSDavid du Colombier int verset; // version has been set
619a747e4fSDavid du Colombier int ver2hi; // server got a version 2 hello
629a747e4fSDavid du Colombier int isClient; // is this the client or server?
639a747e4fSDavid du Colombier Bytes *sid; // SessionID
649a747e4fSDavid du Colombier Bytes *cert; // only last - no chain
659a747e4fSDavid du Colombier
669a747e4fSDavid du Colombier Lock statelk;
679a747e4fSDavid du Colombier int state; // must be set using setstate
689a747e4fSDavid du Colombier
699a747e4fSDavid du Colombier // input buffer for handshake messages
709a747e4fSDavid du Colombier uchar buf[MaxChunk+2048];
719a747e4fSDavid du Colombier uchar *rp, *ep;
729a747e4fSDavid du Colombier
739a747e4fSDavid du Colombier uchar crandom[RandomSize]; // client random
749a747e4fSDavid du Colombier uchar srandom[RandomSize]; // server random
759a747e4fSDavid du Colombier int clientVersion; // version in ClientHello
769a747e4fSDavid du Colombier char *digest; // name of digest algorithm to use
779a747e4fSDavid du Colombier char *enc; // name of encryption algorithm to use
789a747e4fSDavid du Colombier int nsecret; // amount of secret data to init keys
799a747e4fSDavid du Colombier
809a747e4fSDavid du Colombier // for finished messages
819a747e4fSDavid du Colombier MD5state hsmd5; // handshake hash
829a747e4fSDavid du Colombier SHAstate hssha1; // handshake hash
839a747e4fSDavid du Colombier Finished finished;
849a747e4fSDavid du Colombier } TlsConnection;
859a747e4fSDavid du Colombier
869a747e4fSDavid du Colombier typedef struct Msg{
879a747e4fSDavid du Colombier int tag;
889a747e4fSDavid du Colombier union {
899a747e4fSDavid du Colombier struct {
909a747e4fSDavid du Colombier int version;
919a747e4fSDavid du Colombier uchar random[RandomSize];
929a747e4fSDavid du Colombier Bytes* sid;
939a747e4fSDavid du Colombier Ints* ciphers;
949a747e4fSDavid du Colombier Bytes* compressors;
959a747e4fSDavid du Colombier } clientHello;
969a747e4fSDavid du Colombier struct {
979a747e4fSDavid du Colombier int version;
989a747e4fSDavid du Colombier uchar random[RandomSize];
999a747e4fSDavid du Colombier Bytes* sid;
1009a747e4fSDavid du Colombier int cipher;
1019a747e4fSDavid du Colombier int compressor;
1029a747e4fSDavid du Colombier } serverHello;
1039a747e4fSDavid du Colombier struct {
1049a747e4fSDavid du Colombier int ncert;
1059a747e4fSDavid du Colombier Bytes **certs;
1069a747e4fSDavid du Colombier } certificate;
1079a747e4fSDavid du Colombier struct {
1089a747e4fSDavid du Colombier Bytes *types;
1099a747e4fSDavid du Colombier int nca;
1109a747e4fSDavid du Colombier Bytes **cas;
1119a747e4fSDavid du Colombier } certificateRequest;
1129a747e4fSDavid du Colombier struct {
1139a747e4fSDavid du Colombier Bytes *key;
1149a747e4fSDavid du Colombier } clientKeyExchange;
1159a747e4fSDavid du Colombier Finished finished;
1169a747e4fSDavid du Colombier } u;
1179a747e4fSDavid du Colombier } Msg;
1189a747e4fSDavid du Colombier
1199a747e4fSDavid du Colombier typedef struct TlsSec{
1209a747e4fSDavid du Colombier char *server; // name of remote; nil for server
1219a747e4fSDavid du Colombier int ok; // <0 killed; == 0 in progress; >0 reusable
1229a747e4fSDavid du Colombier RSApub *rsapub;
1239a747e4fSDavid du Colombier AuthRpc *rpc; // factotum for rsa private key
1249a747e4fSDavid du Colombier uchar sec[MasterSecretSize]; // master secret
1259a747e4fSDavid du Colombier uchar crandom[RandomSize]; // client random
1269a747e4fSDavid du Colombier uchar srandom[RandomSize]; // server random
1279a747e4fSDavid du Colombier int clientVers; // version in ClientHello
1289a747e4fSDavid du Colombier int vers; // final version
1299a747e4fSDavid du Colombier // byte generation and handshake checksum
1309a747e4fSDavid du Colombier void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
1319a747e4fSDavid du Colombier void (*setFinished)(TlsSec*, MD5state, SHAstate, uchar*, int);
1329a747e4fSDavid du Colombier int nfin;
1339a747e4fSDavid du Colombier } TlsSec;
1349a747e4fSDavid du Colombier
1359a747e4fSDavid du Colombier
1369a747e4fSDavid du Colombier enum {
1379a747e4fSDavid du Colombier TLSVersion = 0x0301,
1389a747e4fSDavid du Colombier SSL3Version = 0x0300,
1399a747e4fSDavid du Colombier ProtocolVersion = 0x0301, // maximum version we speak
1409a747e4fSDavid du Colombier MinProtoVersion = 0x0300, // limits on version we accept
1419a747e4fSDavid du Colombier MaxProtoVersion = 0x03ff,
1429a747e4fSDavid du Colombier };
1439a747e4fSDavid du Colombier
1449a747e4fSDavid du Colombier // handshake type
1459a747e4fSDavid du Colombier enum {
1469a747e4fSDavid du Colombier HHelloRequest,
1479a747e4fSDavid du Colombier HClientHello,
1489a747e4fSDavid du Colombier HServerHello,
1499a747e4fSDavid du Colombier HSSL2ClientHello = 9, /* local convention; see devtls.c */
1509a747e4fSDavid du Colombier HCertificate = 11,
1519a747e4fSDavid du Colombier HServerKeyExchange,
1529a747e4fSDavid du Colombier HCertificateRequest,
1539a747e4fSDavid du Colombier HServerHelloDone,
1549a747e4fSDavid du Colombier HCertificateVerify,
1559a747e4fSDavid du Colombier HClientKeyExchange,
1569a747e4fSDavid du Colombier HFinished = 20,
1579a747e4fSDavid du Colombier HMax
1589a747e4fSDavid du Colombier };
1599a747e4fSDavid du Colombier
1609a747e4fSDavid du Colombier // alerts
1619a747e4fSDavid du Colombier enum {
1629a747e4fSDavid du Colombier ECloseNotify = 0,
1639a747e4fSDavid du Colombier EUnexpectedMessage = 10,
1649a747e4fSDavid du Colombier EBadRecordMac = 20,
1659a747e4fSDavid du Colombier EDecryptionFailed = 21,
1669a747e4fSDavid du Colombier ERecordOverflow = 22,
1679a747e4fSDavid du Colombier EDecompressionFailure = 30,
1689a747e4fSDavid du Colombier EHandshakeFailure = 40,
1699a747e4fSDavid du Colombier ENoCertificate = 41,
1709a747e4fSDavid du Colombier EBadCertificate = 42,
1719a747e4fSDavid du Colombier EUnsupportedCertificate = 43,
1729a747e4fSDavid du Colombier ECertificateRevoked = 44,
1739a747e4fSDavid du Colombier ECertificateExpired = 45,
1749a747e4fSDavid du Colombier ECertificateUnknown = 46,
1759a747e4fSDavid du Colombier EIllegalParameter = 47,
1769a747e4fSDavid du Colombier EUnknownCa = 48,
1779a747e4fSDavid du Colombier EAccessDenied = 49,
1789a747e4fSDavid du Colombier EDecodeError = 50,
1799a747e4fSDavid du Colombier EDecryptError = 51,
1809a747e4fSDavid du Colombier EExportRestriction = 60,
1819a747e4fSDavid du Colombier EProtocolVersion = 70,
1829a747e4fSDavid du Colombier EInsufficientSecurity = 71,
1839a747e4fSDavid du Colombier EInternalError = 80,
1849a747e4fSDavid du Colombier EUserCanceled = 90,
1859a747e4fSDavid du Colombier ENoRenegotiation = 100,
1869a747e4fSDavid du Colombier EMax = 256
1879a747e4fSDavid du Colombier };
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier // cipher suites
1909a747e4fSDavid du Colombier enum {
1919a747e4fSDavid du Colombier TLS_NULL_WITH_NULL_NULL = 0x0000,
1929a747e4fSDavid du Colombier TLS_RSA_WITH_NULL_MD5 = 0x0001,
1939a747e4fSDavid du Colombier TLS_RSA_WITH_NULL_SHA = 0x0002,
1949a747e4fSDavid du Colombier TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003,
1959a747e4fSDavid du Colombier TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
1969a747e4fSDavid du Colombier TLS_RSA_WITH_RC4_128_SHA = 0x0005,
1979a747e4fSDavid du Colombier TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0X0006,
1989a747e4fSDavid du Colombier TLS_RSA_WITH_IDEA_CBC_SHA = 0X0007,
1999a747e4fSDavid du Colombier TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0008,
2009a747e4fSDavid du Colombier TLS_RSA_WITH_DES_CBC_SHA = 0X0009,
2019a747e4fSDavid du Colombier TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0X000A,
2029a747e4fSDavid du Colombier TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X000B,
2039a747e4fSDavid du Colombier TLS_DH_DSS_WITH_DES_CBC_SHA = 0X000C,
2049a747e4fSDavid du Colombier TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0X000D,
2059a747e4fSDavid du Colombier TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X000E,
2069a747e4fSDavid du Colombier TLS_DH_RSA_WITH_DES_CBC_SHA = 0X000F,
2079a747e4fSDavid du Colombier TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0X0010,
2089a747e4fSDavid du Colombier TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X0011,
2099a747e4fSDavid du Colombier TLS_DHE_DSS_WITH_DES_CBC_SHA = 0X0012,
2109a747e4fSDavid du Colombier TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0X0013, // ZZZ must be implemented for tls1.0 compliance
2119a747e4fSDavid du Colombier TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0014,
2129a747e4fSDavid du Colombier TLS_DHE_RSA_WITH_DES_CBC_SHA = 0X0015,
2139a747e4fSDavid du Colombier TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0X0016,
2149a747e4fSDavid du Colombier TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017,
2159a747e4fSDavid du Colombier TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018,
2169a747e4fSDavid du Colombier TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0X0019,
2179a747e4fSDavid du Colombier TLS_DH_anon_WITH_DES_CBC_SHA = 0X001A,
2189a747e4fSDavid du Colombier TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0X001B,
2199a747e4fSDavid du Colombier
2209a747e4fSDavid du Colombier TLS_RSA_WITH_AES_128_CBC_SHA = 0X002f, // aes, aka rijndael with 128 bit blocks
2219a747e4fSDavid du Colombier TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0X0030,
2229a747e4fSDavid du Colombier TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0X0031,
2239a747e4fSDavid du Colombier TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0X0032,
2249a747e4fSDavid du Colombier TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0X0033,
2259a747e4fSDavid du Colombier TLS_DH_anon_WITH_AES_128_CBC_SHA = 0X0034,
2269a747e4fSDavid du Colombier TLS_RSA_WITH_AES_256_CBC_SHA = 0X0035,
2279a747e4fSDavid du Colombier TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0X0036,
2289a747e4fSDavid du Colombier TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0X0037,
2299a747e4fSDavid du Colombier TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0X0038,
2309a747e4fSDavid du Colombier TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0X0039,
2319a747e4fSDavid du Colombier TLS_DH_anon_WITH_AES_256_CBC_SHA = 0X003A,
2329a747e4fSDavid du Colombier CipherMax
2339a747e4fSDavid du Colombier };
2349a747e4fSDavid du Colombier
2359a747e4fSDavid du Colombier // compression methods
2369a747e4fSDavid du Colombier enum {
2379a747e4fSDavid du Colombier CompressionNull = 0,
2389a747e4fSDavid du Colombier CompressionMax
2399a747e4fSDavid du Colombier };
2409a747e4fSDavid du Colombier
2419a747e4fSDavid du Colombier static Algs cipherAlgs[] = {
2429a747e4fSDavid du Colombier {"rc4_128", "md5", 2*(16+MD5dlen), TLS_RSA_WITH_RC4_128_MD5},
2439a747e4fSDavid du Colombier {"rc4_128", "sha1", 2*(16+SHA1dlen), TLS_RSA_WITH_RC4_128_SHA},
2449a747e4fSDavid du Colombier {"3des_ede_cbc", "sha1", 2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},
245*ad6ca847SDavid du Colombier {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_RSA_WITH_AES_128_CBC_SHA},
246*ad6ca847SDavid du Colombier {"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_RSA_WITH_AES_256_CBC_SHA}
2479a747e4fSDavid du Colombier };
2489a747e4fSDavid du Colombier
2499a747e4fSDavid du Colombier static uchar compressors[] = {
2509a747e4fSDavid du Colombier CompressionNull,
2519a747e4fSDavid du Colombier };
2529a747e4fSDavid du Colombier
25351711cb6SDavid du Colombier static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chain);
2549a747e4fSDavid du Colombier static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...));
2559a747e4fSDavid du Colombier
2569a747e4fSDavid du Colombier static void msgClear(Msg *m);
2579a747e4fSDavid du Colombier static char* msgPrint(char *buf, int n, Msg *m);
2589a747e4fSDavid du Colombier static int msgRecv(TlsConnection *c, Msg *m);
2599a747e4fSDavid du Colombier static int msgSend(TlsConnection *c, Msg *m, int act);
2609a747e4fSDavid du Colombier static void tlsError(TlsConnection *c, int err, char *msg, ...);
2619a747e4fSDavid du Colombier #pragma varargck argpos tlsError 3
2629a747e4fSDavid du Colombier static int setVersion(TlsConnection *c, int version);
2639a747e4fSDavid du Colombier static int finishedMatch(TlsConnection *c, Finished *f);
2649a747e4fSDavid du Colombier static void tlsConnectionFree(TlsConnection *c);
2659a747e4fSDavid du Colombier
2669a747e4fSDavid du Colombier static int setAlgs(TlsConnection *c, int a);
2679a747e4fSDavid du Colombier static int okCipher(Ints *cv);
2689a747e4fSDavid du Colombier static int okCompression(Bytes *cv);
2699a747e4fSDavid du Colombier static int initCiphers(void);
2709a747e4fSDavid du Colombier static Ints* makeciphers(void);
2719a747e4fSDavid du Colombier
2729a747e4fSDavid du Colombier static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom);
2739a747e4fSDavid du Colombier static int tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd);
2749a747e4fSDavid du Colombier static TlsSec* tlsSecInitc(int cvers, uchar *crandom);
2759a747e4fSDavid 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);
2769a747e4fSDavid du Colombier static int tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient);
2779a747e4fSDavid du Colombier static void tlsSecOk(TlsSec *sec);
2789a747e4fSDavid du Colombier static void tlsSecKill(TlsSec *sec);
2799a747e4fSDavid du Colombier static void tlsSecClose(TlsSec *sec);
2809a747e4fSDavid du Colombier static void setMasterSecret(TlsSec *sec, Bytes *pm);
2819a747e4fSDavid du Colombier static void serverMasterSecret(TlsSec *sec, uchar *epm, int nepm);
2829a747e4fSDavid du Colombier static void setSecrets(TlsSec *sec, uchar *kd, int nkd);
2839a747e4fSDavid du Colombier static int clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm);
2849a747e4fSDavid du Colombier static Bytes *pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);
2859a747e4fSDavid du Colombier static Bytes *pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm);
2869a747e4fSDavid du Colombier static void tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
2879a747e4fSDavid du Colombier static void sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);
2889a747e4fSDavid du Colombier static void sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label,
2899a747e4fSDavid du Colombier uchar *seed0, int nseed0, uchar *seed1, int nseed1);
2909a747e4fSDavid du Colombier static int setVers(TlsSec *sec, int version);
2919a747e4fSDavid du Colombier
2929a747e4fSDavid du Colombier static AuthRpc* factotum_rsa_open(uchar *cert, int certlen);
2939a747e4fSDavid du Colombier static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);
2949a747e4fSDavid du Colombier static void factotum_rsa_close(AuthRpc*rpc);
2959a747e4fSDavid du Colombier
2969a747e4fSDavid du Colombier static void* emalloc(int);
2979a747e4fSDavid du Colombier static void* erealloc(void*, int);
2989a747e4fSDavid du Colombier static void put32(uchar *p, u32int);
2999a747e4fSDavid du Colombier static void put24(uchar *p, int);
3009a747e4fSDavid du Colombier static void put16(uchar *p, int);
3019a747e4fSDavid du Colombier static u32int get32(uchar *p);
3029a747e4fSDavid du Colombier static int get24(uchar *p);
3039a747e4fSDavid du Colombier static int get16(uchar *p);
3049a747e4fSDavid du Colombier static Bytes* newbytes(int len);
3059a747e4fSDavid du Colombier static Bytes* makebytes(uchar* buf, int len);
3069a747e4fSDavid du Colombier static void freebytes(Bytes* b);
3079a747e4fSDavid du Colombier static Ints* newints(int len);
3089a747e4fSDavid du Colombier static Ints* makeints(int* buf, int len);
3099a747e4fSDavid du Colombier static void freeints(Ints* b);
3109a747e4fSDavid du Colombier
3119a747e4fSDavid du Colombier //================= client/server ========================
3129a747e4fSDavid du Colombier
3139a747e4fSDavid du Colombier // push TLS onto fd, returning new (application) file descriptor
3149a747e4fSDavid du Colombier // or -1 if error.
3159a747e4fSDavid du Colombier int
tlsServer(int fd,TLSconn * conn)3169a747e4fSDavid du Colombier tlsServer(int fd, TLSconn *conn)
3179a747e4fSDavid du Colombier {
3189a747e4fSDavid du Colombier char buf[8];
3199a747e4fSDavid du Colombier char dname[64];
3209a747e4fSDavid du Colombier int n, data, ctl, hand;
3219a747e4fSDavid du Colombier TlsConnection *tls;
3229a747e4fSDavid du Colombier
3239a747e4fSDavid du Colombier if(conn == nil)
3249a747e4fSDavid du Colombier return -1;
3259a747e4fSDavid du Colombier ctl = open("#a/tls/clone", ORDWR);
3269a747e4fSDavid du Colombier if(ctl < 0)
3279a747e4fSDavid du Colombier return -1;
3289a747e4fSDavid du Colombier n = read(ctl, buf, sizeof(buf)-1);
3299a747e4fSDavid du Colombier if(n < 0){
3309a747e4fSDavid du Colombier close(ctl);
3319a747e4fSDavid du Colombier return -1;
3329a747e4fSDavid du Colombier }
3339a747e4fSDavid du Colombier buf[n] = 0;
3349a747e4fSDavid du Colombier sprint(conn->dir, "#a/tls/%s", buf);
3359a747e4fSDavid du Colombier sprint(dname, "#a/tls/%s/hand", buf);
3369a747e4fSDavid du Colombier hand = open(dname, ORDWR);
3379a747e4fSDavid du Colombier if(hand < 0){
3389a747e4fSDavid du Colombier close(ctl);
3399a747e4fSDavid du Colombier return -1;
3409a747e4fSDavid du Colombier }
3419a747e4fSDavid du Colombier fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
34251711cb6SDavid du Colombier tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace, conn->chain);
3439a747e4fSDavid du Colombier sprint(dname, "#a/tls/%s/data", buf);
3449a747e4fSDavid du Colombier data = open(dname, ORDWR);
3459a747e4fSDavid du Colombier close(fd);
3469a747e4fSDavid du Colombier close(hand);
3479a747e4fSDavid du Colombier close(ctl);
3489a747e4fSDavid du Colombier if(data < 0){
3499a747e4fSDavid du Colombier return -1;
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier if(tls == nil){
3529a747e4fSDavid du Colombier close(data);
3539a747e4fSDavid du Colombier return -1;
3549a747e4fSDavid du Colombier }
3559a747e4fSDavid du Colombier if(conn->cert)
3569a747e4fSDavid du Colombier free(conn->cert);
3579a747e4fSDavid du Colombier conn->cert = 0; // client certificates are not yet implemented
3589a747e4fSDavid du Colombier conn->certlen = 0;
3599a747e4fSDavid du Colombier conn->sessionIDlen = tls->sid->len;
3609a747e4fSDavid du Colombier conn->sessionID = emalloc(conn->sessionIDlen);
3619a747e4fSDavid du Colombier memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
3620d862726SDavid du Colombier if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0)
3630d862726SDavid du Colombier tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize);
3649a747e4fSDavid du Colombier tlsConnectionFree(tls);
3659a747e4fSDavid du Colombier return data;
3669a747e4fSDavid du Colombier }
3679a747e4fSDavid du Colombier
3689a747e4fSDavid du Colombier // push TLS onto fd, returning new (application) file descriptor
3699a747e4fSDavid du Colombier // or -1 if error.
3709a747e4fSDavid du Colombier int
tlsClient(int fd,TLSconn * conn)3719a747e4fSDavid du Colombier tlsClient(int fd, TLSconn *conn)
3729a747e4fSDavid du Colombier {
3739a747e4fSDavid du Colombier char buf[8];
3749a747e4fSDavid du Colombier char dname[64];
3759a747e4fSDavid du Colombier int n, data, ctl, hand;
3769a747e4fSDavid du Colombier TlsConnection *tls;
3779a747e4fSDavid du Colombier
3789a747e4fSDavid du Colombier if(!conn)
3799a747e4fSDavid du Colombier return -1;
3809a747e4fSDavid du Colombier ctl = open("#a/tls/clone", ORDWR);
3819a747e4fSDavid du Colombier if(ctl < 0)
3829a747e4fSDavid du Colombier return -1;
3839a747e4fSDavid du Colombier n = read(ctl, buf, sizeof(buf)-1);
3849a747e4fSDavid du Colombier if(n < 0){
3859a747e4fSDavid du Colombier close(ctl);
3869a747e4fSDavid du Colombier return -1;
3879a747e4fSDavid du Colombier }
3889a747e4fSDavid du Colombier buf[n] = 0;
3899a747e4fSDavid du Colombier sprint(conn->dir, "#a/tls/%s", buf);
3909a747e4fSDavid du Colombier sprint(dname, "#a/tls/%s/hand", buf);
3919a747e4fSDavid du Colombier hand = open(dname, ORDWR);
3929a747e4fSDavid du Colombier if(hand < 0){
3939a747e4fSDavid du Colombier close(ctl);
3949a747e4fSDavid du Colombier return -1;
3959a747e4fSDavid du Colombier }
3969a747e4fSDavid du Colombier sprint(dname, "#a/tls/%s/data", buf);
3979a747e4fSDavid du Colombier data = open(dname, ORDWR);
3989a747e4fSDavid du Colombier if(data < 0)
3999a747e4fSDavid du Colombier return -1;
4009a747e4fSDavid du Colombier fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
4019a747e4fSDavid du Colombier tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace);
4029a747e4fSDavid du Colombier close(fd);
4039a747e4fSDavid du Colombier close(hand);
4049a747e4fSDavid du Colombier close(ctl);
4059a747e4fSDavid du Colombier if(tls == nil){
4069a747e4fSDavid du Colombier close(data);
4079a747e4fSDavid du Colombier return -1;
4089a747e4fSDavid du Colombier }
4099a747e4fSDavid du Colombier conn->certlen = tls->cert->len;
4109a747e4fSDavid du Colombier conn->cert = emalloc(conn->certlen);
4119a747e4fSDavid du Colombier memcpy(conn->cert, tls->cert->data, conn->certlen);
4129a747e4fSDavid du Colombier conn->sessionIDlen = tls->sid->len;
4139a747e4fSDavid du Colombier conn->sessionID = emalloc(conn->sessionIDlen);
4149a747e4fSDavid du Colombier memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
4150d862726SDavid du Colombier if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0)
4160d862726SDavid du Colombier tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize);
4179a747e4fSDavid du Colombier tlsConnectionFree(tls);
4189a747e4fSDavid du Colombier return data;
4199a747e4fSDavid du Colombier }
4209a747e4fSDavid du Colombier
42151711cb6SDavid du Colombier static int
countchain(PEMChain * p)42251711cb6SDavid du Colombier countchain(PEMChain *p)
42351711cb6SDavid du Colombier {
42451711cb6SDavid du Colombier int i = 0;
42551711cb6SDavid du Colombier
42651711cb6SDavid du Colombier while (p) {
42751711cb6SDavid du Colombier i++;
42851711cb6SDavid du Colombier p = p->next;
42951711cb6SDavid du Colombier }
43051711cb6SDavid du Colombier return i;
43151711cb6SDavid du Colombier }
43251711cb6SDavid du Colombier
4339a747e4fSDavid du Colombier static TlsConnection *
tlsServer2(int ctl,int hand,uchar * cert,int ncert,int (* trace)(char * fmt,...),PEMChain * chp)43451711cb6SDavid du Colombier tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chp)
4359a747e4fSDavid du Colombier {
4369a747e4fSDavid du Colombier TlsConnection *c;
4379a747e4fSDavid du Colombier Msg m;
4389a747e4fSDavid du Colombier Bytes *csid;
4399a747e4fSDavid du Colombier uchar sid[SidSize], kd[MaxKeyData];
4409a747e4fSDavid du Colombier char *secrets;
44151711cb6SDavid du Colombier int cipher, compressor, nsid, rv, numcerts, i;
4429a747e4fSDavid du Colombier
4439a747e4fSDavid du Colombier if(trace)
4449a747e4fSDavid du Colombier trace("tlsServer2\n");
4459a747e4fSDavid du Colombier if(!initCiphers())
4469a747e4fSDavid du Colombier return nil;
4479a747e4fSDavid du Colombier c = emalloc(sizeof(TlsConnection));
4489a747e4fSDavid du Colombier c->ctl = ctl;
4499a747e4fSDavid du Colombier c->hand = hand;
4509a747e4fSDavid du Colombier c->trace = trace;
4519a747e4fSDavid du Colombier c->version = ProtocolVersion;
4529a747e4fSDavid du Colombier
4539a747e4fSDavid du Colombier memset(&m, 0, sizeof(m));
4549a747e4fSDavid du Colombier if(!msgRecv(c, &m)){
4559a747e4fSDavid du Colombier if(trace)
4569a747e4fSDavid du Colombier trace("initial msgRecv failed\n");
4579a747e4fSDavid du Colombier goto Err;
4589a747e4fSDavid du Colombier }
4599a747e4fSDavid du Colombier if(m.tag != HClientHello) {
4609a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a client hello");
4619a747e4fSDavid du Colombier goto Err;
4629a747e4fSDavid du Colombier }
4639a747e4fSDavid du Colombier c->clientVersion = m.u.clientHello.version;
4649a747e4fSDavid du Colombier if(trace)
4659a747e4fSDavid du Colombier trace("ClientHello version %x\n", c->clientVersion);
4669a747e4fSDavid du Colombier if(setVersion(c, m.u.clientHello.version) < 0) {
4679a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "incompatible version");
4689a747e4fSDavid du Colombier goto Err;
4699a747e4fSDavid du Colombier }
4709a747e4fSDavid du Colombier
4719a747e4fSDavid du Colombier memmove(c->crandom, m.u.clientHello.random, RandomSize);
4729a747e4fSDavid du Colombier cipher = okCipher(m.u.clientHello.ciphers);
4739a747e4fSDavid du Colombier if(cipher < 0) {
4749a747e4fSDavid du Colombier // reply with EInsufficientSecurity if we know that's the case
4759a747e4fSDavid du Colombier if(cipher == -2)
4769a747e4fSDavid du Colombier tlsError(c, EInsufficientSecurity, "cipher suites too weak");
4779a747e4fSDavid du Colombier else
4789a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "no matching cipher suite");
4799a747e4fSDavid du Colombier goto Err;
4809a747e4fSDavid du Colombier }
4819a747e4fSDavid du Colombier if(!setAlgs(c, cipher)){
4829a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "no matching cipher suite");
4839a747e4fSDavid du Colombier goto Err;
4849a747e4fSDavid du Colombier }
4859a747e4fSDavid du Colombier compressor = okCompression(m.u.clientHello.compressors);
4869a747e4fSDavid du Colombier if(compressor < 0) {
4879a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "no matching compressor");
4889a747e4fSDavid du Colombier goto Err;
4899a747e4fSDavid du Colombier }
4909a747e4fSDavid du Colombier
4919a747e4fSDavid du Colombier csid = m.u.clientHello.sid;
4929a747e4fSDavid du Colombier if(trace)
4939a747e4fSDavid du Colombier trace(" cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len);
4949a747e4fSDavid du Colombier c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom);
4959a747e4fSDavid du Colombier if(c->sec == nil){
4969a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "can't initialize security: %r");
4979a747e4fSDavid du Colombier goto Err;
4989a747e4fSDavid du Colombier }
4999a747e4fSDavid du Colombier c->sec->rpc = factotum_rsa_open(cert, ncert);
5009a747e4fSDavid du Colombier if(c->sec->rpc == nil){
5019a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
5029a747e4fSDavid du Colombier goto Err;
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier c->sec->rsapub = X509toRSApub(cert, ncert, nil, 0);
5059a747e4fSDavid du Colombier msgClear(&m);
5069a747e4fSDavid du Colombier
5079a747e4fSDavid du Colombier m.tag = HServerHello;
5089a747e4fSDavid du Colombier m.u.serverHello.version = c->version;
5099a747e4fSDavid du Colombier memmove(m.u.serverHello.random, c->srandom, RandomSize);
5109a747e4fSDavid du Colombier m.u.serverHello.cipher = cipher;
5119a747e4fSDavid du Colombier m.u.serverHello.compressor = compressor;
5129a747e4fSDavid du Colombier c->sid = makebytes(sid, nsid);
5139a747e4fSDavid du Colombier m.u.serverHello.sid = makebytes(c->sid->data, c->sid->len);
5149a747e4fSDavid du Colombier if(!msgSend(c, &m, AQueue))
5159a747e4fSDavid du Colombier goto Err;
5169a747e4fSDavid du Colombier msgClear(&m);
5179a747e4fSDavid du Colombier
5189a747e4fSDavid du Colombier m.tag = HCertificate;
51951711cb6SDavid du Colombier numcerts = countchain(chp);
52051711cb6SDavid du Colombier m.u.certificate.ncert = 1 + numcerts;
5219a747e4fSDavid du Colombier m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes));
5229a747e4fSDavid du Colombier m.u.certificate.certs[0] = makebytes(cert, ncert);
52351711cb6SDavid du Colombier for (i = 0; i < numcerts && chp; i++, chp = chp->next)
52451711cb6SDavid du Colombier m.u.certificate.certs[i+1] = makebytes(chp->pem, chp->pemlen);
5259a747e4fSDavid du Colombier if(!msgSend(c, &m, AQueue))
5269a747e4fSDavid du Colombier goto Err;
5279a747e4fSDavid du Colombier msgClear(&m);
5289a747e4fSDavid du Colombier
5299a747e4fSDavid du Colombier m.tag = HServerHelloDone;
5309a747e4fSDavid du Colombier if(!msgSend(c, &m, AFlush))
5319a747e4fSDavid du Colombier goto Err;
5329a747e4fSDavid du Colombier msgClear(&m);
5339a747e4fSDavid du Colombier
5349a747e4fSDavid du Colombier if(!msgRecv(c, &m))
5359a747e4fSDavid du Colombier goto Err;
5369a747e4fSDavid du Colombier if(m.tag != HClientKeyExchange) {
5379a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a client key exchange");
5389a747e4fSDavid du Colombier goto Err;
5399a747e4fSDavid du Colombier }
5409a747e4fSDavid du Colombier if(tlsSecSecrets(c->sec, c->version, m.u.clientKeyExchange.key->data, m.u.clientKeyExchange.key->len, kd, c->nsecret) < 0){
5419a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
5429a747e4fSDavid du Colombier goto Err;
5439a747e4fSDavid du Colombier }
5449a747e4fSDavid du Colombier if(trace)
5459a747e4fSDavid du Colombier trace("tls secrets\n");
5469a747e4fSDavid du Colombier secrets = (char*)emalloc(2*c->nsecret);
5479a747e4fSDavid du Colombier enc64(secrets, 2*c->nsecret, kd, c->nsecret);
5489a747e4fSDavid du Colombier rv = fprint(c->ctl, "secret %s %s 0 %s", c->digest, c->enc, secrets);
5499a747e4fSDavid du Colombier memset(secrets, 0, 2*c->nsecret);
5509a747e4fSDavid du Colombier free(secrets);
5519a747e4fSDavid du Colombier memset(kd, 0, c->nsecret);
5529a747e4fSDavid du Colombier if(rv < 0){
5539a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "can't set keys: %r");
5549a747e4fSDavid du Colombier goto Err;
5559a747e4fSDavid du Colombier }
5569a747e4fSDavid du Colombier msgClear(&m);
5579a747e4fSDavid du Colombier
5589a747e4fSDavid du Colombier /* no CertificateVerify; skip to Finished */
5599a747e4fSDavid du Colombier if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
5609a747e4fSDavid du Colombier tlsError(c, EInternalError, "can't set finished: %r");
5619a747e4fSDavid du Colombier goto Err;
5629a747e4fSDavid du Colombier }
5639a747e4fSDavid du Colombier if(!msgRecv(c, &m))
5649a747e4fSDavid du Colombier goto Err;
5659a747e4fSDavid du Colombier if(m.tag != HFinished) {
5669a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a finished");
5679a747e4fSDavid du Colombier goto Err;
5689a747e4fSDavid du Colombier }
5699a747e4fSDavid du Colombier if(!finishedMatch(c, &m.u.finished)) {
5709a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "finished verification failed");
5719a747e4fSDavid du Colombier goto Err;
5729a747e4fSDavid du Colombier }
5739a747e4fSDavid du Colombier msgClear(&m);
5749a747e4fSDavid du Colombier
5759a747e4fSDavid du Colombier /* change cipher spec */
5769a747e4fSDavid du Colombier if(fprint(c->ctl, "changecipher") < 0){
5779a747e4fSDavid du Colombier tlsError(c, EInternalError, "can't enable cipher: %r");
5789a747e4fSDavid du Colombier goto Err;
5799a747e4fSDavid du Colombier }
5809a747e4fSDavid du Colombier
5819a747e4fSDavid du Colombier if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
5829a747e4fSDavid du Colombier tlsError(c, EInternalError, "can't set finished: %r");
5839a747e4fSDavid du Colombier goto Err;
5849a747e4fSDavid du Colombier }
5859a747e4fSDavid du Colombier m.tag = HFinished;
5869a747e4fSDavid du Colombier m.u.finished = c->finished;
5879a747e4fSDavid du Colombier if(!msgSend(c, &m, AFlush))
5889a747e4fSDavid du Colombier goto Err;
5899a747e4fSDavid du Colombier msgClear(&m);
5909a747e4fSDavid du Colombier if(trace)
5919a747e4fSDavid du Colombier trace("tls finished\n");
5929a747e4fSDavid du Colombier
5939a747e4fSDavid du Colombier if(fprint(c->ctl, "opened") < 0)
5949a747e4fSDavid du Colombier goto Err;
5959a747e4fSDavid du Colombier tlsSecOk(c->sec);
5969a747e4fSDavid du Colombier return c;
5979a747e4fSDavid du Colombier
5989a747e4fSDavid du Colombier Err:
5999a747e4fSDavid du Colombier msgClear(&m);
6009a747e4fSDavid du Colombier tlsConnectionFree(c);
6019a747e4fSDavid du Colombier return 0;
6029a747e4fSDavid du Colombier }
6039a747e4fSDavid du Colombier
6049a747e4fSDavid du Colombier static TlsConnection *
tlsClient2(int ctl,int hand,uchar * csid,int ncsid,int (* trace)(char * fmt,...))6059a747e4fSDavid du Colombier tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...))
6069a747e4fSDavid du Colombier {
6079a747e4fSDavid du Colombier TlsConnection *c;
6089a747e4fSDavid du Colombier Msg m;
6099a747e4fSDavid du Colombier uchar kd[MaxKeyData], *epm;
6109a747e4fSDavid du Colombier char *secrets;
6119a747e4fSDavid du Colombier int creq, nepm, rv;
6129a747e4fSDavid du Colombier
6139a747e4fSDavid du Colombier if(!initCiphers())
6149a747e4fSDavid du Colombier return nil;
6159a747e4fSDavid du Colombier epm = nil;
6169a747e4fSDavid du Colombier c = emalloc(sizeof(TlsConnection));
6179a747e4fSDavid du Colombier c->version = ProtocolVersion;
6189a747e4fSDavid du Colombier c->ctl = ctl;
6199a747e4fSDavid du Colombier c->hand = hand;
6209a747e4fSDavid du Colombier c->trace = trace;
6219a747e4fSDavid du Colombier c->isClient = 1;
6229a747e4fSDavid du Colombier c->clientVersion = c->version;
6239a747e4fSDavid du Colombier
6249a747e4fSDavid du Colombier c->sec = tlsSecInitc(c->clientVersion, c->crandom);
6259a747e4fSDavid du Colombier if(c->sec == nil)
6269a747e4fSDavid du Colombier goto Err;
6279a747e4fSDavid du Colombier
6289a747e4fSDavid du Colombier /* client hello */
6299a747e4fSDavid du Colombier memset(&m, 0, sizeof(m));
6309a747e4fSDavid du Colombier m.tag = HClientHello;
6319a747e4fSDavid du Colombier m.u.clientHello.version = c->clientVersion;
6329a747e4fSDavid du Colombier memmove(m.u.clientHello.random, c->crandom, RandomSize);
6339a747e4fSDavid du Colombier m.u.clientHello.sid = makebytes(csid, ncsid);
6349a747e4fSDavid du Colombier m.u.clientHello.ciphers = makeciphers();
6359a747e4fSDavid du Colombier m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors));
6369a747e4fSDavid du Colombier if(!msgSend(c, &m, AFlush))
6379a747e4fSDavid du Colombier goto Err;
6389a747e4fSDavid du Colombier msgClear(&m);
6399a747e4fSDavid du Colombier
6409a747e4fSDavid du Colombier /* server hello */
6419a747e4fSDavid du Colombier if(!msgRecv(c, &m))
6429a747e4fSDavid du Colombier goto Err;
6439a747e4fSDavid du Colombier if(m.tag != HServerHello) {
6449a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a server hello");
6459a747e4fSDavid du Colombier goto Err;
6469a747e4fSDavid du Colombier }
6479a747e4fSDavid du Colombier if(setVersion(c, m.u.serverHello.version) < 0) {
6489a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "incompatible version %r");
6499a747e4fSDavid du Colombier goto Err;
6509a747e4fSDavid du Colombier }
6519a747e4fSDavid du Colombier memmove(c->srandom, m.u.serverHello.random, RandomSize);
6529a747e4fSDavid du Colombier c->sid = makebytes(m.u.serverHello.sid->data, m.u.serverHello.sid->len);
6539a747e4fSDavid du Colombier if(c->sid->len != 0 && c->sid->len != SidSize) {
6549a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "invalid server session identifier");
6559a747e4fSDavid du Colombier goto Err;
6569a747e4fSDavid du Colombier }
6579a747e4fSDavid du Colombier if(!setAlgs(c, m.u.serverHello.cipher)) {
6589a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "invalid cipher suite");
6599a747e4fSDavid du Colombier goto Err;
6609a747e4fSDavid du Colombier }
6619a747e4fSDavid du Colombier if(m.u.serverHello.compressor != CompressionNull) {
6629a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "invalid compression");
6639a747e4fSDavid du Colombier goto Err;
6649a747e4fSDavid du Colombier }
6659a747e4fSDavid du Colombier msgClear(&m);
6669a747e4fSDavid du Colombier
6679a747e4fSDavid du Colombier /* certificate */
6689a747e4fSDavid du Colombier if(!msgRecv(c, &m) || m.tag != HCertificate) {
6699a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a certificate");
6709a747e4fSDavid du Colombier goto Err;
6719a747e4fSDavid du Colombier }
6729a747e4fSDavid du Colombier if(m.u.certificate.ncert < 1) {
6739a747e4fSDavid du Colombier tlsError(c, EIllegalParameter, "runt certificate");
6749a747e4fSDavid du Colombier goto Err;
6759a747e4fSDavid du Colombier }
6769a747e4fSDavid du Colombier c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
6779a747e4fSDavid du Colombier msgClear(&m);
6789a747e4fSDavid du Colombier
6799a747e4fSDavid du Colombier /* server key exchange (optional) */
6809a747e4fSDavid du Colombier if(!msgRecv(c, &m))
6819a747e4fSDavid du Colombier goto Err;
6829a747e4fSDavid du Colombier if(m.tag == HServerKeyExchange) {
6839a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "got an server key exchange");
6849a747e4fSDavid du Colombier goto Err;
6859a747e4fSDavid du Colombier // If implementing this later, watch out for rollback attack
6869a747e4fSDavid du Colombier // described in Wagner Schneier 1996, section 4.4.
6879a747e4fSDavid du Colombier }
6889a747e4fSDavid du Colombier
6899a747e4fSDavid du Colombier /* certificate request (optional) */
6909a747e4fSDavid du Colombier creq = 0;
6919a747e4fSDavid du Colombier if(m.tag == HCertificateRequest) {
6929a747e4fSDavid du Colombier creq = 1;
6939a747e4fSDavid du Colombier msgClear(&m);
6949a747e4fSDavid du Colombier if(!msgRecv(c, &m))
6959a747e4fSDavid du Colombier goto Err;
6969a747e4fSDavid du Colombier }
6979a747e4fSDavid du Colombier
6989a747e4fSDavid du Colombier if(m.tag != HServerHelloDone) {
6999a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a server hello done");
7009a747e4fSDavid du Colombier goto Err;
7019a747e4fSDavid du Colombier }
7029a747e4fSDavid du Colombier msgClear(&m);
7039a747e4fSDavid du Colombier
7049a747e4fSDavid du Colombier if(tlsSecSecretc(c->sec, c->sid->data, c->sid->len, c->srandom,
7059a747e4fSDavid du Colombier c->cert->data, c->cert->len, c->version, &epm, &nepm,
7069a747e4fSDavid du Colombier kd, c->nsecret) < 0){
7079a747e4fSDavid du Colombier tlsError(c, EBadCertificate, "invalid x509/rsa certificate");
7089a747e4fSDavid du Colombier goto Err;
7099a747e4fSDavid du Colombier }
7109a747e4fSDavid du Colombier secrets = (char*)emalloc(2*c->nsecret);
7119a747e4fSDavid du Colombier enc64(secrets, 2*c->nsecret, kd, c->nsecret);
7129a747e4fSDavid du Colombier rv = fprint(c->ctl, "secret %s %s 1 %s", c->digest, c->enc, secrets);
7139a747e4fSDavid du Colombier memset(secrets, 0, 2*c->nsecret);
7149a747e4fSDavid du Colombier free(secrets);
7159a747e4fSDavid du Colombier memset(kd, 0, c->nsecret);
7169a747e4fSDavid du Colombier if(rv < 0){
7179a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "can't set keys: %r");
7189a747e4fSDavid du Colombier goto Err;
7199a747e4fSDavid du Colombier }
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier if(creq) {
7229a747e4fSDavid du Colombier /* send a zero length certificate */
7239a747e4fSDavid du Colombier m.tag = HCertificate;
7249a747e4fSDavid du Colombier if(!msgSend(c, &m, AFlush))
7259a747e4fSDavid du Colombier goto Err;
7269a747e4fSDavid du Colombier msgClear(&m);
7279a747e4fSDavid du Colombier }
7289a747e4fSDavid du Colombier
7299a747e4fSDavid du Colombier /* client key exchange */
7309a747e4fSDavid du Colombier m.tag = HClientKeyExchange;
7319a747e4fSDavid du Colombier m.u.clientKeyExchange.key = makebytes(epm, nepm);
7329a747e4fSDavid du Colombier free(epm);
7339a747e4fSDavid du Colombier epm = nil;
7349a747e4fSDavid du Colombier if(m.u.clientKeyExchange.key == nil) {
7359a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "can't set secret: %r");
7369a747e4fSDavid du Colombier goto Err;
7379a747e4fSDavid du Colombier }
7389a747e4fSDavid du Colombier if(!msgSend(c, &m, AFlush))
7399a747e4fSDavid du Colombier goto Err;
7409a747e4fSDavid du Colombier msgClear(&m);
7419a747e4fSDavid du Colombier
7429a747e4fSDavid du Colombier /* change cipher spec */
7439a747e4fSDavid du Colombier if(fprint(c->ctl, "changecipher") < 0){
7449a747e4fSDavid du Colombier tlsError(c, EInternalError, "can't enable cipher: %r");
7459a747e4fSDavid du Colombier goto Err;
7469a747e4fSDavid du Colombier }
7479a747e4fSDavid du Colombier
7489a747e4fSDavid du Colombier // Cipherchange must occur immediately before Finished to avoid
7499a747e4fSDavid du Colombier // potential hole; see section 4.3 of Wagner Schneier 1996.
7509a747e4fSDavid du Colombier if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){
75165fa3f8bSDavid du Colombier tlsError(c, EInternalError, "can't set finished 1: %r");
7529a747e4fSDavid du Colombier goto Err;
7539a747e4fSDavid du Colombier }
7549a747e4fSDavid du Colombier m.tag = HFinished;
7559a747e4fSDavid du Colombier m.u.finished = c->finished;
7569a747e4fSDavid du Colombier
75765fa3f8bSDavid du Colombier if(!msgSend(c, &m, AFlush)) {
75865fa3f8bSDavid du Colombier fprint(2, "tlsClient nepm=%d\n", nepm);
75965fa3f8bSDavid du Colombier tlsError(c, EInternalError, "can't flush after client Finished: %r");
7609a747e4fSDavid du Colombier goto Err;
76165fa3f8bSDavid du Colombier }
7629a747e4fSDavid du Colombier msgClear(&m);
7639a747e4fSDavid du Colombier
7649a747e4fSDavid du Colombier if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){
76565fa3f8bSDavid du Colombier fprint(2, "tlsClient nepm=%d\n", nepm);
76665fa3f8bSDavid du Colombier tlsError(c, EInternalError, "can't set finished 0: %r");
7679a747e4fSDavid du Colombier goto Err;
7689a747e4fSDavid du Colombier }
76965fa3f8bSDavid du Colombier if(!msgRecv(c, &m)) {
77065fa3f8bSDavid du Colombier fprint(2, "tlsClient nepm=%d\n", nepm);
77165fa3f8bSDavid du Colombier tlsError(c, EInternalError, "can't read server Finished: %r");
7729a747e4fSDavid du Colombier goto Err;
77365fa3f8bSDavid du Colombier }
7749a747e4fSDavid du Colombier if(m.tag != HFinished) {
77565fa3f8bSDavid du Colombier fprint(2, "tlsClient nepm=%d\n", nepm);
77665fa3f8bSDavid du Colombier tlsError(c, EUnexpectedMessage, "expected a Finished msg from server");
7779a747e4fSDavid du Colombier goto Err;
7789a747e4fSDavid du Colombier }
7799a747e4fSDavid du Colombier
7809a747e4fSDavid du Colombier if(!finishedMatch(c, &m.u.finished)) {
7819a747e4fSDavid du Colombier tlsError(c, EHandshakeFailure, "finished verification failed");
7829a747e4fSDavid du Colombier goto Err;
7839a747e4fSDavid du Colombier }
7849a747e4fSDavid du Colombier msgClear(&m);
7859a747e4fSDavid du Colombier
7869a747e4fSDavid du Colombier if(fprint(c->ctl, "opened") < 0){
7879a747e4fSDavid du Colombier if(trace)
7889a747e4fSDavid du Colombier trace("unable to do final open: %r\n");
7899a747e4fSDavid du Colombier goto Err;
7909a747e4fSDavid du Colombier }
7919a747e4fSDavid du Colombier tlsSecOk(c->sec);
7929a747e4fSDavid du Colombier return c;
7939a747e4fSDavid du Colombier
7949a747e4fSDavid du Colombier Err:
7959a747e4fSDavid du Colombier free(epm);
7969a747e4fSDavid du Colombier msgClear(&m);
7979a747e4fSDavid du Colombier tlsConnectionFree(c);
7989a747e4fSDavid du Colombier return 0;
7999a747e4fSDavid du Colombier }
8009a747e4fSDavid du Colombier
8019a747e4fSDavid du Colombier
8029a747e4fSDavid du Colombier //================= message functions ========================
8039a747e4fSDavid du Colombier
8049a747e4fSDavid du Colombier static uchar sendbuf[9000], *sendp;
8059a747e4fSDavid du Colombier
8069a747e4fSDavid du Colombier static int
msgSend(TlsConnection * c,Msg * m,int act)8079a747e4fSDavid du Colombier msgSend(TlsConnection *c, Msg *m, int act)
8089a747e4fSDavid du Colombier {
8099a747e4fSDavid du Colombier uchar *p; // sendp = start of new message; p = write pointer
8109a747e4fSDavid du Colombier int nn, n, i;
8119a747e4fSDavid du Colombier
8129a747e4fSDavid du Colombier if(sendp == nil)
8139a747e4fSDavid du Colombier sendp = sendbuf;
8149a747e4fSDavid du Colombier p = sendp;
8159a747e4fSDavid du Colombier if(c->trace)
8169a747e4fSDavid du Colombier c->trace("send %s", msgPrint((char*)p, (sizeof sendbuf) - (p-sendbuf), m));
8179a747e4fSDavid du Colombier
8189a747e4fSDavid du Colombier p[0] = m->tag; // header - fill in size later
8199a747e4fSDavid du Colombier p += 4;
8209a747e4fSDavid du Colombier
8219a747e4fSDavid du Colombier switch(m->tag) {
8229a747e4fSDavid du Colombier default:
8239a747e4fSDavid du Colombier tlsError(c, EInternalError, "can't encode a %d", m->tag);
8249a747e4fSDavid du Colombier goto Err;
8259a747e4fSDavid du Colombier case HClientHello:
8269a747e4fSDavid du Colombier // version
8279a747e4fSDavid du Colombier put16(p, m->u.clientHello.version);
8289a747e4fSDavid du Colombier p += 2;
8299a747e4fSDavid du Colombier
8309a747e4fSDavid du Colombier // random
8319a747e4fSDavid du Colombier memmove(p, m->u.clientHello.random, RandomSize);
8329a747e4fSDavid du Colombier p += RandomSize;
8339a747e4fSDavid du Colombier
8349a747e4fSDavid du Colombier // sid
8359a747e4fSDavid du Colombier n = m->u.clientHello.sid->len;
8369a747e4fSDavid du Colombier assert(n < 256);
8379a747e4fSDavid du Colombier p[0] = n;
8389a747e4fSDavid du Colombier memmove(p+1, m->u.clientHello.sid->data, n);
8399a747e4fSDavid du Colombier p += n+1;
8409a747e4fSDavid du Colombier
8419a747e4fSDavid du Colombier n = m->u.clientHello.ciphers->len;
8429a747e4fSDavid du Colombier assert(n > 0 && n < 200);
8439a747e4fSDavid du Colombier put16(p, n*2);
8449a747e4fSDavid du Colombier p += 2;
8459a747e4fSDavid du Colombier for(i=0; i<n; i++) {
8469a747e4fSDavid du Colombier put16(p, m->u.clientHello.ciphers->data[i]);
8479a747e4fSDavid du Colombier p += 2;
8489a747e4fSDavid du Colombier }
8499a747e4fSDavid du Colombier
8509a747e4fSDavid du Colombier n = m->u.clientHello.compressors->len;
8519a747e4fSDavid du Colombier assert(n > 0);
8529a747e4fSDavid du Colombier p[0] = n;
8539a747e4fSDavid du Colombier memmove(p+1, m->u.clientHello.compressors->data, n);
8549a747e4fSDavid du Colombier p += n+1;
8559a747e4fSDavid du Colombier break;
8569a747e4fSDavid du Colombier case HServerHello:
8579a747e4fSDavid du Colombier put16(p, m->u.serverHello.version);
8589a747e4fSDavid du Colombier p += 2;
8599a747e4fSDavid du Colombier
8609a747e4fSDavid du Colombier // random
8619a747e4fSDavid du Colombier memmove(p, m->u.serverHello.random, RandomSize);
8629a747e4fSDavid du Colombier p += RandomSize;
8639a747e4fSDavid du Colombier
8649a747e4fSDavid du Colombier // sid
8659a747e4fSDavid du Colombier n = m->u.serverHello.sid->len;
8669a747e4fSDavid du Colombier assert(n < 256);
8679a747e4fSDavid du Colombier p[0] = n;
8689a747e4fSDavid du Colombier memmove(p+1, m->u.serverHello.sid->data, n);
8699a747e4fSDavid du Colombier p += n+1;
8709a747e4fSDavid du Colombier
8719a747e4fSDavid du Colombier put16(p, m->u.serverHello.cipher);
8729a747e4fSDavid du Colombier p += 2;
8739a747e4fSDavid du Colombier p[0] = m->u.serverHello.compressor;
8749a747e4fSDavid du Colombier p += 1;
8759a747e4fSDavid du Colombier break;
8769a747e4fSDavid du Colombier case HServerHelloDone:
8779a747e4fSDavid du Colombier break;
8789a747e4fSDavid du Colombier case HCertificate:
8799a747e4fSDavid du Colombier nn = 0;
8809a747e4fSDavid du Colombier for(i = 0; i < m->u.certificate.ncert; i++)
8819a747e4fSDavid du Colombier nn += 3 + m->u.certificate.certs[i]->len;
8829a747e4fSDavid du Colombier if(p + 3 + nn - sendbuf > sizeof(sendbuf)) {
8839a747e4fSDavid du Colombier tlsError(c, EInternalError, "output buffer too small for certificate");
8849a747e4fSDavid du Colombier goto Err;
8859a747e4fSDavid du Colombier }
8869a747e4fSDavid du Colombier put24(p, nn);
8879a747e4fSDavid du Colombier p += 3;
8889a747e4fSDavid du Colombier for(i = 0; i < m->u.certificate.ncert; i++){
8899a747e4fSDavid du Colombier put24(p, m->u.certificate.certs[i]->len);
8909a747e4fSDavid du Colombier p += 3;
8919a747e4fSDavid du Colombier memmove(p, m->u.certificate.certs[i]->data, m->u.certificate.certs[i]->len);
8929a747e4fSDavid du Colombier p += m->u.certificate.certs[i]->len;
8939a747e4fSDavid du Colombier }
8949a747e4fSDavid du Colombier break;
8959a747e4fSDavid du Colombier case HClientKeyExchange:
8969a747e4fSDavid du Colombier n = m->u.clientKeyExchange.key->len;
8979a747e4fSDavid du Colombier if(c->version != SSL3Version){
8989a747e4fSDavid du Colombier put16(p, n);
8999a747e4fSDavid du Colombier p += 2;
9009a747e4fSDavid du Colombier }
9019a747e4fSDavid du Colombier memmove(p, m->u.clientKeyExchange.key->data, n);
9029a747e4fSDavid du Colombier p += n;
9039a747e4fSDavid du Colombier break;
9049a747e4fSDavid du Colombier case HFinished:
9059a747e4fSDavid du Colombier memmove(p, m->u.finished.verify, m->u.finished.n);
9069a747e4fSDavid du Colombier p += m->u.finished.n;
9079a747e4fSDavid du Colombier break;
9089a747e4fSDavid du Colombier }
9099a747e4fSDavid du Colombier
9109a747e4fSDavid du Colombier // go back and fill in size
9119a747e4fSDavid du Colombier n = p-sendp;
9129a747e4fSDavid du Colombier assert(p <= sendbuf+sizeof(sendbuf));
9139a747e4fSDavid du Colombier put24(sendp+1, n-4);
9149a747e4fSDavid du Colombier
9159a747e4fSDavid du Colombier // remember hash of Handshake messages
9169a747e4fSDavid du Colombier if(m->tag != HHelloRequest) {
9179a747e4fSDavid du Colombier md5(sendp, n, 0, &c->hsmd5);
9189a747e4fSDavid du Colombier sha1(sendp, n, 0, &c->hssha1);
9199a747e4fSDavid du Colombier }
9209a747e4fSDavid du Colombier
9219a747e4fSDavid du Colombier sendp = p;
9229a747e4fSDavid du Colombier if(act == AFlush){
9239a747e4fSDavid du Colombier sendp = sendbuf;
9249a747e4fSDavid du Colombier if(write(c->hand, sendbuf, p-sendbuf) < 0){
9259a747e4fSDavid du Colombier fprint(2, "write error: %r\n");
9269a747e4fSDavid du Colombier goto Err;
9279a747e4fSDavid du Colombier }
9289a747e4fSDavid du Colombier }
9299a747e4fSDavid du Colombier msgClear(m);
9309a747e4fSDavid du Colombier return 1;
9319a747e4fSDavid du Colombier Err:
9329a747e4fSDavid du Colombier msgClear(m);
9339a747e4fSDavid du Colombier return 0;
9349a747e4fSDavid du Colombier }
9359a747e4fSDavid du Colombier
9369a747e4fSDavid du Colombier static uchar*
tlsReadN(TlsConnection * c,int n)9379a747e4fSDavid du Colombier tlsReadN(TlsConnection *c, int n)
9389a747e4fSDavid du Colombier {
9399a747e4fSDavid du Colombier uchar *p;
9409a747e4fSDavid du Colombier int nn, nr;
9419a747e4fSDavid du Colombier
9429a747e4fSDavid du Colombier nn = c->ep - c->rp;
9439a747e4fSDavid du Colombier if(nn < n){
9449a747e4fSDavid du Colombier if(c->rp != c->buf){
9459a747e4fSDavid du Colombier memmove(c->buf, c->rp, nn);
9469a747e4fSDavid du Colombier c->rp = c->buf;
9479a747e4fSDavid du Colombier c->ep = &c->buf[nn];
9489a747e4fSDavid du Colombier }
9499a747e4fSDavid du Colombier for(; nn < n; nn += nr) {
9509a747e4fSDavid du Colombier nr = read(c->hand, &c->rp[nn], n - nn);
9519a747e4fSDavid du Colombier if(nr <= 0)
9529a747e4fSDavid du Colombier return nil;
9539a747e4fSDavid du Colombier c->ep += nr;
9549a747e4fSDavid du Colombier }
9559a747e4fSDavid du Colombier }
9569a747e4fSDavid du Colombier p = c->rp;
9579a747e4fSDavid du Colombier c->rp += n;
9589a747e4fSDavid du Colombier return p;
9599a747e4fSDavid du Colombier }
9609a747e4fSDavid du Colombier
9619a747e4fSDavid du Colombier static int
msgRecv(TlsConnection * c,Msg * m)9629a747e4fSDavid du Colombier msgRecv(TlsConnection *c, Msg *m)
9639a747e4fSDavid du Colombier {
9649a747e4fSDavid du Colombier uchar *p;
9659a747e4fSDavid du Colombier int type, n, nn, i, nsid, nrandom, nciph;
9669a747e4fSDavid du Colombier
9679a747e4fSDavid du Colombier for(;;) {
9689a747e4fSDavid du Colombier p = tlsReadN(c, 4);
9699a747e4fSDavid du Colombier if(p == nil)
9709a747e4fSDavid du Colombier return 0;
9719a747e4fSDavid du Colombier type = p[0];
9729a747e4fSDavid du Colombier n = get24(p+1);
9739a747e4fSDavid du Colombier
9749a747e4fSDavid du Colombier if(type != HHelloRequest)
9759a747e4fSDavid du Colombier break;
9769a747e4fSDavid du Colombier if(n != 0) {
9779a747e4fSDavid du Colombier tlsError(c, EDecodeError, "invalid hello request during handshake");
9789a747e4fSDavid du Colombier return 0;
9799a747e4fSDavid du Colombier }
9809a747e4fSDavid du Colombier }
9819a747e4fSDavid du Colombier
9829a747e4fSDavid du Colombier if(n > sizeof(c->buf)) {
9839a747e4fSDavid du Colombier tlsError(c, EDecodeError, "handshake message too long %d %d", n, sizeof(c->buf));
9849a747e4fSDavid du Colombier return 0;
9859a747e4fSDavid du Colombier }
9869a747e4fSDavid du Colombier
9879a747e4fSDavid du Colombier if(type == HSSL2ClientHello){
9889a747e4fSDavid du Colombier /* Cope with an SSL3 ClientHello expressed in SSL2 record format.
9899a747e4fSDavid du Colombier This is sent by some clients that we must interoperate
9909a747e4fSDavid du Colombier with, such as Java's JSSE and Microsoft's Internet Explorer. */
9919a747e4fSDavid du Colombier p = tlsReadN(c, n);
9929a747e4fSDavid du Colombier if(p == nil)
9939a747e4fSDavid du Colombier return 0;
9949a747e4fSDavid du Colombier md5(p, n, 0, &c->hsmd5);
9959a747e4fSDavid du Colombier sha1(p, n, 0, &c->hssha1);
9969a747e4fSDavid du Colombier m->tag = HClientHello;
9979a747e4fSDavid du Colombier if(n < 22)
9989a747e4fSDavid du Colombier goto Short;
9999a747e4fSDavid du Colombier m->u.clientHello.version = get16(p+1);
10009a747e4fSDavid du Colombier p += 3;
10019a747e4fSDavid du Colombier n -= 3;
10029a747e4fSDavid du Colombier nn = get16(p); /* cipher_spec_len */
10039a747e4fSDavid du Colombier nsid = get16(p + 2);
10049a747e4fSDavid du Colombier nrandom = get16(p + 4);
10059a747e4fSDavid du Colombier p += 6;
10069a747e4fSDavid du Colombier n -= 6;
10079a747e4fSDavid du Colombier if(nsid != 0 /* no sid's, since shouldn't restart using ssl2 header */
10089a747e4fSDavid du Colombier || nrandom < 16 || nn % 3)
10099a747e4fSDavid du Colombier goto Err;
10109a747e4fSDavid du Colombier if(c->trace && (n - nrandom != nn))
10119a747e4fSDavid du Colombier c->trace("n-nrandom!=nn: n=%d nrandom=%d nn=%d\n", n, nrandom, nn);
10129a747e4fSDavid du Colombier /* ignore ssl2 ciphers and look for {0x00, ssl3 cipher} */
10139a747e4fSDavid du Colombier nciph = 0;
10149a747e4fSDavid du Colombier for(i = 0; i < nn; i += 3)
10159a747e4fSDavid du Colombier if(p[i] == 0)
10169a747e4fSDavid du Colombier nciph++;
10179a747e4fSDavid du Colombier m->u.clientHello.ciphers = newints(nciph);
10189a747e4fSDavid du Colombier nciph = 0;
10199a747e4fSDavid du Colombier for(i = 0; i < nn; i += 3)
10209a747e4fSDavid du Colombier if(p[i] == 0)
10219a747e4fSDavid du Colombier m->u.clientHello.ciphers->data[nciph++] = get16(&p[i + 1]);
10229a747e4fSDavid du Colombier p += nn;
10239a747e4fSDavid du Colombier m->u.clientHello.sid = makebytes(nil, 0);
10249a747e4fSDavid du Colombier if(nrandom > RandomSize)
10259a747e4fSDavid du Colombier nrandom = RandomSize;
10269a747e4fSDavid du Colombier memset(m->u.clientHello.random, 0, RandomSize - nrandom);
10279a747e4fSDavid du Colombier memmove(&m->u.clientHello.random[RandomSize - nrandom], p, nrandom);
10289a747e4fSDavid du Colombier m->u.clientHello.compressors = newbytes(1);
10299a747e4fSDavid du Colombier m->u.clientHello.compressors->data[0] = CompressionNull;
10309a747e4fSDavid du Colombier goto Ok;
10319a747e4fSDavid du Colombier }
10329a747e4fSDavid du Colombier
10339a747e4fSDavid du Colombier md5(p, 4, 0, &c->hsmd5);
10349a747e4fSDavid du Colombier sha1(p, 4, 0, &c->hssha1);
10359a747e4fSDavid du Colombier
10369a747e4fSDavid du Colombier p = tlsReadN(c, n);
10379a747e4fSDavid du Colombier if(p == nil)
10389a747e4fSDavid du Colombier return 0;
10399a747e4fSDavid du Colombier
10409a747e4fSDavid du Colombier md5(p, n, 0, &c->hsmd5);
10419a747e4fSDavid du Colombier sha1(p, n, 0, &c->hssha1);
10429a747e4fSDavid du Colombier
10439a747e4fSDavid du Colombier m->tag = type;
10449a747e4fSDavid du Colombier
10459a747e4fSDavid du Colombier switch(type) {
10469a747e4fSDavid du Colombier default:
10479a747e4fSDavid du Colombier tlsError(c, EUnexpectedMessage, "can't decode a %d", type);
10489a747e4fSDavid du Colombier goto Err;
10499a747e4fSDavid du Colombier case HClientHello:
10509a747e4fSDavid du Colombier if(n < 2)
10519a747e4fSDavid du Colombier goto Short;
10529a747e4fSDavid du Colombier m->u.clientHello.version = get16(p);
10539a747e4fSDavid du Colombier p += 2;
10549a747e4fSDavid du Colombier n -= 2;
10559a747e4fSDavid du Colombier
10569a747e4fSDavid du Colombier if(n < RandomSize)
10579a747e4fSDavid du Colombier goto Short;
10589a747e4fSDavid du Colombier memmove(m->u.clientHello.random, p, RandomSize);
10599a747e4fSDavid du Colombier p += RandomSize;
10609a747e4fSDavid du Colombier n -= RandomSize;
10619a747e4fSDavid du Colombier if(n < 1 || n < p[0]+1)
10629a747e4fSDavid du Colombier goto Short;
10639a747e4fSDavid du Colombier m->u.clientHello.sid = makebytes(p+1, p[0]);
10649a747e4fSDavid du Colombier p += m->u.clientHello.sid->len+1;
10659a747e4fSDavid du Colombier n -= m->u.clientHello.sid->len+1;
10669a747e4fSDavid du Colombier
10679a747e4fSDavid du Colombier if(n < 2)
10689a747e4fSDavid du Colombier goto Short;
10699a747e4fSDavid du Colombier nn = get16(p);
10709a747e4fSDavid du Colombier p += 2;
10719a747e4fSDavid du Colombier n -= 2;
10729a747e4fSDavid du Colombier
10739a747e4fSDavid du Colombier if((nn & 1) || n < nn || nn < 2)
10749a747e4fSDavid du Colombier goto Short;
10759a747e4fSDavid du Colombier m->u.clientHello.ciphers = newints(nn >> 1);
10769a747e4fSDavid du Colombier for(i = 0; i < nn; i += 2)
10779a747e4fSDavid du Colombier m->u.clientHello.ciphers->data[i >> 1] = get16(&p[i]);
10789a747e4fSDavid du Colombier p += nn;
10799a747e4fSDavid du Colombier n -= nn;
10809a747e4fSDavid du Colombier
10819a747e4fSDavid du Colombier if(n < 1 || n < p[0]+1 || p[0] == 0)
10829a747e4fSDavid du Colombier goto Short;
10839a747e4fSDavid du Colombier nn = p[0];
10849a747e4fSDavid du Colombier m->u.clientHello.compressors = newbytes(nn);
10859a747e4fSDavid du Colombier memmove(m->u.clientHello.compressors->data, p+1, nn);
10869a747e4fSDavid du Colombier n -= nn + 1;
10879a747e4fSDavid du Colombier break;
10889a747e4fSDavid du Colombier case HServerHello:
10899a747e4fSDavid du Colombier if(n < 2)
10909a747e4fSDavid du Colombier goto Short;
10919a747e4fSDavid du Colombier m->u.serverHello.version = get16(p);
10929a747e4fSDavid du Colombier p += 2;
10939a747e4fSDavid du Colombier n -= 2;
10949a747e4fSDavid du Colombier
10959a747e4fSDavid du Colombier if(n < RandomSize)
10969a747e4fSDavid du Colombier goto Short;
10979a747e4fSDavid du Colombier memmove(m->u.serverHello.random, p, RandomSize);
10989a747e4fSDavid du Colombier p += RandomSize;
10999a747e4fSDavid du Colombier n -= RandomSize;
11009a747e4fSDavid du Colombier
11019a747e4fSDavid du Colombier if(n < 1 || n < p[0]+1)
11029a747e4fSDavid du Colombier goto Short;
11039a747e4fSDavid du Colombier m->u.serverHello.sid = makebytes(p+1, p[0]);
11049a747e4fSDavid du Colombier p += m->u.serverHello.sid->len+1;
11059a747e4fSDavid du Colombier n -= m->u.serverHello.sid->len+1;
11069a747e4fSDavid du Colombier
11079a747e4fSDavid du Colombier if(n < 3)
11089a747e4fSDavid du Colombier goto Short;
11099a747e4fSDavid du Colombier m->u.serverHello.cipher = get16(p);
11109a747e4fSDavid du Colombier m->u.serverHello.compressor = p[2];
11119a747e4fSDavid du Colombier n -= 3;
11129a747e4fSDavid du Colombier break;
11139a747e4fSDavid du Colombier case HCertificate:
11149a747e4fSDavid du Colombier if(n < 3)
11159a747e4fSDavid du Colombier goto Short;
11169a747e4fSDavid du Colombier nn = get24(p);
11179a747e4fSDavid du Colombier p += 3;
11189a747e4fSDavid du Colombier n -= 3;
11199a747e4fSDavid du Colombier if(n != nn)
11209a747e4fSDavid du Colombier goto Short;
11219a747e4fSDavid du Colombier /* certs */
11229a747e4fSDavid du Colombier i = 0;
11239a747e4fSDavid du Colombier while(n > 0) {
11249a747e4fSDavid du Colombier if(n < 3)
11259a747e4fSDavid du Colombier goto Short;
11269a747e4fSDavid du Colombier nn = get24(p);
11279a747e4fSDavid du Colombier p += 3;
11289a747e4fSDavid du Colombier n -= 3;
11299a747e4fSDavid du Colombier if(nn > n)
11309a747e4fSDavid du Colombier goto Short;
11319a747e4fSDavid du Colombier m->u.certificate.ncert = i+1;
11329a747e4fSDavid du Colombier m->u.certificate.certs = erealloc(m->u.certificate.certs, (i+1)*sizeof(Bytes));
11339a747e4fSDavid du Colombier m->u.certificate.certs[i] = makebytes(p, nn);
11349a747e4fSDavid du Colombier p += nn;
11359a747e4fSDavid du Colombier n -= nn;
11369a747e4fSDavid du Colombier i++;
11379a747e4fSDavid du Colombier }
11389a747e4fSDavid du Colombier break;
11399a747e4fSDavid du Colombier case HCertificateRequest:
114090630c3aSDavid du Colombier if(n < 1)
114190630c3aSDavid du Colombier goto Short;
114290630c3aSDavid du Colombier nn = p[0];
114390630c3aSDavid du Colombier p += 1;
114490630c3aSDavid du Colombier n -= 1;
114590630c3aSDavid du Colombier if(nn < 1 || nn > n)
114690630c3aSDavid du Colombier goto Short;
114790630c3aSDavid du Colombier m->u.certificateRequest.types = makebytes(p, nn);
114890630c3aSDavid du Colombier p += nn;
114990630c3aSDavid du Colombier n -= nn;
11509a747e4fSDavid du Colombier if(n < 2)
11519a747e4fSDavid du Colombier goto Short;
11529a747e4fSDavid du Colombier nn = get16(p);
11539a747e4fSDavid du Colombier p += 2;
11549a747e4fSDavid du Colombier n -= 2;
115525fc6993SDavid du Colombier /* nn == 0 can happen; yahoo's servers do it */
115625fc6993SDavid du Colombier if(nn != n)
11579a747e4fSDavid du Colombier goto Short;
11589a747e4fSDavid du Colombier /* cas */
11599a747e4fSDavid du Colombier i = 0;
11609a747e4fSDavid du Colombier while(n > 0) {
11619a747e4fSDavid du Colombier if(n < 2)
11629a747e4fSDavid du Colombier goto Short;
11639a747e4fSDavid du Colombier nn = get16(p);
11649a747e4fSDavid du Colombier p += 2;
11659a747e4fSDavid du Colombier n -= 2;
11669a747e4fSDavid du Colombier if(nn < 1 || nn > n)
11679a747e4fSDavid du Colombier goto Short;
11689a747e4fSDavid du Colombier m->u.certificateRequest.nca = i+1;
116925fc6993SDavid du Colombier m->u.certificateRequest.cas = erealloc(
117025fc6993SDavid du Colombier m->u.certificateRequest.cas, (i+1)*sizeof(Bytes));
11719a747e4fSDavid du Colombier m->u.certificateRequest.cas[i] = makebytes(p, nn);
11729a747e4fSDavid du Colombier p += nn;
11739a747e4fSDavid du Colombier n -= nn;
11749a747e4fSDavid du Colombier i++;
11759a747e4fSDavid du Colombier }
11769a747e4fSDavid du Colombier break;
11779a747e4fSDavid du Colombier case HServerHelloDone:
11789a747e4fSDavid du Colombier break;
11799a747e4fSDavid du Colombier case HClientKeyExchange:
11809a747e4fSDavid du Colombier /*
11819a747e4fSDavid du Colombier * this message depends upon the encryption selected
11829a747e4fSDavid du Colombier * assume rsa.
11839a747e4fSDavid du Colombier */
11849a747e4fSDavid du Colombier if(c->version == SSL3Version)
11859a747e4fSDavid du Colombier nn = n;
11869a747e4fSDavid du Colombier else{
11879a747e4fSDavid du Colombier if(n < 2)
11889a747e4fSDavid du Colombier goto Short;
11899a747e4fSDavid du Colombier nn = get16(p);
11909a747e4fSDavid du Colombier p += 2;
11919a747e4fSDavid du Colombier n -= 2;
11929a747e4fSDavid du Colombier }
11939a747e4fSDavid du Colombier if(n < nn)
11949a747e4fSDavid du Colombier goto Short;
11959a747e4fSDavid du Colombier m->u.clientKeyExchange.key = makebytes(p, nn);
11969a747e4fSDavid du Colombier n -= nn;
11979a747e4fSDavid du Colombier break;
11989a747e4fSDavid du Colombier case HFinished:
11999a747e4fSDavid du Colombier m->u.finished.n = c->finished.n;
12009a747e4fSDavid du Colombier if(n < m->u.finished.n)
12019a747e4fSDavid du Colombier goto Short;
12029a747e4fSDavid du Colombier memmove(m->u.finished.verify, p, m->u.finished.n);
12039a747e4fSDavid du Colombier n -= m->u.finished.n;
12049a747e4fSDavid du Colombier break;
12059a747e4fSDavid du Colombier }
12069a747e4fSDavid du Colombier
12079a747e4fSDavid du Colombier if(type != HClientHello && n != 0)
12089a747e4fSDavid du Colombier goto Short;
12099a747e4fSDavid du Colombier Ok:
12109a747e4fSDavid du Colombier if(c->trace){
1211ed50b0e8SDavid du Colombier char *buf;
1212ed50b0e8SDavid du Colombier buf = emalloc(8000);
1213ed50b0e8SDavid du Colombier c->trace("recv %s", msgPrint(buf, 8000, m));
1214ed50b0e8SDavid du Colombier free(buf);
12159a747e4fSDavid du Colombier }
12169a747e4fSDavid du Colombier return 1;
12179a747e4fSDavid du Colombier Short:
12189a747e4fSDavid du Colombier tlsError(c, EDecodeError, "handshake message has invalid length");
12199a747e4fSDavid du Colombier Err:
12209a747e4fSDavid du Colombier msgClear(m);
12219a747e4fSDavid du Colombier return 0;
12229a747e4fSDavid du Colombier }
12239a747e4fSDavid du Colombier
12249a747e4fSDavid du Colombier static void
msgClear(Msg * m)12259a747e4fSDavid du Colombier msgClear(Msg *m)
12269a747e4fSDavid du Colombier {
12279a747e4fSDavid du Colombier int i;
12289a747e4fSDavid du Colombier
12299a747e4fSDavid du Colombier switch(m->tag) {
12309a747e4fSDavid du Colombier default:
123114cc0f53SDavid du Colombier sysfatal("msgClear: unknown message type: %d", m->tag);
12329a747e4fSDavid du Colombier case HHelloRequest:
12339a747e4fSDavid du Colombier break;
12349a747e4fSDavid du Colombier case HClientHello:
12359a747e4fSDavid du Colombier freebytes(m->u.clientHello.sid);
12369a747e4fSDavid du Colombier freeints(m->u.clientHello.ciphers);
12379a747e4fSDavid du Colombier freebytes(m->u.clientHello.compressors);
12389a747e4fSDavid du Colombier break;
12399a747e4fSDavid du Colombier case HServerHello:
12409a747e4fSDavid du Colombier freebytes(m->u.clientHello.sid);
12419a747e4fSDavid du Colombier break;
12429a747e4fSDavid du Colombier case HCertificate:
12439a747e4fSDavid du Colombier for(i=0; i<m->u.certificate.ncert; i++)
12449a747e4fSDavid du Colombier freebytes(m->u.certificate.certs[i]);
12459a747e4fSDavid du Colombier free(m->u.certificate.certs);
12469a747e4fSDavid du Colombier break;
12479a747e4fSDavid du Colombier case HCertificateRequest:
12489a747e4fSDavid du Colombier freebytes(m->u.certificateRequest.types);
12499a747e4fSDavid du Colombier for(i=0; i<m->u.certificateRequest.nca; i++)
12509a747e4fSDavid du Colombier freebytes(m->u.certificateRequest.cas[i]);
12519a747e4fSDavid du Colombier free(m->u.certificateRequest.cas);
12529a747e4fSDavid du Colombier break;
12539a747e4fSDavid du Colombier case HServerHelloDone:
12549a747e4fSDavid du Colombier break;
12559a747e4fSDavid du Colombier case HClientKeyExchange:
12569a747e4fSDavid du Colombier freebytes(m->u.clientKeyExchange.key);
12579a747e4fSDavid du Colombier break;
12589a747e4fSDavid du Colombier case HFinished:
12599a747e4fSDavid du Colombier break;
12609a747e4fSDavid du Colombier }
12619a747e4fSDavid du Colombier memset(m, 0, sizeof(Msg));
12629a747e4fSDavid du Colombier }
12639a747e4fSDavid du Colombier
12649a747e4fSDavid du Colombier static char *
bytesPrint(char * bs,char * be,char * s0,Bytes * b,char * s1)12659a747e4fSDavid du Colombier bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1)
12669a747e4fSDavid du Colombier {
12679a747e4fSDavid du Colombier int i;
12689a747e4fSDavid du Colombier
12699a747e4fSDavid du Colombier if(s0)
12709a747e4fSDavid du Colombier bs = seprint(bs, be, "%s", s0);
12719a747e4fSDavid du Colombier bs = seprint(bs, be, "[");
12729a747e4fSDavid du Colombier if(b == nil)
12739a747e4fSDavid du Colombier bs = seprint(bs, be, "nil");
12749a747e4fSDavid du Colombier else
12759a747e4fSDavid du Colombier for(i=0; i<b->len; i++)
12769a747e4fSDavid du Colombier bs = seprint(bs, be, "%.2x ", b->data[i]);
12779a747e4fSDavid du Colombier bs = seprint(bs, be, "]");
12789a747e4fSDavid du Colombier if(s1)
12799a747e4fSDavid du Colombier bs = seprint(bs, be, "%s", s1);
12809a747e4fSDavid du Colombier return bs;
12819a747e4fSDavid du Colombier }
12829a747e4fSDavid du Colombier
12839a747e4fSDavid du Colombier static char *
intsPrint(char * bs,char * be,char * s0,Ints * b,char * s1)12849a747e4fSDavid du Colombier intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1)
12859a747e4fSDavid du Colombier {
12869a747e4fSDavid du Colombier int i;
12879a747e4fSDavid du Colombier
12889a747e4fSDavid du Colombier if(s0)
12899a747e4fSDavid du Colombier bs = seprint(bs, be, "%s", s0);
12909a747e4fSDavid du Colombier bs = seprint(bs, be, "[");
12919a747e4fSDavid du Colombier if(b == nil)
12929a747e4fSDavid du Colombier bs = seprint(bs, be, "nil");
12939a747e4fSDavid du Colombier else
12949a747e4fSDavid du Colombier for(i=0; i<b->len; i++)
12959a747e4fSDavid du Colombier bs = seprint(bs, be, "%x ", b->data[i]);
12969a747e4fSDavid du Colombier bs = seprint(bs, be, "]");
12979a747e4fSDavid du Colombier if(s1)
12989a747e4fSDavid du Colombier bs = seprint(bs, be, "%s", s1);
12999a747e4fSDavid du Colombier return bs;
13009a747e4fSDavid du Colombier }
13019a747e4fSDavid du Colombier
13029a747e4fSDavid du Colombier static char*
msgPrint(char * buf,int n,Msg * m)13039a747e4fSDavid du Colombier msgPrint(char *buf, int n, Msg *m)
13049a747e4fSDavid du Colombier {
13059a747e4fSDavid du Colombier int i;
13069a747e4fSDavid du Colombier char *bs = buf, *be = buf+n;
13079a747e4fSDavid du Colombier
13089a747e4fSDavid du Colombier switch(m->tag) {
13099a747e4fSDavid du Colombier default:
13109a747e4fSDavid du Colombier bs = seprint(bs, be, "unknown %d\n", m->tag);
13119a747e4fSDavid du Colombier break;
13129a747e4fSDavid du Colombier case HClientHello:
13139a747e4fSDavid du Colombier bs = seprint(bs, be, "ClientHello\n");
13149a747e4fSDavid du Colombier bs = seprint(bs, be, "\tversion: %.4x\n", m->u.clientHello.version);
13159a747e4fSDavid du Colombier bs = seprint(bs, be, "\trandom: ");
13169a747e4fSDavid du Colombier for(i=0; i<RandomSize; i++)
13179a747e4fSDavid du Colombier bs = seprint(bs, be, "%.2x", m->u.clientHello.random[i]);
13189a747e4fSDavid du Colombier bs = seprint(bs, be, "\n");
13199a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\tsid: ", m->u.clientHello.sid, "\n");
13209a747e4fSDavid du Colombier bs = intsPrint(bs, be, "\tciphers: ", m->u.clientHello.ciphers, "\n");
13219a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\tcompressors: ", m->u.clientHello.compressors, "\n");
13229a747e4fSDavid du Colombier break;
13239a747e4fSDavid du Colombier case HServerHello:
13249a747e4fSDavid du Colombier bs = seprint(bs, be, "ServerHello\n");
13259a747e4fSDavid du Colombier bs = seprint(bs, be, "\tversion: %.4x\n", m->u.serverHello.version);
13269a747e4fSDavid du Colombier bs = seprint(bs, be, "\trandom: ");
13279a747e4fSDavid du Colombier for(i=0; i<RandomSize; i++)
13289a747e4fSDavid du Colombier bs = seprint(bs, be, "%.2x", m->u.serverHello.random[i]);
13299a747e4fSDavid du Colombier bs = seprint(bs, be, "\n");
13309a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\tsid: ", m->u.serverHello.sid, "\n");
13319a747e4fSDavid du Colombier bs = seprint(bs, be, "\tcipher: %.4x\n", m->u.serverHello.cipher);
13329a747e4fSDavid du Colombier bs = seprint(bs, be, "\tcompressor: %.2x\n", m->u.serverHello.compressor);
13339a747e4fSDavid du Colombier break;
13349a747e4fSDavid du Colombier case HCertificate:
13359a747e4fSDavid du Colombier bs = seprint(bs, be, "Certificate\n");
13369a747e4fSDavid du Colombier for(i=0; i<m->u.certificate.ncert; i++)
13379a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\t", m->u.certificate.certs[i], "\n");
13389a747e4fSDavid du Colombier break;
13399a747e4fSDavid du Colombier case HCertificateRequest:
13409a747e4fSDavid du Colombier bs = seprint(bs, be, "CertificateRequest\n");
13419a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n");
13429a747e4fSDavid du Colombier bs = seprint(bs, be, "\tcertificateauthorities\n");
13439a747e4fSDavid du Colombier for(i=0; i<m->u.certificateRequest.nca; i++)
13449a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
13459a747e4fSDavid du Colombier break;
13469a747e4fSDavid du Colombier case HServerHelloDone:
13479a747e4fSDavid du Colombier bs = seprint(bs, be, "ServerHelloDone\n");
13489a747e4fSDavid du Colombier break;
13499a747e4fSDavid du Colombier case HClientKeyExchange:
13509a747e4fSDavid du Colombier bs = seprint(bs, be, "HClientKeyExchange\n");
13519a747e4fSDavid du Colombier bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n");
13529a747e4fSDavid du Colombier break;
13539a747e4fSDavid du Colombier case HFinished:
13549a747e4fSDavid du Colombier bs = seprint(bs, be, "HFinished\n");
13559a747e4fSDavid du Colombier for(i=0; i<m->u.finished.n; i++)
13569a747e4fSDavid du Colombier bs = seprint(bs, be, "%.2x", m->u.finished.verify[i]);
13579a747e4fSDavid du Colombier bs = seprint(bs, be, "\n");
13589a747e4fSDavid du Colombier break;
13599a747e4fSDavid du Colombier }
13609a747e4fSDavid du Colombier USED(bs);
13619a747e4fSDavid du Colombier return buf;
13629a747e4fSDavid du Colombier }
13639a747e4fSDavid du Colombier
13649a747e4fSDavid du Colombier static void
tlsError(TlsConnection * c,int err,char * fmt,...)13659a747e4fSDavid du Colombier tlsError(TlsConnection *c, int err, char *fmt, ...)
13669a747e4fSDavid du Colombier {
13679a747e4fSDavid du Colombier char msg[512];
13689a747e4fSDavid du Colombier va_list arg;
13699a747e4fSDavid du Colombier
13709a747e4fSDavid du Colombier va_start(arg, fmt);
13719a747e4fSDavid du Colombier vseprint(msg, msg+sizeof(msg), fmt, arg);
13729a747e4fSDavid du Colombier va_end(arg);
13739a747e4fSDavid du Colombier if(c->trace)
13749a747e4fSDavid du Colombier c->trace("tlsError: %s\n", msg);
13759a747e4fSDavid du Colombier else if(c->erred)
13769a747e4fSDavid du Colombier fprint(2, "double error: %r, %s", msg);
13779a747e4fSDavid du Colombier else
13789a747e4fSDavid du Colombier werrstr("tls: local %s", msg);
13799a747e4fSDavid du Colombier c->erred = 1;
13809a747e4fSDavid du Colombier fprint(c->ctl, "alert %d", err);
13819a747e4fSDavid du Colombier }
13829a747e4fSDavid du Colombier
13839a747e4fSDavid du Colombier // commit to specific version number
13849a747e4fSDavid du Colombier static int
setVersion(TlsConnection * c,int version)13859a747e4fSDavid du Colombier setVersion(TlsConnection *c, int version)
13869a747e4fSDavid du Colombier {
13879a747e4fSDavid du Colombier if(c->verset || version > MaxProtoVersion || version < MinProtoVersion)
13889a747e4fSDavid du Colombier return -1;
13899a747e4fSDavid du Colombier if(version > c->version)
13909a747e4fSDavid du Colombier version = c->version;
13919a747e4fSDavid du Colombier if(version == SSL3Version) {
13929a747e4fSDavid du Colombier c->version = version;
13939a747e4fSDavid du Colombier c->finished.n = SSL3FinishedLen;
13949a747e4fSDavid du Colombier }else if(version == TLSVersion){
13959a747e4fSDavid du Colombier c->version = version;
13969a747e4fSDavid du Colombier c->finished.n = TLSFinishedLen;
13979a747e4fSDavid du Colombier }else
13989a747e4fSDavid du Colombier return -1;
13999a747e4fSDavid du Colombier c->verset = 1;
14009a747e4fSDavid du Colombier return fprint(c->ctl, "version 0x%x", version);
14019a747e4fSDavid du Colombier }
14029a747e4fSDavid du Colombier
14039a747e4fSDavid du Colombier // confirm that received Finished message matches the expected value
14049a747e4fSDavid du Colombier static int
finishedMatch(TlsConnection * c,Finished * f)14059a747e4fSDavid du Colombier finishedMatch(TlsConnection *c, Finished *f)
14069a747e4fSDavid du Colombier {
14079a747e4fSDavid du Colombier return memcmp(f->verify, c->finished.verify, f->n) == 0;
14089a747e4fSDavid du Colombier }
14099a747e4fSDavid du Colombier
14109a747e4fSDavid du Colombier // free memory associated with TlsConnection struct
14119a747e4fSDavid du Colombier // (but don't close the TLS channel itself)
14129a747e4fSDavid du Colombier static void
tlsConnectionFree(TlsConnection * c)14139a747e4fSDavid du Colombier tlsConnectionFree(TlsConnection *c)
14149a747e4fSDavid du Colombier {
14159a747e4fSDavid du Colombier tlsSecClose(c->sec);
14169a747e4fSDavid du Colombier freebytes(c->sid);
14179a747e4fSDavid du Colombier freebytes(c->cert);
14189a747e4fSDavid du Colombier memset(c, 0, sizeof(c));
14199a747e4fSDavid du Colombier free(c);
14209a747e4fSDavid du Colombier }
14219a747e4fSDavid du Colombier
14229a747e4fSDavid du Colombier
14239a747e4fSDavid du Colombier //================= cipher choices ========================
14249a747e4fSDavid du Colombier
14259a747e4fSDavid du Colombier static int weakCipher[CipherMax] =
14269a747e4fSDavid du Colombier {
14279a747e4fSDavid du Colombier 1, /* TLS_NULL_WITH_NULL_NULL */
14289a747e4fSDavid du Colombier 1, /* TLS_RSA_WITH_NULL_MD5 */
14299a747e4fSDavid du Colombier 1, /* TLS_RSA_WITH_NULL_SHA */
14309a747e4fSDavid du Colombier 1, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */
14319a747e4fSDavid du Colombier 0, /* TLS_RSA_WITH_RC4_128_MD5 */
14329a747e4fSDavid du Colombier 0, /* TLS_RSA_WITH_RC4_128_SHA */
14339a747e4fSDavid du Colombier 1, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */
14349a747e4fSDavid du Colombier 0, /* TLS_RSA_WITH_IDEA_CBC_SHA */
14359a747e4fSDavid du Colombier 1, /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */
14369a747e4fSDavid du Colombier 0, /* TLS_RSA_WITH_DES_CBC_SHA */
14379a747e4fSDavid du Colombier 0, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */
14389a747e4fSDavid du Colombier 1, /* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */
14399a747e4fSDavid du Colombier 0, /* TLS_DH_DSS_WITH_DES_CBC_SHA */
14409a747e4fSDavid du Colombier 0, /* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */
14419a747e4fSDavid du Colombier 1, /* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */
14429a747e4fSDavid du Colombier 0, /* TLS_DH_RSA_WITH_DES_CBC_SHA */
14439a747e4fSDavid du Colombier 0, /* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */
14449a747e4fSDavid du Colombier 1, /* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */
14459a747e4fSDavid du Colombier 0, /* TLS_DHE_DSS_WITH_DES_CBC_SHA */
14469a747e4fSDavid du Colombier 0, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */
14479a747e4fSDavid du Colombier 1, /* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */
14489a747e4fSDavid du Colombier 0, /* TLS_DHE_RSA_WITH_DES_CBC_SHA */
14499a747e4fSDavid du Colombier 0, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */
14509a747e4fSDavid du Colombier 1, /* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */
14519a747e4fSDavid du Colombier 1, /* TLS_DH_anon_WITH_RC4_128_MD5 */
14529a747e4fSDavid du Colombier 1, /* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */
14539a747e4fSDavid du Colombier 1, /* TLS_DH_anon_WITH_DES_CBC_SHA */
14549a747e4fSDavid du Colombier 1, /* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */
14559a747e4fSDavid du Colombier };
14569a747e4fSDavid du Colombier
14579a747e4fSDavid du Colombier static int
setAlgs(TlsConnection * c,int a)14589a747e4fSDavid du Colombier setAlgs(TlsConnection *c, int a)
14599a747e4fSDavid du Colombier {
14609a747e4fSDavid du Colombier int i;
14619a747e4fSDavid du Colombier
14629a747e4fSDavid du Colombier for(i = 0; i < nelem(cipherAlgs); i++){
14639a747e4fSDavid du Colombier if(cipherAlgs[i].tlsid == a){
14649a747e4fSDavid du Colombier c->enc = cipherAlgs[i].enc;
14659a747e4fSDavid du Colombier c->digest = cipherAlgs[i].digest;
14669a747e4fSDavid du Colombier c->nsecret = cipherAlgs[i].nsecret;
14679a747e4fSDavid du Colombier if(c->nsecret > MaxKeyData)
14689a747e4fSDavid du Colombier return 0;
14699a747e4fSDavid du Colombier return 1;
14709a747e4fSDavid du Colombier }
14719a747e4fSDavid du Colombier }
14729a747e4fSDavid du Colombier return 0;
14739a747e4fSDavid du Colombier }
14749a747e4fSDavid du Colombier
14759a747e4fSDavid du Colombier static int
okCipher(Ints * cv)14769a747e4fSDavid du Colombier okCipher(Ints *cv)
14779a747e4fSDavid du Colombier {
14789a747e4fSDavid du Colombier int weak, i, j, c;
14799a747e4fSDavid du Colombier
14809a747e4fSDavid du Colombier weak = 1;
14819a747e4fSDavid du Colombier for(i = 0; i < cv->len; i++) {
14829a747e4fSDavid du Colombier c = cv->data[i];
14839a747e4fSDavid du Colombier if(c >= CipherMax)
14849a747e4fSDavid du Colombier weak = 0;
14859a747e4fSDavid du Colombier else
14869a747e4fSDavid du Colombier weak &= weakCipher[c];
14879a747e4fSDavid du Colombier for(j = 0; j < nelem(cipherAlgs); j++)
14889a747e4fSDavid du Colombier if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
14899a747e4fSDavid du Colombier return c;
14909a747e4fSDavid du Colombier }
14919a747e4fSDavid du Colombier if(weak)
14929a747e4fSDavid du Colombier return -2;
14939a747e4fSDavid du Colombier return -1;
14949a747e4fSDavid du Colombier }
14959a747e4fSDavid du Colombier
14969a747e4fSDavid du Colombier static int
okCompression(Bytes * cv)14979a747e4fSDavid du Colombier okCompression(Bytes *cv)
14989a747e4fSDavid du Colombier {
14999a747e4fSDavid du Colombier int i, j, c;
15009a747e4fSDavid du Colombier
15019a747e4fSDavid du Colombier for(i = 0; i < cv->len; i++) {
15029a747e4fSDavid du Colombier c = cv->data[i];
15039a747e4fSDavid du Colombier for(j = 0; j < nelem(compressors); j++) {
15049a747e4fSDavid du Colombier if(compressors[j] == c)
15059a747e4fSDavid du Colombier return c;
15069a747e4fSDavid du Colombier }
15079a747e4fSDavid du Colombier }
15089a747e4fSDavid du Colombier return -1;
15099a747e4fSDavid du Colombier }
15109a747e4fSDavid du Colombier
15119a747e4fSDavid du Colombier static Lock ciphLock;
15129a747e4fSDavid du Colombier static int nciphers;
15139a747e4fSDavid du Colombier
15149a747e4fSDavid du Colombier static int
initCiphers(void)15159a747e4fSDavid du Colombier initCiphers(void)
15169a747e4fSDavid du Colombier {
15179a747e4fSDavid du Colombier enum {MaxAlgF = 1024, MaxAlgs = 10};
15189a747e4fSDavid du Colombier char s[MaxAlgF], *flds[MaxAlgs];
15199a747e4fSDavid du Colombier int i, j, n, ok;
15209a747e4fSDavid du Colombier
15219a747e4fSDavid du Colombier lock(&ciphLock);
15229a747e4fSDavid du Colombier if(nciphers){
15239a747e4fSDavid du Colombier unlock(&ciphLock);
15249a747e4fSDavid du Colombier return nciphers;
15259a747e4fSDavid du Colombier }
15269a747e4fSDavid du Colombier j = open("#a/tls/encalgs", OREAD);
15279a747e4fSDavid du Colombier if(j < 0){
15289a747e4fSDavid du Colombier werrstr("can't open #a/tls/encalgs: %r");
15299a747e4fSDavid du Colombier return 0;
15309a747e4fSDavid du Colombier }
15319a747e4fSDavid du Colombier n = read(j, s, MaxAlgF-1);
15329a747e4fSDavid du Colombier close(j);
15339a747e4fSDavid du Colombier if(n <= 0){
15349a747e4fSDavid du Colombier werrstr("nothing in #a/tls/encalgs: %r");
15359a747e4fSDavid du Colombier return 0;
15369a747e4fSDavid du Colombier }
15379a747e4fSDavid du Colombier s[n] = 0;
15389a747e4fSDavid du Colombier n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
15399a747e4fSDavid du Colombier for(i = 0; i < nelem(cipherAlgs); i++){
15409a747e4fSDavid du Colombier ok = 0;
15419a747e4fSDavid du Colombier for(j = 0; j < n; j++){
15429a747e4fSDavid du Colombier if(strcmp(cipherAlgs[i].enc, flds[j]) == 0){
15439a747e4fSDavid du Colombier ok = 1;
15449a747e4fSDavid du Colombier break;
15459a747e4fSDavid du Colombier }
15469a747e4fSDavid du Colombier }
15479a747e4fSDavid du Colombier cipherAlgs[i].ok = ok;
15489a747e4fSDavid du Colombier }
15499a747e4fSDavid du Colombier
15509a747e4fSDavid du Colombier j = open("#a/tls/hashalgs", OREAD);
15519a747e4fSDavid du Colombier if(j < 0){
15529a747e4fSDavid du Colombier werrstr("can't open #a/tls/hashalgs: %r");
15539a747e4fSDavid du Colombier return 0;
15549a747e4fSDavid du Colombier }
15559a747e4fSDavid du Colombier n = read(j, s, MaxAlgF-1);
15569a747e4fSDavid du Colombier close(j);
15579a747e4fSDavid du Colombier if(n <= 0){
15589a747e4fSDavid du Colombier werrstr("nothing in #a/tls/hashalgs: %r");
15599a747e4fSDavid du Colombier return 0;
15609a747e4fSDavid du Colombier }
15619a747e4fSDavid du Colombier s[n] = 0;
15629a747e4fSDavid du Colombier n = getfields(s, flds, MaxAlgs, 1, " \t\r\n");
15639a747e4fSDavid du Colombier for(i = 0; i < nelem(cipherAlgs); i++){
15649a747e4fSDavid du Colombier ok = 0;
15659a747e4fSDavid du Colombier for(j = 0; j < n; j++){
15669a747e4fSDavid du Colombier if(strcmp(cipherAlgs[i].digest, flds[j]) == 0){
15679a747e4fSDavid du Colombier ok = 1;
15689a747e4fSDavid du Colombier break;
15699a747e4fSDavid du Colombier }
15709a747e4fSDavid du Colombier }
15719a747e4fSDavid du Colombier cipherAlgs[i].ok &= ok;
15729a747e4fSDavid du Colombier if(cipherAlgs[i].ok)
15739a747e4fSDavid du Colombier nciphers++;
15749a747e4fSDavid du Colombier }
15759a747e4fSDavid du Colombier unlock(&ciphLock);
15769a747e4fSDavid du Colombier return nciphers;
15779a747e4fSDavid du Colombier }
15789a747e4fSDavid du Colombier
15799a747e4fSDavid du Colombier static Ints*
makeciphers(void)15809a747e4fSDavid du Colombier makeciphers(void)
15819a747e4fSDavid du Colombier {
15829a747e4fSDavid du Colombier Ints *is;
15839a747e4fSDavid du Colombier int i, j;
15849a747e4fSDavid du Colombier
15859a747e4fSDavid du Colombier is = newints(nciphers);
15869a747e4fSDavid du Colombier j = 0;
15879a747e4fSDavid du Colombier for(i = 0; i < nelem(cipherAlgs); i++){
15889a747e4fSDavid du Colombier if(cipherAlgs[i].ok)
15899a747e4fSDavid du Colombier is->data[j++] = cipherAlgs[i].tlsid;
15909a747e4fSDavid du Colombier }
15919a747e4fSDavid du Colombier return is;
15929a747e4fSDavid du Colombier }
15939a747e4fSDavid du Colombier
15949a747e4fSDavid du Colombier
15959a747e4fSDavid du Colombier
15969a747e4fSDavid du Colombier //================= security functions ========================
15979a747e4fSDavid du Colombier
15989a747e4fSDavid du Colombier // given X.509 certificate, set up connection to factotum
15999a747e4fSDavid du Colombier // for using corresponding private key
16009a747e4fSDavid du Colombier static AuthRpc*
factotum_rsa_open(uchar * cert,int certlen)16019a747e4fSDavid du Colombier factotum_rsa_open(uchar *cert, int certlen)
16029a747e4fSDavid du Colombier {
16039a747e4fSDavid du Colombier int afd;
16049a747e4fSDavid du Colombier char *s;
16059a747e4fSDavid du Colombier mpint *pub = nil;
16069a747e4fSDavid du Colombier RSApub *rsapub;
16079a747e4fSDavid du Colombier AuthRpc *rpc;
16089a747e4fSDavid du Colombier
16099a747e4fSDavid du Colombier // start talking to factotum
16109a747e4fSDavid du Colombier if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
16119a747e4fSDavid du Colombier return nil;
16129a747e4fSDavid du Colombier if((rpc = auth_allocrpc(afd)) == nil){
16139a747e4fSDavid du Colombier close(afd);
16149a747e4fSDavid du Colombier return nil;
16159a747e4fSDavid du Colombier }
161665fa3f8bSDavid du Colombier s = "proto=rsa service=tls role=client";
16179a747e4fSDavid du Colombier if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
16189a747e4fSDavid du Colombier factotum_rsa_close(rpc);
16199a747e4fSDavid du Colombier return nil;
16209a747e4fSDavid du Colombier }
16219a747e4fSDavid du Colombier
16229a747e4fSDavid du Colombier // roll factotum keyring around to match certificate
16239a747e4fSDavid du Colombier rsapub = X509toRSApub(cert, certlen, nil, 0);
16249a747e4fSDavid du Colombier while(1){
16259a747e4fSDavid du Colombier if(auth_rpc(rpc, "read", nil, 0) != ARok){
16269a747e4fSDavid du Colombier factotum_rsa_close(rpc);
16279a747e4fSDavid du Colombier rpc = nil;
16289a747e4fSDavid du Colombier goto done;
16299a747e4fSDavid du Colombier }
16309a747e4fSDavid du Colombier pub = strtomp(rpc->arg, nil, 16, nil);
16319a747e4fSDavid du Colombier assert(pub != nil);
16329a747e4fSDavid du Colombier if(mpcmp(pub,rsapub->n) == 0)
16339a747e4fSDavid du Colombier break;
16349a747e4fSDavid du Colombier }
16359a747e4fSDavid du Colombier done:
16369a747e4fSDavid du Colombier mpfree(pub);
16379a747e4fSDavid du Colombier rsapubfree(rsapub);
16389a747e4fSDavid du Colombier return rpc;
16399a747e4fSDavid du Colombier }
16409a747e4fSDavid du Colombier
16419a747e4fSDavid du Colombier static mpint*
factotum_rsa_decrypt(AuthRpc * rpc,mpint * cipher)16429a747e4fSDavid du Colombier factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher)
16439a747e4fSDavid du Colombier {
16449a747e4fSDavid du Colombier char *p;
16459a747e4fSDavid du Colombier int rv;
16469a747e4fSDavid du Colombier
16479a747e4fSDavid du Colombier if((p = mptoa(cipher, 16, nil, 0)) == nil)
16489a747e4fSDavid du Colombier return nil;
16499a747e4fSDavid du Colombier rv = auth_rpc(rpc, "write", p, strlen(p));
16509a747e4fSDavid du Colombier free(p);
16519a747e4fSDavid du Colombier if(rv != ARok || auth_rpc(rpc, "read", nil, 0) != ARok)
16529a747e4fSDavid du Colombier return nil;
16539a747e4fSDavid du Colombier mpfree(cipher);
16549a747e4fSDavid du Colombier return strtomp(rpc->arg, nil, 16, nil);
16559a747e4fSDavid du Colombier }
16569a747e4fSDavid du Colombier
16579a747e4fSDavid du Colombier static void
factotum_rsa_close(AuthRpc * rpc)16589a747e4fSDavid du Colombier factotum_rsa_close(AuthRpc*rpc)
16599a747e4fSDavid du Colombier {
16609a747e4fSDavid du Colombier if(!rpc)
16619a747e4fSDavid du Colombier return;
16629a747e4fSDavid du Colombier close(rpc->afd);
16639a747e4fSDavid du Colombier auth_freerpc(rpc);
16649a747e4fSDavid du Colombier }
16659a747e4fSDavid du Colombier
16669a747e4fSDavid 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)16679a747e4fSDavid du Colombier tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
16689a747e4fSDavid du Colombier {
16699a747e4fSDavid du Colombier uchar ai[MD5dlen], tmp[MD5dlen];
16709a747e4fSDavid du Colombier int i, n;
16719a747e4fSDavid du Colombier MD5state *s;
16729a747e4fSDavid du Colombier
16739a747e4fSDavid du Colombier // generate a1
16749a747e4fSDavid du Colombier s = hmac_md5(label, nlabel, key, nkey, nil, nil);
16759a747e4fSDavid du Colombier s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
16769a747e4fSDavid du Colombier hmac_md5(seed1, nseed1, key, nkey, ai, s);
16779a747e4fSDavid du Colombier
16789a747e4fSDavid du Colombier while(nbuf > 0) {
16799a747e4fSDavid du Colombier s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil);
16809a747e4fSDavid du Colombier s = hmac_md5(label, nlabel, key, nkey, nil, s);
16819a747e4fSDavid du Colombier s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
16829a747e4fSDavid du Colombier hmac_md5(seed1, nseed1, key, nkey, tmp, s);
16839a747e4fSDavid du Colombier n = MD5dlen;
16849a747e4fSDavid du Colombier if(n > nbuf)
16859a747e4fSDavid du Colombier n = nbuf;
16869a747e4fSDavid du Colombier for(i = 0; i < n; i++)
16879a747e4fSDavid du Colombier buf[i] ^= tmp[i];
16889a747e4fSDavid du Colombier buf += n;
16899a747e4fSDavid du Colombier nbuf -= n;
16909a747e4fSDavid du Colombier hmac_md5(ai, MD5dlen, key, nkey, tmp, nil);
16919a747e4fSDavid du Colombier memmove(ai, tmp, MD5dlen);
16929a747e4fSDavid du Colombier }
16939a747e4fSDavid du Colombier }
16949a747e4fSDavid du Colombier
16959a747e4fSDavid 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)16969a747e4fSDavid du Colombier tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
16979a747e4fSDavid du Colombier {
16989a747e4fSDavid du Colombier uchar ai[SHA1dlen], tmp[SHA1dlen];
16999a747e4fSDavid du Colombier int i, n;
17009a747e4fSDavid du Colombier SHAstate *s;
17019a747e4fSDavid du Colombier
17029a747e4fSDavid du Colombier // generate a1
17039a747e4fSDavid du Colombier s = hmac_sha1(label, nlabel, key, nkey, nil, nil);
17049a747e4fSDavid du Colombier s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
17059a747e4fSDavid du Colombier hmac_sha1(seed1, nseed1, key, nkey, ai, s);
17069a747e4fSDavid du Colombier
17079a747e4fSDavid du Colombier while(nbuf > 0) {
17089a747e4fSDavid du Colombier s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil);
17099a747e4fSDavid du Colombier s = hmac_sha1(label, nlabel, key, nkey, nil, s);
17109a747e4fSDavid du Colombier s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
17119a747e4fSDavid du Colombier hmac_sha1(seed1, nseed1, key, nkey, tmp, s);
17129a747e4fSDavid du Colombier n = SHA1dlen;
17139a747e4fSDavid du Colombier if(n > nbuf)
17149a747e4fSDavid du Colombier n = nbuf;
17159a747e4fSDavid du Colombier for(i = 0; i < n; i++)
17169a747e4fSDavid du Colombier buf[i] ^= tmp[i];
17179a747e4fSDavid du Colombier buf += n;
17189a747e4fSDavid du Colombier nbuf -= n;
17199a747e4fSDavid du Colombier hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil);
17209a747e4fSDavid du Colombier memmove(ai, tmp, SHA1dlen);
17219a747e4fSDavid du Colombier }
17229a747e4fSDavid du Colombier }
17239a747e4fSDavid du Colombier
17249a747e4fSDavid du Colombier // fill buf with md5(args)^sha1(args)
17259a747e4fSDavid du Colombier static void
tlsPRF(uchar * buf,int nbuf,uchar * key,int nkey,char * label,uchar * seed0,int nseed0,uchar * seed1,int nseed1)17269a747e4fSDavid du Colombier tlsPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
17279a747e4fSDavid du Colombier {
17289a747e4fSDavid du Colombier int i;
17299a747e4fSDavid du Colombier int nlabel = strlen(label);
17309a747e4fSDavid du Colombier int n = (nkey + 1) >> 1;
17319a747e4fSDavid du Colombier
17329a747e4fSDavid du Colombier for(i = 0; i < nbuf; i++)
17339a747e4fSDavid du Colombier buf[i] = 0;
17349a747e4fSDavid du Colombier tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
17359a747e4fSDavid du Colombier tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
17369a747e4fSDavid du Colombier }
17379a747e4fSDavid du Colombier
17389a747e4fSDavid du Colombier /*
17399a747e4fSDavid du Colombier * for setting server session id's
17409a747e4fSDavid du Colombier */
17419a747e4fSDavid du Colombier static Lock sidLock;
17429a747e4fSDavid du Colombier static long maxSid = 1;
17439a747e4fSDavid du Colombier
17449a747e4fSDavid du Colombier /* the keys are verified to have the same public components
17459a747e4fSDavid du Colombier * and to function correctly with pkcs 1 encryption and decryption. */
17469a747e4fSDavid du Colombier static TlsSec*
tlsSecInits(int cvers,uchar * csid,int ncsid,uchar * crandom,uchar * ssid,int * nssid,uchar * srandom)17479a747e4fSDavid du Colombier tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom)
17489a747e4fSDavid du Colombier {
17499a747e4fSDavid du Colombier TlsSec *sec = emalloc(sizeof(*sec));
17509a747e4fSDavid du Colombier
17519a747e4fSDavid du Colombier USED(csid); USED(ncsid); // ignore csid for now
17529a747e4fSDavid du Colombier
17539a747e4fSDavid du Colombier memmove(sec->crandom, crandom, RandomSize);
17549a747e4fSDavid du Colombier sec->clientVers = cvers;
17559a747e4fSDavid du Colombier
17569a747e4fSDavid du Colombier put32(sec->srandom, time(0));
17579a747e4fSDavid du Colombier genrandom(sec->srandom+4, RandomSize-4);
17589a747e4fSDavid du Colombier memmove(srandom, sec->srandom, RandomSize);
17599a747e4fSDavid du Colombier
17609a747e4fSDavid du Colombier /*
17619a747e4fSDavid du Colombier * make up a unique sid: use our pid, and and incrementing id
17629a747e4fSDavid du Colombier * can signal no sid by setting nssid to 0.
17639a747e4fSDavid du Colombier */
17649a747e4fSDavid du Colombier memset(ssid, 0, SidSize);
17659a747e4fSDavid du Colombier put32(ssid, getpid());
17669a747e4fSDavid du Colombier lock(&sidLock);
17679a747e4fSDavid du Colombier put32(ssid+4, maxSid++);
17689a747e4fSDavid du Colombier unlock(&sidLock);
17699a747e4fSDavid du Colombier *nssid = SidSize;
17709a747e4fSDavid du Colombier return sec;
17719a747e4fSDavid du Colombier }
17729a747e4fSDavid du Colombier
17739a747e4fSDavid du Colombier static int
tlsSecSecrets(TlsSec * sec,int vers,uchar * epm,int nepm,uchar * kd,int nkd)17749a747e4fSDavid du Colombier tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd)
17759a747e4fSDavid du Colombier {
17769a747e4fSDavid du Colombier if(epm != nil){
17779a747e4fSDavid du Colombier if(setVers(sec, vers) < 0)
17789a747e4fSDavid du Colombier goto Err;
17799a747e4fSDavid du Colombier serverMasterSecret(sec, epm, nepm);
17809a747e4fSDavid du Colombier }else if(sec->vers != vers){
17819a747e4fSDavid du Colombier werrstr("mismatched session versions");
17829a747e4fSDavid du Colombier goto Err;
17839a747e4fSDavid du Colombier }
17849a747e4fSDavid du Colombier setSecrets(sec, kd, nkd);
17859a747e4fSDavid du Colombier return 0;
17869a747e4fSDavid du Colombier Err:
17879a747e4fSDavid du Colombier sec->ok = -1;
17889a747e4fSDavid du Colombier return -1;
17899a747e4fSDavid du Colombier }
17909a747e4fSDavid du Colombier
17919a747e4fSDavid du Colombier static TlsSec*
tlsSecInitc(int cvers,uchar * crandom)17929a747e4fSDavid du Colombier tlsSecInitc(int cvers, uchar *crandom)
17939a747e4fSDavid du Colombier {
17949a747e4fSDavid du Colombier TlsSec *sec = emalloc(sizeof(*sec));
17959a747e4fSDavid du Colombier sec->clientVers = cvers;
17969a747e4fSDavid du Colombier put32(sec->crandom, time(0));
17979a747e4fSDavid du Colombier genrandom(sec->crandom+4, RandomSize-4);
17989a747e4fSDavid du Colombier memmove(crandom, sec->crandom, RandomSize);
17999a747e4fSDavid du Colombier return sec;
18009a747e4fSDavid du Colombier }
18019a747e4fSDavid du Colombier
18029a747e4fSDavid 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)18039a747e4fSDavid 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)
18049a747e4fSDavid du Colombier {
18059a747e4fSDavid du Colombier RSApub *pub;
18069a747e4fSDavid du Colombier
18079a747e4fSDavid du Colombier pub = nil;
18089a747e4fSDavid du Colombier
18099a747e4fSDavid du Colombier USED(sid);
18109a747e4fSDavid du Colombier USED(nsid);
18119a747e4fSDavid du Colombier
18129a747e4fSDavid du Colombier memmove(sec->srandom, srandom, RandomSize);
18139a747e4fSDavid du Colombier
18149a747e4fSDavid du Colombier if(setVers(sec, vers) < 0)
18159a747e4fSDavid du Colombier goto Err;
18169a747e4fSDavid du Colombier
18179a747e4fSDavid du Colombier pub = X509toRSApub(cert, ncert, nil, 0);
18189a747e4fSDavid du Colombier if(pub == nil){
18199a747e4fSDavid du Colombier werrstr("invalid x509/rsa certificate");
18209a747e4fSDavid du Colombier goto Err;
18219a747e4fSDavid du Colombier }
18229a747e4fSDavid du Colombier if(clientMasterSecret(sec, pub, epm, nepm) < 0)
18239a747e4fSDavid du Colombier goto Err;
18249a747e4fSDavid du Colombier rsapubfree(pub);
18259a747e4fSDavid du Colombier setSecrets(sec, kd, nkd);
18269a747e4fSDavid du Colombier return 0;
18279a747e4fSDavid du Colombier
18289a747e4fSDavid du Colombier Err:
18299a747e4fSDavid du Colombier if(pub != nil)
18309a747e4fSDavid du Colombier rsapubfree(pub);
18319a747e4fSDavid du Colombier sec->ok = -1;
18329a747e4fSDavid du Colombier return -1;
18339a747e4fSDavid du Colombier }
18349a747e4fSDavid du Colombier
18359a747e4fSDavid du Colombier static int
tlsSecFinished(TlsSec * sec,MD5state md5,SHAstate sha1,uchar * fin,int nfin,int isclient)18369a747e4fSDavid du Colombier tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient)
18379a747e4fSDavid du Colombier {
18389a747e4fSDavid du Colombier if(sec->nfin != nfin){
18399a747e4fSDavid du Colombier sec->ok = -1;
18409a747e4fSDavid du Colombier werrstr("invalid finished exchange");
18419a747e4fSDavid du Colombier return -1;
18429a747e4fSDavid du Colombier }
18439a747e4fSDavid du Colombier md5.malloced = 0;
18449a747e4fSDavid du Colombier sha1.malloced = 0;
18459a747e4fSDavid du Colombier (*sec->setFinished)(sec, md5, sha1, fin, isclient);
18469a747e4fSDavid du Colombier return 1;
18479a747e4fSDavid du Colombier }
18489a747e4fSDavid du Colombier
18499a747e4fSDavid du Colombier static void
tlsSecOk(TlsSec * sec)18509a747e4fSDavid du Colombier tlsSecOk(TlsSec *sec)
18519a747e4fSDavid du Colombier {
18529a747e4fSDavid du Colombier if(sec->ok == 0)
18539a747e4fSDavid du Colombier sec->ok = 1;
18549a747e4fSDavid du Colombier }
18559a747e4fSDavid du Colombier
18569a747e4fSDavid du Colombier static void
tlsSecKill(TlsSec * sec)18579a747e4fSDavid du Colombier tlsSecKill(TlsSec *sec)
18589a747e4fSDavid du Colombier {
18599a747e4fSDavid du Colombier if(!sec)
18609a747e4fSDavid du Colombier return;
18619a747e4fSDavid du Colombier factotum_rsa_close(sec->rpc);
18629a747e4fSDavid du Colombier sec->ok = -1;
18639a747e4fSDavid du Colombier }
18649a747e4fSDavid du Colombier
18659a747e4fSDavid du Colombier static void
tlsSecClose(TlsSec * sec)18669a747e4fSDavid du Colombier tlsSecClose(TlsSec *sec)
18679a747e4fSDavid du Colombier {
18689a747e4fSDavid du Colombier if(!sec)
18699a747e4fSDavid du Colombier return;
18709a747e4fSDavid du Colombier factotum_rsa_close(sec->rpc);
18719a747e4fSDavid du Colombier free(sec->server);
18729a747e4fSDavid du Colombier free(sec);
18739a747e4fSDavid du Colombier }
18749a747e4fSDavid du Colombier
18759a747e4fSDavid du Colombier static int
setVers(TlsSec * sec,int v)18769a747e4fSDavid du Colombier setVers(TlsSec *sec, int v)
18779a747e4fSDavid du Colombier {
18789a747e4fSDavid du Colombier if(v == SSL3Version){
18799a747e4fSDavid du Colombier sec->setFinished = sslSetFinished;
18809a747e4fSDavid du Colombier sec->nfin = SSL3FinishedLen;
18819a747e4fSDavid du Colombier sec->prf = sslPRF;
18829a747e4fSDavid du Colombier }else if(v == TLSVersion){
18839a747e4fSDavid du Colombier sec->setFinished = tlsSetFinished;
18849a747e4fSDavid du Colombier sec->nfin = TLSFinishedLen;
18859a747e4fSDavid du Colombier sec->prf = tlsPRF;
18869a747e4fSDavid du Colombier }else{
18879a747e4fSDavid du Colombier werrstr("invalid version");
18889a747e4fSDavid du Colombier return -1;
18899a747e4fSDavid du Colombier }
18909a747e4fSDavid du Colombier sec->vers = v;
18919a747e4fSDavid du Colombier return 0;
18929a747e4fSDavid du Colombier }
18939a747e4fSDavid du Colombier
18949a747e4fSDavid du Colombier /*
18959a747e4fSDavid du Colombier * generate secret keys from the master secret.
18969a747e4fSDavid du Colombier *
18979a747e4fSDavid du Colombier * different crypto selections will require different amounts
18989a747e4fSDavid du Colombier * of key expansion and use of key expansion data,
18999a747e4fSDavid du Colombier * but it's all generated using the same function.
19009a747e4fSDavid du Colombier */
19019a747e4fSDavid du Colombier static void
setSecrets(TlsSec * sec,uchar * kd,int nkd)19029a747e4fSDavid du Colombier setSecrets(TlsSec *sec, uchar *kd, int nkd)
19039a747e4fSDavid du Colombier {
19049a747e4fSDavid du Colombier (*sec->prf)(kd, nkd, sec->sec, MasterSecretSize, "key expansion",
19059a747e4fSDavid du Colombier sec->srandom, RandomSize, sec->crandom, RandomSize);
19069a747e4fSDavid du Colombier }
19079a747e4fSDavid du Colombier
19089a747e4fSDavid du Colombier /*
19099a747e4fSDavid du Colombier * set the master secret from the pre-master secret.
19109a747e4fSDavid du Colombier */
19119a747e4fSDavid du Colombier static void
setMasterSecret(TlsSec * sec,Bytes * pm)19129a747e4fSDavid du Colombier setMasterSecret(TlsSec *sec, Bytes *pm)
19139a747e4fSDavid du Colombier {
19149a747e4fSDavid du Colombier (*sec->prf)(sec->sec, MasterSecretSize, pm->data, MasterSecretSize, "master secret",
19159a747e4fSDavid du Colombier sec->crandom, RandomSize, sec->srandom, RandomSize);
19169a747e4fSDavid du Colombier }
19179a747e4fSDavid du Colombier
19189a747e4fSDavid du Colombier static void
serverMasterSecret(TlsSec * sec,uchar * epm,int nepm)19199a747e4fSDavid du Colombier serverMasterSecret(TlsSec *sec, uchar *epm, int nepm)
19209a747e4fSDavid du Colombier {
19219a747e4fSDavid du Colombier Bytes *pm;
19229a747e4fSDavid du Colombier
19239a747e4fSDavid du Colombier pm = pkcs1_decrypt(sec, epm, nepm);
19249a747e4fSDavid du Colombier
19259a747e4fSDavid du Colombier // if the client messed up, just continue as if everything is ok,
19269a747e4fSDavid du Colombier // to prevent attacks to check for correctly formatted messages.
192765fa3f8bSDavid du Colombier // Hence the fprint(2,) can't be replaced by tlsError(), which sends an Alert msg to the client.
19289a747e4fSDavid du Colombier if(sec->ok < 0 || pm == nil || get16(pm->data) != sec->clientVers){
192965fa3f8bSDavid du Colombier fprint(2, "serverMasterSecret failed ok=%d pm=%p pmvers=%x cvers=%x nepm=%d\n",
193065fa3f8bSDavid du Colombier sec->ok, pm, pm ? get16(pm->data) : -1, sec->clientVers, nepm);
19319a747e4fSDavid du Colombier sec->ok = -1;
19329a747e4fSDavid du Colombier if(pm != nil)
19339a747e4fSDavid du Colombier freebytes(pm);
19349a747e4fSDavid du Colombier pm = newbytes(MasterSecretSize);
19359a747e4fSDavid du Colombier genrandom(pm->data, MasterSecretSize);
19369a747e4fSDavid du Colombier }
19379a747e4fSDavid du Colombier setMasterSecret(sec, pm);
19389a747e4fSDavid du Colombier memset(pm->data, 0, pm->len);
19399a747e4fSDavid du Colombier freebytes(pm);
19409a747e4fSDavid du Colombier }
19419a747e4fSDavid du Colombier
19429a747e4fSDavid du Colombier static int
clientMasterSecret(TlsSec * sec,RSApub * pub,uchar ** epm,int * nepm)19439a747e4fSDavid du Colombier clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm)
19449a747e4fSDavid du Colombier {
19459a747e4fSDavid du Colombier Bytes *pm, *key;
19469a747e4fSDavid du Colombier
19479a747e4fSDavid du Colombier pm = newbytes(MasterSecretSize);
19489a747e4fSDavid du Colombier put16(pm->data, sec->clientVers);
19499a747e4fSDavid du Colombier genrandom(pm->data+2, MasterSecretSize - 2);
19509a747e4fSDavid du Colombier
19519a747e4fSDavid du Colombier setMasterSecret(sec, pm);
19529a747e4fSDavid du Colombier
19539a747e4fSDavid du Colombier key = pkcs1_encrypt(pm, pub, 2);
19549a747e4fSDavid du Colombier memset(pm->data, 0, pm->len);
19559a747e4fSDavid du Colombier freebytes(pm);
19569a747e4fSDavid du Colombier if(key == nil){
19579a747e4fSDavid du Colombier werrstr("tls pkcs1_encrypt failed");
19589a747e4fSDavid du Colombier return -1;
19599a747e4fSDavid du Colombier }
19609a747e4fSDavid du Colombier
19619a747e4fSDavid du Colombier *nepm = key->len;
19629a747e4fSDavid du Colombier *epm = malloc(*nepm);
19639a747e4fSDavid du Colombier if(*epm == nil){
19649a747e4fSDavid du Colombier freebytes(key);
19659a747e4fSDavid du Colombier werrstr("out of memory");
19669a747e4fSDavid du Colombier return -1;
19679a747e4fSDavid du Colombier }
19689a747e4fSDavid du Colombier memmove(*epm, key->data, *nepm);
19699a747e4fSDavid du Colombier
19709a747e4fSDavid du Colombier freebytes(key);
19719a747e4fSDavid du Colombier
19729a747e4fSDavid du Colombier return 1;
19739a747e4fSDavid du Colombier }
19749a747e4fSDavid du Colombier
19759a747e4fSDavid du Colombier static void
sslSetFinished(TlsSec * sec,MD5state hsmd5,SHAstate hssha1,uchar * finished,int isClient)19769a747e4fSDavid du Colombier sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
19779a747e4fSDavid du Colombier {
19789a747e4fSDavid du Colombier DigestState *s;
19799a747e4fSDavid du Colombier uchar h0[MD5dlen], h1[SHA1dlen], pad[48];
19809a747e4fSDavid du Colombier char *label;
19819a747e4fSDavid du Colombier
19829a747e4fSDavid du Colombier if(isClient)
19839a747e4fSDavid du Colombier label = "CLNT";
19849a747e4fSDavid du Colombier else
19859a747e4fSDavid du Colombier label = "SRVR";
19869a747e4fSDavid du Colombier
19879a747e4fSDavid du Colombier md5((uchar*)label, 4, nil, &hsmd5);
19889a747e4fSDavid du Colombier md5(sec->sec, MasterSecretSize, nil, &hsmd5);
19899a747e4fSDavid du Colombier memset(pad, 0x36, 48);
19909a747e4fSDavid du Colombier md5(pad, 48, nil, &hsmd5);
19919a747e4fSDavid du Colombier md5(nil, 0, h0, &hsmd5);
19929a747e4fSDavid du Colombier memset(pad, 0x5C, 48);
19939a747e4fSDavid du Colombier s = md5(sec->sec, MasterSecretSize, nil, nil);
19949a747e4fSDavid du Colombier s = md5(pad, 48, nil, s);
19959a747e4fSDavid du Colombier md5(h0, MD5dlen, finished, s);
19969a747e4fSDavid du Colombier
19979a747e4fSDavid du Colombier sha1((uchar*)label, 4, nil, &hssha1);
19989a747e4fSDavid du Colombier sha1(sec->sec, MasterSecretSize, nil, &hssha1);
19999a747e4fSDavid du Colombier memset(pad, 0x36, 40);
20009a747e4fSDavid du Colombier sha1(pad, 40, nil, &hssha1);
20019a747e4fSDavid du Colombier sha1(nil, 0, h1, &hssha1);
20029a747e4fSDavid du Colombier memset(pad, 0x5C, 40);
20039a747e4fSDavid du Colombier s = sha1(sec->sec, MasterSecretSize, nil, nil);
20049a747e4fSDavid du Colombier s = sha1(pad, 40, nil, s);
20059a747e4fSDavid du Colombier sha1(h1, SHA1dlen, finished + MD5dlen, s);
20069a747e4fSDavid du Colombier }
20079a747e4fSDavid du Colombier
20089a747e4fSDavid du Colombier // fill "finished" arg with md5(args)^sha1(args)
20099a747e4fSDavid du Colombier static void
tlsSetFinished(TlsSec * sec,MD5state hsmd5,SHAstate hssha1,uchar * finished,int isClient)20109a747e4fSDavid du Colombier tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient)
20119a747e4fSDavid du Colombier {
20129a747e4fSDavid du Colombier uchar h0[MD5dlen], h1[SHA1dlen];
20139a747e4fSDavid du Colombier char *label;
20149a747e4fSDavid du Colombier
20159a747e4fSDavid du Colombier // get current hash value, but allow further messages to be hashed in
20169a747e4fSDavid du Colombier md5(nil, 0, h0, &hsmd5);
20179a747e4fSDavid du Colombier sha1(nil, 0, h1, &hssha1);
20189a747e4fSDavid du Colombier
20199a747e4fSDavid du Colombier if(isClient)
20209a747e4fSDavid du Colombier label = "client finished";
20219a747e4fSDavid du Colombier else
20229a747e4fSDavid du Colombier label = "server finished";
20239a747e4fSDavid du Colombier tlsPRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen);
20249a747e4fSDavid du Colombier }
20259a747e4fSDavid du Colombier
20269a747e4fSDavid du Colombier static void
sslPRF(uchar * buf,int nbuf,uchar * key,int nkey,char * label,uchar * seed0,int nseed0,uchar * seed1,int nseed1)20279a747e4fSDavid du Colombier sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
20289a747e4fSDavid du Colombier {
20299a747e4fSDavid du Colombier DigestState *s;
20309a747e4fSDavid du Colombier uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26];
20319a747e4fSDavid du Colombier int i, n, len;
20329a747e4fSDavid du Colombier
20339a747e4fSDavid du Colombier USED(label);
20349a747e4fSDavid du Colombier len = 1;
20359a747e4fSDavid du Colombier while(nbuf > 0){
20369a747e4fSDavid du Colombier if(len > 26)
20379a747e4fSDavid du Colombier return;
20389a747e4fSDavid du Colombier for(i = 0; i < len; i++)
20399a747e4fSDavid du Colombier tmp[i] = 'A' - 1 + len;
20409a747e4fSDavid du Colombier s = sha1(tmp, len, nil, nil);
20419a747e4fSDavid du Colombier s = sha1(key, nkey, nil, s);
20429a747e4fSDavid du Colombier s = sha1(seed0, nseed0, nil, s);
20439a747e4fSDavid du Colombier sha1(seed1, nseed1, sha1dig, s);
20449a747e4fSDavid du Colombier s = md5(key, nkey, nil, nil);
20459a747e4fSDavid du Colombier md5(sha1dig, SHA1dlen, md5dig, s);
20469a747e4fSDavid du Colombier n = MD5dlen;
20479a747e4fSDavid du Colombier if(n > nbuf)
20489a747e4fSDavid du Colombier n = nbuf;
20499a747e4fSDavid du Colombier memmove(buf, md5dig, n);
20509a747e4fSDavid du Colombier buf += n;
20519a747e4fSDavid du Colombier nbuf -= n;
20529a747e4fSDavid du Colombier len++;
20539a747e4fSDavid du Colombier }
20549a747e4fSDavid du Colombier }
20559a747e4fSDavid du Colombier
20569a747e4fSDavid du Colombier static mpint*
bytestomp(Bytes * bytes)20579a747e4fSDavid du Colombier bytestomp(Bytes* bytes)
20589a747e4fSDavid du Colombier {
20599a747e4fSDavid du Colombier mpint* ans;
20609a747e4fSDavid du Colombier
20619a747e4fSDavid du Colombier ans = betomp(bytes->data, bytes->len, nil);
20629a747e4fSDavid du Colombier return ans;
20639a747e4fSDavid du Colombier }
20649a747e4fSDavid du Colombier
20659a747e4fSDavid du Colombier /*
20669a747e4fSDavid du Colombier * Convert mpint* to Bytes, putting high order byte first.
20679a747e4fSDavid du Colombier */
20689a747e4fSDavid du Colombier static Bytes*
mptobytes(mpint * big)20699a747e4fSDavid du Colombier mptobytes(mpint* big)
20709a747e4fSDavid du Colombier {
20719a747e4fSDavid du Colombier int n, m;
20729a747e4fSDavid du Colombier uchar *a;
20739a747e4fSDavid du Colombier Bytes* ans;
20749a747e4fSDavid du Colombier
207592fd5f07SDavid du Colombier a = nil;
20769a747e4fSDavid du Colombier n = (mpsignif(big)+7)/8;
20779a747e4fSDavid du Colombier m = mptobe(big, nil, n, &a);
20789a747e4fSDavid du Colombier ans = makebytes(a, m);
207992fd5f07SDavid du Colombier if(a != nil)
208092fd5f07SDavid du Colombier free(a);
20819a747e4fSDavid du Colombier return ans;
20829a747e4fSDavid du Colombier }
20839a747e4fSDavid du Colombier
20849a747e4fSDavid du Colombier // Do RSA computation on block according to key, and pad
20859a747e4fSDavid du Colombier // result on left with zeros to make it modlen long.
20869a747e4fSDavid du Colombier static Bytes*
rsacomp(Bytes * block,RSApub * key,int modlen)20879a747e4fSDavid du Colombier rsacomp(Bytes* block, RSApub* key, int modlen)
20889a747e4fSDavid du Colombier {
20899a747e4fSDavid du Colombier mpint *x, *y;
20909a747e4fSDavid du Colombier Bytes *a, *ybytes;
20919a747e4fSDavid du Colombier int ylen;
20929a747e4fSDavid du Colombier
20939a747e4fSDavid du Colombier x = bytestomp(block);
20949a747e4fSDavid du Colombier y = rsaencrypt(key, x, nil);
20959a747e4fSDavid du Colombier mpfree(x);
20969a747e4fSDavid du Colombier ybytes = mptobytes(y);
20979a747e4fSDavid du Colombier ylen = ybytes->len;
20989a747e4fSDavid du Colombier
20999a747e4fSDavid du Colombier if(ylen < modlen) {
21009a747e4fSDavid du Colombier a = newbytes(modlen);
21019a747e4fSDavid du Colombier memset(a->data, 0, modlen-ylen);
21029a747e4fSDavid du Colombier memmove(a->data+modlen-ylen, ybytes->data, ylen);
21039a747e4fSDavid du Colombier freebytes(ybytes);
21049a747e4fSDavid du Colombier ybytes = a;
21059a747e4fSDavid du Colombier }
21069a747e4fSDavid du Colombier else if(ylen > modlen) {
21079a747e4fSDavid du Colombier // assume it has leading zeros (mod should make it so)
21089a747e4fSDavid du Colombier a = newbytes(modlen);
21099a747e4fSDavid du Colombier memmove(a->data, ybytes->data, modlen);
21109a747e4fSDavid du Colombier freebytes(ybytes);
21119a747e4fSDavid du Colombier ybytes = a;
21129a747e4fSDavid du Colombier }
21139a747e4fSDavid du Colombier mpfree(y);
21149a747e4fSDavid du Colombier return ybytes;
21159a747e4fSDavid du Colombier }
21169a747e4fSDavid du Colombier
21173ff48bf5SDavid du Colombier // encrypt data according to PKCS#1, /lib/rfc/rfc2437 9.1.2.1
21189a747e4fSDavid du Colombier static Bytes*
pkcs1_encrypt(Bytes * data,RSApub * key,int blocktype)21199a747e4fSDavid du Colombier pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype)
21209a747e4fSDavid du Colombier {
21219a747e4fSDavid du Colombier Bytes *pad, *eb, *ans;
21229a747e4fSDavid du Colombier int i, dlen, padlen, modlen;
21239a747e4fSDavid du Colombier
21249a747e4fSDavid du Colombier modlen = (mpsignif(key->n)+7)/8;
21259a747e4fSDavid du Colombier dlen = data->len;
21269a747e4fSDavid du Colombier if(modlen < 12 || dlen > modlen - 11)
21279a747e4fSDavid du Colombier return nil;
21289a747e4fSDavid du Colombier padlen = modlen - 3 - dlen;
21299a747e4fSDavid du Colombier pad = newbytes(padlen);
21309a747e4fSDavid du Colombier genrandom(pad->data, padlen);
21319a747e4fSDavid du Colombier for(i = 0; i < padlen; i++) {
21329a747e4fSDavid du Colombier if(blocktype == 0)
21339a747e4fSDavid du Colombier pad->data[i] = 0;
21349a747e4fSDavid du Colombier else if(blocktype == 1)
21359a747e4fSDavid du Colombier pad->data[i] = 255;
21369a747e4fSDavid du Colombier else if(pad->data[i] == 0)
21379a747e4fSDavid du Colombier pad->data[i] = 1;
21389a747e4fSDavid du Colombier }
21399a747e4fSDavid du Colombier eb = newbytes(modlen);
21409a747e4fSDavid du Colombier eb->data[0] = 0;
21419a747e4fSDavid du Colombier eb->data[1] = blocktype;
21429a747e4fSDavid du Colombier memmove(eb->data+2, pad->data, padlen);
21439a747e4fSDavid du Colombier eb->data[padlen+2] = 0;
21449a747e4fSDavid du Colombier memmove(eb->data+padlen+3, data->data, dlen);
21459a747e4fSDavid du Colombier ans = rsacomp(eb, key, modlen);
21469a747e4fSDavid du Colombier freebytes(eb);
21479a747e4fSDavid du Colombier freebytes(pad);
21489a747e4fSDavid du Colombier return ans;
21499a747e4fSDavid du Colombier }
21509a747e4fSDavid du Colombier
21519a747e4fSDavid du Colombier // decrypt data according to PKCS#1, with given key.
21529a747e4fSDavid du Colombier // expect a block type of 2.
21539a747e4fSDavid du Colombier static Bytes*
pkcs1_decrypt(TlsSec * sec,uchar * epm,int nepm)21549a747e4fSDavid du Colombier pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm)
21559a747e4fSDavid du Colombier {
21569a747e4fSDavid du Colombier Bytes *eb, *ans = nil;
21579a747e4fSDavid du Colombier int i, modlen;
21589a747e4fSDavid du Colombier mpint *x, *y;
21599a747e4fSDavid du Colombier
21609a747e4fSDavid du Colombier modlen = (mpsignif(sec->rsapub->n)+7)/8;
21619a747e4fSDavid du Colombier if(nepm != modlen)
21629a747e4fSDavid du Colombier return nil;
21639a747e4fSDavid du Colombier x = betomp(epm, nepm, nil);
21649a747e4fSDavid du Colombier y = factotum_rsa_decrypt(sec->rpc, x);
21659a747e4fSDavid du Colombier if(y == nil)
21669a747e4fSDavid du Colombier return nil;
21679a747e4fSDavid du Colombier eb = mptobytes(y);
21689a747e4fSDavid du Colombier if(eb->len < modlen){ // pad on left with zeros
21699a747e4fSDavid du Colombier ans = newbytes(modlen);
21709a747e4fSDavid du Colombier memset(ans->data, 0, modlen-eb->len);
21719a747e4fSDavid du Colombier memmove(ans->data+modlen-eb->len, eb->data, eb->len);
21729a747e4fSDavid du Colombier freebytes(eb);
21739a747e4fSDavid du Colombier eb = ans;
21749a747e4fSDavid du Colombier }
21759a747e4fSDavid du Colombier if(eb->data[0] == 0 && eb->data[1] == 2) {
21769a747e4fSDavid du Colombier for(i = 2; i < modlen; i++)
21779a747e4fSDavid du Colombier if(eb->data[i] == 0)
21789a747e4fSDavid du Colombier break;
21799a747e4fSDavid du Colombier if(i < modlen - 1)
21809a747e4fSDavid du Colombier ans = makebytes(eb->data+i+1, modlen-(i+1));
21819a747e4fSDavid du Colombier }
21829a747e4fSDavid du Colombier freebytes(eb);
21839a747e4fSDavid du Colombier return ans;
21849a747e4fSDavid du Colombier }
21859a747e4fSDavid du Colombier
21869a747e4fSDavid du Colombier
21879a747e4fSDavid du Colombier //================= general utility functions ========================
21889a747e4fSDavid du Colombier
21899a747e4fSDavid du Colombier static void *
emalloc(int n)21909a747e4fSDavid du Colombier emalloc(int n)
21919a747e4fSDavid du Colombier {
21929a747e4fSDavid du Colombier void *p;
21939a747e4fSDavid du Colombier if(n==0)
21949a747e4fSDavid du Colombier n=1;
21959a747e4fSDavid du Colombier p = malloc(n);
21969a747e4fSDavid du Colombier if(p == nil){
21979a747e4fSDavid du Colombier exits("out of memory");
21989a747e4fSDavid du Colombier }
21999a747e4fSDavid du Colombier memset(p, 0, n);
22009a747e4fSDavid du Colombier return p;
22019a747e4fSDavid du Colombier }
22029a747e4fSDavid du Colombier
22039a747e4fSDavid du Colombier static void *
erealloc(void * ReallocP,int ReallocN)22049a747e4fSDavid du Colombier erealloc(void *ReallocP, int ReallocN)
22059a747e4fSDavid du Colombier {
22069a747e4fSDavid du Colombier if(ReallocN == 0)
22079a747e4fSDavid du Colombier ReallocN = 1;
22089a747e4fSDavid du Colombier if(!ReallocP)
22099a747e4fSDavid du Colombier ReallocP = emalloc(ReallocN);
22109a747e4fSDavid du Colombier else if(!(ReallocP = realloc(ReallocP, ReallocN))){
22119a747e4fSDavid du Colombier exits("out of memory");
22129a747e4fSDavid du Colombier }
22139a747e4fSDavid du Colombier return(ReallocP);
22149a747e4fSDavid du Colombier }
22159a747e4fSDavid du Colombier
22169a747e4fSDavid du Colombier static void
put32(uchar * p,u32int x)22179a747e4fSDavid du Colombier put32(uchar *p, u32int x)
22189a747e4fSDavid du Colombier {
22199a747e4fSDavid du Colombier p[0] = x>>24;
22209a747e4fSDavid du Colombier p[1] = x>>16;
22219a747e4fSDavid du Colombier p[2] = x>>8;
22229a747e4fSDavid du Colombier p[3] = x;
22239a747e4fSDavid du Colombier }
22249a747e4fSDavid du Colombier
22259a747e4fSDavid du Colombier static void
put24(uchar * p,int x)22269a747e4fSDavid du Colombier put24(uchar *p, int x)
22279a747e4fSDavid du Colombier {
22289a747e4fSDavid du Colombier p[0] = x>>16;
22299a747e4fSDavid du Colombier p[1] = x>>8;
22309a747e4fSDavid du Colombier p[2] = x;
22319a747e4fSDavid du Colombier }
22329a747e4fSDavid du Colombier
22339a747e4fSDavid du Colombier static void
put16(uchar * p,int x)22349a747e4fSDavid du Colombier put16(uchar *p, int x)
22359a747e4fSDavid du Colombier {
22369a747e4fSDavid du Colombier p[0] = x>>8;
22379a747e4fSDavid du Colombier p[1] = x;
22389a747e4fSDavid du Colombier }
22399a747e4fSDavid du Colombier
22409a747e4fSDavid du Colombier static u32int
get32(uchar * p)22419a747e4fSDavid du Colombier get32(uchar *p)
22429a747e4fSDavid du Colombier {
22439a747e4fSDavid du Colombier return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
22449a747e4fSDavid du Colombier }
22459a747e4fSDavid du Colombier
22469a747e4fSDavid du Colombier static int
get24(uchar * p)22479a747e4fSDavid du Colombier get24(uchar *p)
22489a747e4fSDavid du Colombier {
22499a747e4fSDavid du Colombier return (p[0]<<16)|(p[1]<<8)|p[2];
22509a747e4fSDavid du Colombier }
22519a747e4fSDavid du Colombier
22529a747e4fSDavid du Colombier static int
get16(uchar * p)22539a747e4fSDavid du Colombier get16(uchar *p)
22549a747e4fSDavid du Colombier {
22559a747e4fSDavid du Colombier return (p[0]<<8)|p[1];
22569a747e4fSDavid du Colombier }
22579a747e4fSDavid du Colombier
22582d8b52e8SDavid du Colombier #define OFFSET(x, s) offsetof(s, x)
22599a747e4fSDavid du Colombier
22609a747e4fSDavid du Colombier /*
22619a747e4fSDavid du Colombier * malloc and return a new Bytes structure capable of
22629a747e4fSDavid du Colombier * holding len bytes. (len >= 0)
22639a747e4fSDavid du Colombier * Used to use crypt_malloc, which aborts if malloc fails.
22649a747e4fSDavid du Colombier */
22659a747e4fSDavid du Colombier static Bytes*
newbytes(int len)22669a747e4fSDavid du Colombier newbytes(int len)
22679a747e4fSDavid du Colombier {
22689a747e4fSDavid du Colombier Bytes* ans;
22699a747e4fSDavid du Colombier
22709a747e4fSDavid du Colombier ans = (Bytes*)malloc(OFFSET(data[0], Bytes) + len);
22719a747e4fSDavid du Colombier ans->len = len;
22729a747e4fSDavid du Colombier return ans;
22739a747e4fSDavid du Colombier }
22749a747e4fSDavid du Colombier
22759a747e4fSDavid du Colombier /*
22769a747e4fSDavid du Colombier * newbytes(len), with data initialized from buf
22779a747e4fSDavid du Colombier */
22789a747e4fSDavid du Colombier static Bytes*
makebytes(uchar * buf,int len)22799a747e4fSDavid du Colombier makebytes(uchar* buf, int len)
22809a747e4fSDavid du Colombier {
22819a747e4fSDavid du Colombier Bytes* ans;
22829a747e4fSDavid du Colombier
22839a747e4fSDavid du Colombier ans = newbytes(len);
22849a747e4fSDavid du Colombier memmove(ans->data, buf, len);
22859a747e4fSDavid du Colombier return ans;
22869a747e4fSDavid du Colombier }
22879a747e4fSDavid du Colombier
22889a747e4fSDavid du Colombier static void
freebytes(Bytes * b)22899a747e4fSDavid du Colombier freebytes(Bytes* b)
22909a747e4fSDavid du Colombier {
22919a747e4fSDavid du Colombier if(b != nil)
22929a747e4fSDavid du Colombier free(b);
22939a747e4fSDavid du Colombier }
22949a747e4fSDavid du Colombier
22959a747e4fSDavid du Colombier /* len is number of ints */
22969a747e4fSDavid du Colombier static Ints*
newints(int len)22979a747e4fSDavid du Colombier newints(int len)
22989a747e4fSDavid du Colombier {
22999a747e4fSDavid du Colombier Ints* ans;
23009a747e4fSDavid du Colombier
23019a747e4fSDavid du Colombier ans = (Ints*)malloc(OFFSET(data[0], Ints) + len*sizeof(int));
23029a747e4fSDavid du Colombier ans->len = len;
23039a747e4fSDavid du Colombier return ans;
23049a747e4fSDavid du Colombier }
23059a747e4fSDavid du Colombier
23069a747e4fSDavid du Colombier static Ints*
makeints(int * buf,int len)23079a747e4fSDavid du Colombier makeints(int* buf, int len)
23089a747e4fSDavid du Colombier {
23099a747e4fSDavid du Colombier Ints* ans;
23109a747e4fSDavid du Colombier
23119a747e4fSDavid du Colombier ans = newints(len);
23129a747e4fSDavid du Colombier if(len > 0)
23139a747e4fSDavid du Colombier memmove(ans->data, buf, len*sizeof(int));
23149a747e4fSDavid du Colombier return ans;
23159a747e4fSDavid du Colombier }
23169a747e4fSDavid du Colombier
23179a747e4fSDavid du Colombier static void
freeints(Ints * b)23189a747e4fSDavid du Colombier freeints(Ints* b)
23199a747e4fSDavid du Colombier {
23209a747e4fSDavid du Colombier if(b != nil)
23219a747e4fSDavid du Colombier free(b);
23229a747e4fSDavid du Colombier }
2323