1diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py 2index 52c20ac..feca423 100644 3--- a/third_party/tlslite/tlslite/constants.py 4+++ b/third_party/tlslite/tlslite/constants.py 5@@ -143,6 +143,10 @@ class CipherSuite: 6 7 TLS_RSA_WITH_RC4_128_MD5 = 0x0004 8 9+ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016 10+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 11+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 12+ 13 TLS_DH_ANON_WITH_AES_128_CBC_SHA = 0x0034 14 TLS_DH_ANON_WITH_AES_256_CBC_SHA = 0x003A 15 16@@ -150,17 +154,20 @@ class CipherSuite: 17 tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) 18 tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) 19 tripleDESSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA) 20+ tripleDESSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) 21 22 aes128Suites = [] 23 aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA) 24 aes128Suites.append(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) 25 aes128Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA) 26+ aes128Suites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA) 27 aes128Suites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA) 28 29 aes256Suites = [] 30 aes256Suites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA) 31 aes256Suites.append(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) 32 aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA) 33+ aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA) 34 aes256Suites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA) 35 36 rc4Suites = [] 37@@ -178,6 +185,9 @@ class CipherSuite: 38 shaSuites.append(TLS_RSA_WITH_AES_128_CBC_SHA) 39 shaSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA) 40 shaSuites.append(TLS_RSA_WITH_RC4_128_SHA) 41+ shaSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) 42+ shaSuites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA) 43+ shaSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA) 44 shaSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA) 45 shaSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA) 46 47@@ -188,6 +198,7 @@ class CipherSuite: 48 def _filterSuites(suites, settings): 49 macNames = settings.macNames 50 cipherNames = settings.cipherNames 51+ keyExchangeNames = settings.keyExchangeNames 52 macSuites = [] 53 if "sha" in macNames: 54 macSuites += CipherSuite.shaSuites 55@@ -204,7 +215,20 @@ class CipherSuite: 56 if "rc4" in cipherNames: 57 cipherSuites += CipherSuite.rc4Suites 58 59- return [s for s in suites if s in macSuites and s in cipherSuites] 60+ keyExchangeSuites = [] 61+ if "rsa" in keyExchangeNames: 62+ keyExchangeSuites += CipherSuite.certSuites 63+ if "dhe_rsa" in keyExchangeNames: 64+ keyExchangeSuites += CipherSuite.dheCertSuites 65+ if "srp_sha" in keyExchangeNames: 66+ keyExchangeSuites += CipherSuite.srpSuites 67+ if "srp_sha_rsa" in keyExchangeNames: 68+ keyExchangeSuites += CipherSuite.srpCertSuites 69+ if "dh_anon" in keyExchangeNames: 70+ keyExchangeSuites += CipherSuite.anonSuites 71+ 72+ return [s for s in suites if s in macSuites and 73+ s in cipherSuites and s in keyExchangeSuites] 74 75 srpSuites = [] 76 srpSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) 77@@ -236,12 +260,22 @@ class CipherSuite: 78 certSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA) 79 certSuites.append(TLS_RSA_WITH_RC4_128_SHA) 80 certSuites.append(TLS_RSA_WITH_RC4_128_MD5) 81- certAllSuites = srpCertSuites + certSuites 82 83 @staticmethod 84 def getCertSuites(settings): 85 return CipherSuite._filterSuites(CipherSuite.certSuites, settings) 86 87+ dheCertSuites = [] 88+ dheCertSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) 89+ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA) 90+ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA) 91+ 92+ @staticmethod 93+ def getDheCertSuites(settings): 94+ return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings) 95+ 96+ certAllSuites = srpCertSuites + certSuites + dheCertSuites 97+ 98 anonSuites = [] 99 anonSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA) 100 anonSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA) 101@@ -250,6 +284,8 @@ class CipherSuite: 102 def getAnonSuites(settings): 103 return CipherSuite._filterSuites(CipherSuite.anonSuites, settings) 104 105+ dhAllSuites = dheCertSuites + anonSuites 106+ 107 @staticmethod 108 def canonicalCipherName(ciphersuite): 109 "Return the canonical name of the cipher whose number is provided." 110diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py 111index 7a38ee2..e0bc0e6 100644 112--- a/third_party/tlslite/tlslite/handshakesettings.py 113+++ b/third_party/tlslite/tlslite/handshakesettings.py 114@@ -13,7 +13,9 @@ from .utils import cipherfactory 115 # RC4 is preferred as faster in Python, works in SSL3, and immune to CBC 116 # issues such as timing attacks 117 CIPHER_NAMES = ["rc4", "aes256", "aes128", "3des"] 118-MAC_NAMES = ["sha"] # "md5" is allowed 119+MAC_NAMES = ["sha"] # Don't allow "md5" by default. 120+ALL_MAC_NAMES = ["sha", "md5"] 121+KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"] 122 CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"] 123 CERTIFICATE_TYPES = ["x509"] 124 125@@ -102,6 +104,7 @@ class HandshakeSettings(object): 126 self.maxKeySize = 8193 127 self.cipherNames = CIPHER_NAMES 128 self.macNames = MAC_NAMES 129+ self.keyExchangeNames = KEY_EXCHANGE_NAMES 130 self.cipherImplementations = CIPHER_IMPLEMENTATIONS 131 self.certificateTypes = CERTIFICATE_TYPES 132 self.minVersion = (3,0) 133@@ -116,6 +119,7 @@ class HandshakeSettings(object): 134 other.maxKeySize = self.maxKeySize 135 other.cipherNames = self.cipherNames 136 other.macNames = self.macNames 137+ other.keyExchangeNames = self.keyExchangeNames 138 other.cipherImplementations = self.cipherImplementations 139 other.certificateTypes = self.certificateTypes 140 other.minVersion = self.minVersion 141@@ -148,6 +152,12 @@ class HandshakeSettings(object): 142 for s in other.cipherNames: 143 if s not in CIPHER_NAMES: 144 raise ValueError("Unknown cipher name: '%s'" % s) 145+ for s in other.macNames: 146+ if s not in ALL_MAC_NAMES: 147+ raise ValueError("Unknown MAC name: '%s'" % s) 148+ for s in other.keyExchangeNames: 149+ if s not in KEY_EXCHANGE_NAMES: 150+ raise ValueError("Unknown key exchange name: '%s'" % s) 151 for s in other.cipherImplementations: 152 if s not in CIPHER_IMPLEMENTATIONS: 153 raise ValueError("Unknown cipher implementation: '%s'" % s) 154diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py 155index 532d86b..550b387 100644 156--- a/third_party/tlslite/tlslite/messages.py 157+++ b/third_party/tlslite/tlslite/messages.py 158@@ -533,31 +533,31 @@ class ServerKeyExchange(HandshakeMsg): 159 p.stopLengthCheck() 160 return self 161 162- def write(self): 163+ def write_params(self): 164 w = Writer() 165 if self.cipherSuite in CipherSuite.srpAllSuites: 166 w.addVarSeq(numberToByteArray(self.srp_N), 1, 2) 167 w.addVarSeq(numberToByteArray(self.srp_g), 1, 2) 168 w.addVarSeq(self.srp_s, 1, 1) 169 w.addVarSeq(numberToByteArray(self.srp_B), 1, 2) 170- if self.cipherSuite in CipherSuite.srpCertSuites: 171- w.addVarSeq(self.signature, 1, 2) 172- elif self.cipherSuite in CipherSuite.anonSuites: 173+ elif self.cipherSuite in CipherSuite.dhAllSuites: 174 w.addVarSeq(numberToByteArray(self.dh_p), 1, 2) 175 w.addVarSeq(numberToByteArray(self.dh_g), 1, 2) 176 w.addVarSeq(numberToByteArray(self.dh_Ys), 1, 2) 177- if self.cipherSuite in []: # TODO support for signed_params 178- w.addVarSeq(self.signature, 1, 2) 179+ else: 180+ assert(False) 181+ return w.bytes 182+ 183+ def write(self): 184+ w = Writer() 185+ w.bytes += self.write_params() 186+ if self.cipherSuite in CipherSuite.certAllSuites: 187+ w.addVarSeq(self.signature, 1, 2) 188 return self.postWrite(w) 189 190 def hash(self, clientRandom, serverRandom): 191- oldCipherSuite = self.cipherSuite 192- self.cipherSuite = None 193- try: 194- bytes = clientRandom + serverRandom + self.write()[4:] 195- return MD5(bytes) + SHA1(bytes) 196- finally: 197- self.cipherSuite = oldCipherSuite 198+ bytes = clientRandom + serverRandom + self.write_params() 199+ return MD5(bytes) + SHA1(bytes) 200 201 class ServerHelloDone(HandshakeMsg): 202 def __init__(self): 203@@ -607,7 +607,7 @@ class ClientKeyExchange(HandshakeMsg): 204 p.getFixBytes(len(p.bytes)-p.index) 205 else: 206 raise AssertionError() 207- elif self.cipherSuite in CipherSuite.anonSuites: 208+ elif self.cipherSuite in CipherSuite.dhAllSuites: 209 self.dh_Yc = bytesToNumber(p.getVarBytes(2)) 210 else: 211 raise AssertionError() 212diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py 213index 20cd85b..e6f7820 100644 214--- a/third_party/tlslite/tlslite/tlsconnection.py 215+++ b/third_party/tlslite/tlslite/tlsconnection.py 216@@ -23,6 +23,103 @@ from .mathtls import * 217 from .handshakesettings import HandshakeSettings 218 from .utils.tackwrapper import * 219 220+class KeyExchange(object): 221+ def __init__(self, cipherSuite, clientHello, serverHello, privateKey): 222+ """ 223+ Initializes the KeyExchange. privateKey is the signing private key. 224+ """ 225+ self.cipherSuite = cipherSuite 226+ self.clientHello = clientHello 227+ self.serverHello = serverHello 228+ self.privateKey = privateKey 229+ 230+ def makeServerKeyExchange(): 231+ """ 232+ Returns a ServerKeyExchange object for the server's initial leg in the 233+ handshake. If the key exchange method does not send ServerKeyExchange 234+ (e.g. RSA), it returns None. 235+ """ 236+ raise NotImplementedError() 237+ 238+ def processClientKeyExchange(clientKeyExchange): 239+ """ 240+ Processes the client's ClientKeyExchange message and returns the 241+ premaster secret. Raises TLSLocalAlert on error. 242+ """ 243+ raise NotImplementedError() 244+ 245+class RSAKeyExchange(KeyExchange): 246+ def makeServerKeyExchange(self): 247+ return None 248+ 249+ def processClientKeyExchange(self, clientKeyExchange): 250+ premasterSecret = self.privateKey.decrypt(\ 251+ clientKeyExchange.encryptedPreMasterSecret) 252+ 253+ # On decryption failure randomize premaster secret to avoid 254+ # Bleichenbacher's "million message" attack 255+ randomPreMasterSecret = getRandomBytes(48) 256+ if not premasterSecret: 257+ premasterSecret = randomPreMasterSecret 258+ elif len(premasterSecret)!=48: 259+ premasterSecret = randomPreMasterSecret 260+ else: 261+ versionCheck = (premasterSecret[0], premasterSecret[1]) 262+ if versionCheck != self.clientHello.client_version: 263+ #Tolerate buggy IE clients 264+ if versionCheck != self.serverHello.server_version: 265+ premasterSecret = randomPreMasterSecret 266+ return premasterSecret 267+ 268+def _hexStringToNumber(s): 269+ s = s.replace(" ", "").replace("\n", "") 270+ if len(s) % 2 != 0: 271+ raise ValueError("Length is not even") 272+ return bytesToNumber(bytearray(s.decode("hex"))) 273+ 274+class DHE_RSAKeyExchange(KeyExchange): 275+ # 2048-bit MODP Group (RFC 3526, Section 3) 276+ dh_p = _hexStringToNumber(""" 277+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 278+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD 279+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 280+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED 281+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D 282+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F 283+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D 284+670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B 285+E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 286+DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510 287+15728E5A 8AACAA68 FFFFFFFF FFFFFFFF""") 288+ dh_g = 2 289+ 290+ # RFC 3526, Section 8. 291+ strength = 160 292+ 293+ def makeServerKeyExchange(self): 294+ # Per RFC 3526, Section 1, the exponent should have double the entropy 295+ # of the strength of the curve. 296+ self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 / 8)) 297+ dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p) 298+ 299+ serverKeyExchange = ServerKeyExchange(self.cipherSuite) 300+ serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys) 301+ serverKeyExchange.signature = self.privateKey.sign( 302+ serverKeyExchange.hash(self.clientHello.random, 303+ self.serverHello.random)) 304+ return serverKeyExchange 305+ 306+ def processClientKeyExchange(self, clientKeyExchange): 307+ dh_Yc = clientKeyExchange.dh_Yc 308+ 309+ # First half of RFC 2631, Section 2.1.5. Validate the client's public 310+ # key. 311+ if not 2 <= dh_Yc <= self.dh_p - 1: 312+ raise TLSLocalAlert(AlertDescription.illegal_parameter, 313+ "Invalid dh_Yc value") 314+ 315+ S = powMod(dh_Yc, self.dh_Xs, self.dh_p) 316+ return numberToByteArray(S) 317 318 class TLSConnection(TLSRecordLayer): 319 """ 320@@ -500,6 +597,8 @@ class TLSConnection(TLSRecordLayer): 321 cipherSuites += CipherSuite.getSrpAllSuites(settings) 322 elif certParams: 323 cipherSuites += CipherSuite.getCertSuites(settings) 324+ # TODO: Client DHE_RSA not supported. 325+ # cipherSuites += CipherSuite.getDheCertSuites(settings) 326 elif anonParams: 327 cipherSuites += CipherSuite.getAnonSuites(settings) 328 else: 329@@ -1204,10 +1303,23 @@ class TLSConnection(TLSRecordLayer): 330 else: break 331 premasterSecret = result 332 333- # Perform the RSA key exchange 334- elif cipherSuite in CipherSuite.certSuites: 335+ # Perform the RSA or DHE_RSA key exchange 336+ elif (cipherSuite in CipherSuite.certSuites or 337+ cipherSuite in CipherSuite.dheCertSuites): 338+ if cipherSuite in CipherSuite.certSuites: 339+ keyExchange = RSAKeyExchange(cipherSuite, 340+ clientHello, 341+ serverHello, 342+ privateKey) 343+ elif cipherSuite in CipherSuite.dheCertSuites: 344+ keyExchange = DHE_RSAKeyExchange(cipherSuite, 345+ clientHello, 346+ serverHello, 347+ privateKey) 348+ else: 349+ assert(False) 350 for result in self._serverCertKeyExchange(clientHello, serverHello, 351- certChain, privateKey, 352+ certChain, keyExchange, 353 reqCert, reqCAs, cipherSuite, 354 settings, ocspResponse): 355 if result in (0,1): yield result 356@@ -1268,6 +1380,7 @@ class TLSConnection(TLSRecordLayer): 357 cipherSuites += CipherSuite.getSrpSuites(settings) 358 elif certChain: 359 cipherSuites += CipherSuite.getCertSuites(settings) 360+ cipherSuites += CipherSuite.getDheCertSuites(settings) 361 elif anon: 362 cipherSuites += CipherSuite.getAnonSuites(settings) 363 else: 364@@ -1483,11 +1596,11 @@ class TLSConnection(TLSRecordLayer): 365 366 367 def _serverCertKeyExchange(self, clientHello, serverHello, 368- serverCertChain, privateKey, 369+ serverCertChain, keyExchange, 370 reqCert, reqCAs, cipherSuite, 371 settings, ocspResponse): 372- #Send ServerHello, Certificate[, CertificateRequest], 373- #ServerHelloDone 374+ #Send ServerHello, Certificate[, ServerKeyExchange] 375+ #[, CertificateRequest], ServerHelloDone 376 msgs = [] 377 378 # If we verify a client cert chain, return it 379@@ -1497,6 +1610,9 @@ class TLSConnection(TLSRecordLayer): 380 msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) 381 if serverHello.status_request: 382 msgs.append(CertificateStatus().create(ocspResponse)) 383+ serverKeyExchange = keyExchange.makeServerKeyExchange() 384+ if serverKeyExchange is not None: 385+ msgs.append(serverKeyExchange) 386 if reqCert and reqCAs: 387 msgs.append(CertificateRequest().create(\ 388 [ClientCertificateType.rsa_sign], reqCAs)) 389@@ -1555,21 +1671,13 @@ class TLSConnection(TLSRecordLayer): 390 else: break 391 clientKeyExchange = result 392 393- #Decrypt ClientKeyExchange 394- premasterSecret = privateKey.decrypt(\ 395- clientKeyExchange.encryptedPreMasterSecret) 396- 397- # On decryption failure randomize premaster secret to avoid 398- # Bleichenbacher's "million message" attack 399- randomPreMasterSecret = getRandomBytes(48) 400- versionCheck = (premasterSecret[0], premasterSecret[1]) 401- if not premasterSecret: 402- premasterSecret = randomPreMasterSecret 403- elif len(premasterSecret)!=48: 404- premasterSecret = randomPreMasterSecret 405- elif versionCheck != clientHello.client_version: 406- if versionCheck != self.version: #Tolerate buggy IE clients 407- premasterSecret = randomPreMasterSecret 408+ #Process ClientKeyExchange 409+ try: 410+ premasterSecret = \ 411+ keyExchange.processClientKeyExchange(clientKeyExchange) 412+ except TLSLocalAlert, alert: 413+ for result in self._sendError(alert.description, alert.message): 414+ yield result 415 416 #Get and check CertificateVerify, if relevant 417 if clientCertChain: 418