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