| Index: third_party/tlslite/patches/dhe_rsa.patch
|
| diff --git a/third_party/tlslite/patches/dhe_rsa.patch b/third_party/tlslite/patches/dhe_rsa.patch
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1466851a66b3c734869efcffc414ca2938a5d697
|
| --- /dev/null
|
| +++ b/third_party/tlslite/patches/dhe_rsa.patch
|
| @@ -0,0 +1,417 @@
|
| +diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
|
| +index 52c20ac..feca423 100644
|
| +--- a/third_party/tlslite/tlslite/constants.py
|
| ++++ b/third_party/tlslite/tlslite/constants.py
|
| +@@ -143,6 +143,10 @@ class CipherSuite:
|
| +
|
| + TLS_RSA_WITH_RC4_128_MD5 = 0x0004
|
| +
|
| ++ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016
|
| ++ TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033
|
| ++ TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039
|
| ++
|
| + TLS_DH_ANON_WITH_AES_128_CBC_SHA = 0x0034
|
| + TLS_DH_ANON_WITH_AES_256_CBC_SHA = 0x003A
|
| +
|
| +@@ -150,17 +154,20 @@ class CipherSuite:
|
| + tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
|
| + tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
|
| + tripleDESSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA)
|
| ++ tripleDESSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
| +
|
| + aes128Suites = []
|
| + aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
|
| + aes128Suites.append(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA)
|
| + aes128Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA)
|
| ++ aes128Suites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
|
| + aes128Suites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
|
| +
|
| + aes256Suites = []
|
| + aes256Suites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
|
| + aes256Suites.append(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA)
|
| + aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
|
| ++ aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
|
| + aes256Suites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
|
| +
|
| + rc4Suites = []
|
| +@@ -178,6 +185,9 @@ class CipherSuite:
|
| + shaSuites.append(TLS_RSA_WITH_AES_128_CBC_SHA)
|
| + shaSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
|
| + shaSuites.append(TLS_RSA_WITH_RC4_128_SHA)
|
| ++ shaSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
| ++ shaSuites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
|
| ++ shaSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
|
| + shaSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
|
| + shaSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
|
| +
|
| +@@ -188,6 +198,7 @@ class CipherSuite:
|
| + def _filterSuites(suites, settings):
|
| + macNames = settings.macNames
|
| + cipherNames = settings.cipherNames
|
| ++ keyExchangeNames = settings.keyExchangeNames
|
| + macSuites = []
|
| + if "sha" in macNames:
|
| + macSuites += CipherSuite.shaSuites
|
| +@@ -204,7 +215,20 @@ class CipherSuite:
|
| + if "rc4" in cipherNames:
|
| + cipherSuites += CipherSuite.rc4Suites
|
| +
|
| +- return [s for s in suites if s in macSuites and s in cipherSuites]
|
| ++ keyExchangeSuites = []
|
| ++ if "rsa" in keyExchangeNames:
|
| ++ keyExchangeSuites += CipherSuite.certSuites
|
| ++ if "dhe_rsa" in keyExchangeNames:
|
| ++ keyExchangeSuites += CipherSuite.dheCertSuites
|
| ++ if "srp_sha" in keyExchangeNames:
|
| ++ keyExchangeSuites += CipherSuite.srpSuites
|
| ++ if "srp_sha_rsa" in keyExchangeNames:
|
| ++ keyExchangeSuites += CipherSuite.srpCertSuites
|
| ++ if "dh_anon" in keyExchangeNames:
|
| ++ keyExchangeSuites += CipherSuite.anonSuites
|
| ++
|
| ++ return [s for s in suites if s in macSuites and
|
| ++ s in cipherSuites and s in keyExchangeSuites]
|
| +
|
| + srpSuites = []
|
| + srpSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
|
| +@@ -236,12 +260,22 @@ class CipherSuite:
|
| + certSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
|
| + certSuites.append(TLS_RSA_WITH_RC4_128_SHA)
|
| + certSuites.append(TLS_RSA_WITH_RC4_128_MD5)
|
| +- certAllSuites = srpCertSuites + certSuites
|
| +
|
| + @staticmethod
|
| + def getCertSuites(settings):
|
| + return CipherSuite._filterSuites(CipherSuite.certSuites, settings)
|
| +
|
| ++ dheCertSuites = []
|
| ++ dheCertSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
|
| ++ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
|
| ++ dheCertSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
|
| ++
|
| ++ @staticmethod
|
| ++ def getDheCertSuites(settings):
|
| ++ return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings)
|
| ++
|
| ++ certAllSuites = srpCertSuites + certSuites + dheCertSuites
|
| ++
|
| + anonSuites = []
|
| + anonSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
|
| + anonSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
|
| +@@ -250,6 +284,8 @@ class CipherSuite:
|
| + def getAnonSuites(settings):
|
| + return CipherSuite._filterSuites(CipherSuite.anonSuites, settings)
|
| +
|
| ++ dhAllSuites = dheCertSuites + anonSuites
|
| ++
|
| + @staticmethod
|
| + def canonicalCipherName(ciphersuite):
|
| + "Return the canonical name of the cipher whose number is provided."
|
| +diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py
|
| +index 7a38ee2..e0bc0e6 100644
|
| +--- a/third_party/tlslite/tlslite/handshakesettings.py
|
| ++++ b/third_party/tlslite/tlslite/handshakesettings.py
|
| +@@ -13,7 +13,9 @@ from .utils import cipherfactory
|
| + # RC4 is preferred as faster in Python, works in SSL3, and immune to CBC
|
| + # issues such as timing attacks
|
| + CIPHER_NAMES = ["rc4", "aes256", "aes128", "3des"]
|
| +-MAC_NAMES = ["sha"] # "md5" is allowed
|
| ++MAC_NAMES = ["sha"] # Don't allow "md5" by default.
|
| ++ALL_MAC_NAMES = ["sha", "md5"]
|
| ++KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
|
| + CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
|
| + CERTIFICATE_TYPES = ["x509"]
|
| +
|
| +@@ -102,6 +104,7 @@ class HandshakeSettings(object):
|
| + self.maxKeySize = 8193
|
| + self.cipherNames = CIPHER_NAMES
|
| + self.macNames = MAC_NAMES
|
| ++ self.keyExchangeNames = KEY_EXCHANGE_NAMES
|
| + self.cipherImplementations = CIPHER_IMPLEMENTATIONS
|
| + self.certificateTypes = CERTIFICATE_TYPES
|
| + self.minVersion = (3,0)
|
| +@@ -116,6 +119,7 @@ class HandshakeSettings(object):
|
| + other.maxKeySize = self.maxKeySize
|
| + other.cipherNames = self.cipherNames
|
| + other.macNames = self.macNames
|
| ++ other.keyExchangeNames = self.keyExchangeNames
|
| + other.cipherImplementations = self.cipherImplementations
|
| + other.certificateTypes = self.certificateTypes
|
| + other.minVersion = self.minVersion
|
| +@@ -148,6 +152,12 @@ class HandshakeSettings(object):
|
| + for s in other.cipherNames:
|
| + if s not in CIPHER_NAMES:
|
| + raise ValueError("Unknown cipher name: '%s'" % s)
|
| ++ for s in other.macNames:
|
| ++ if s not in ALL_MAC_NAMES:
|
| ++ raise ValueError("Unknown MAC name: '%s'" % s)
|
| ++ for s in other.keyExchangeNames:
|
| ++ if s not in KEY_EXCHANGE_NAMES:
|
| ++ raise ValueError("Unknown key exchange name: '%s'" % s)
|
| + for s in other.cipherImplementations:
|
| + if s not in CIPHER_IMPLEMENTATIONS:
|
| + raise ValueError("Unknown cipher implementation: '%s'" % s)
|
| +diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
|
| +index 532d86b..550b387 100644
|
| +--- a/third_party/tlslite/tlslite/messages.py
|
| ++++ b/third_party/tlslite/tlslite/messages.py
|
| +@@ -533,31 +533,31 @@ class ServerKeyExchange(HandshakeMsg):
|
| + p.stopLengthCheck()
|
| + return self
|
| +
|
| +- def write(self):
|
| ++ def write_params(self):
|
| + w = Writer()
|
| + if self.cipherSuite in CipherSuite.srpAllSuites:
|
| + w.addVarSeq(numberToByteArray(self.srp_N), 1, 2)
|
| + w.addVarSeq(numberToByteArray(self.srp_g), 1, 2)
|
| + w.addVarSeq(self.srp_s, 1, 1)
|
| + w.addVarSeq(numberToByteArray(self.srp_B), 1, 2)
|
| +- if self.cipherSuite in CipherSuite.srpCertSuites:
|
| +- w.addVarSeq(self.signature, 1, 2)
|
| +- elif self.cipherSuite in CipherSuite.anonSuites:
|
| ++ elif self.cipherSuite in CipherSuite.dhAllSuites:
|
| + w.addVarSeq(numberToByteArray(self.dh_p), 1, 2)
|
| + w.addVarSeq(numberToByteArray(self.dh_g), 1, 2)
|
| + w.addVarSeq(numberToByteArray(self.dh_Ys), 1, 2)
|
| +- if self.cipherSuite in []: # TODO support for signed_params
|
| +- w.addVarSeq(self.signature, 1, 2)
|
| ++ else:
|
| ++ assert(False)
|
| ++ return w.bytes
|
| ++
|
| ++ def write(self):
|
| ++ w = Writer()
|
| ++ w.bytes += self.write_params()
|
| ++ if self.cipherSuite in CipherSuite.certAllSuites:
|
| ++ w.addVarSeq(self.signature, 1, 2)
|
| + return self.postWrite(w)
|
| +
|
| + def hash(self, clientRandom, serverRandom):
|
| +- oldCipherSuite = self.cipherSuite
|
| +- self.cipherSuite = None
|
| +- try:
|
| +- bytes = clientRandom + serverRandom + self.write()[4:]
|
| +- return MD5(bytes) + SHA1(bytes)
|
| +- finally:
|
| +- self.cipherSuite = oldCipherSuite
|
| ++ bytes = clientRandom + serverRandom + self.write_params()
|
| ++ return MD5(bytes) + SHA1(bytes)
|
| +
|
| + class ServerHelloDone(HandshakeMsg):
|
| + def __init__(self):
|
| +@@ -607,7 +607,7 @@ class ClientKeyExchange(HandshakeMsg):
|
| + p.getFixBytes(len(p.bytes)-p.index)
|
| + else:
|
| + raise AssertionError()
|
| +- elif self.cipherSuite in CipherSuite.anonSuites:
|
| ++ elif self.cipherSuite in CipherSuite.dhAllSuites:
|
| + self.dh_Yc = bytesToNumber(p.getVarBytes(2))
|
| + else:
|
| + raise AssertionError()
|
| +diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
|
| +index 20cd85b..e6f7820 100644
|
| +--- a/third_party/tlslite/tlslite/tlsconnection.py
|
| ++++ b/third_party/tlslite/tlslite/tlsconnection.py
|
| +@@ -23,6 +23,103 @@ from .mathtls import *
|
| + from .handshakesettings import HandshakeSettings
|
| + from .utils.tackwrapper import *
|
| +
|
| ++class KeyExchange(object):
|
| ++ def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
|
| ++ """
|
| ++ Initializes the KeyExchange. privateKey is the signing private key.
|
| ++ """
|
| ++ self.cipherSuite = cipherSuite
|
| ++ self.clientHello = clientHello
|
| ++ self.serverHello = serverHello
|
| ++ self.privateKey = privateKey
|
| ++
|
| ++ def makeServerKeyExchange():
|
| ++ """
|
| ++ Returns a ServerKeyExchange object for the server's initial leg in the
|
| ++ handshake. If the key exchange method does not send ServerKeyExchange
|
| ++ (e.g. RSA), it returns None.
|
| ++ """
|
| ++ raise NotImplementedError()
|
| ++
|
| ++ def processClientKeyExchange(clientKeyExchange):
|
| ++ """
|
| ++ Processes the client's ClientKeyExchange message and returns the
|
| ++ premaster secret. Raises TLSLocalAlert on error.
|
| ++ """
|
| ++ raise NotImplementedError()
|
| ++
|
| ++class RSAKeyExchange(KeyExchange):
|
| ++ def makeServerKeyExchange(self):
|
| ++ return None
|
| ++
|
| ++ def processClientKeyExchange(self, clientKeyExchange):
|
| ++ premasterSecret = self.privateKey.decrypt(\
|
| ++ clientKeyExchange.encryptedPreMasterSecret)
|
| ++
|
| ++ # On decryption failure randomize premaster secret to avoid
|
| ++ # Bleichenbacher's "million message" attack
|
| ++ randomPreMasterSecret = getRandomBytes(48)
|
| ++ if not premasterSecret:
|
| ++ premasterSecret = randomPreMasterSecret
|
| ++ elif len(premasterSecret)!=48:
|
| ++ premasterSecret = randomPreMasterSecret
|
| ++ else:
|
| ++ versionCheck = (premasterSecret[0], premasterSecret[1])
|
| ++ if versionCheck != self.clientHello.client_version:
|
| ++ #Tolerate buggy IE clients
|
| ++ if versionCheck != self.serverHello.server_version:
|
| ++ premasterSecret = randomPreMasterSecret
|
| ++ return premasterSecret
|
| ++
|
| ++def _hexStringToNumber(s):
|
| ++ s = s.replace(" ", "").replace("\n", "")
|
| ++ if len(s) % 2 != 0:
|
| ++ raise ValueError("Length is not even")
|
| ++ return bytesToNumber(bytearray(s.decode("hex")))
|
| ++
|
| ++class DHE_RSAKeyExchange(KeyExchange):
|
| ++ # 2048-bit MODP Group (RFC 3526, Section 3)
|
| ++ dh_p = _hexStringToNumber("""
|
| ++FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
|
| ++29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
|
| ++EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
|
| ++E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
|
| ++EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
|
| ++C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
|
| ++83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
|
| ++670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
|
| ++E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
|
| ++DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
|
| ++15728E5A 8AACAA68 FFFFFFFF FFFFFFFF""")
|
| ++ dh_g = 2
|
| ++
|
| ++ # RFC 3526, Section 8.
|
| ++ strength = 160
|
| ++
|
| ++ def makeServerKeyExchange(self):
|
| ++ # Per RFC 3526, Section 1, the exponent should have double the entropy
|
| ++ # of the strength of the curve.
|
| ++ self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 / 8))
|
| ++ dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p)
|
| ++
|
| ++ serverKeyExchange = ServerKeyExchange(self.cipherSuite)
|
| ++ serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys)
|
| ++ serverKeyExchange.signature = self.privateKey.sign(
|
| ++ serverKeyExchange.hash(self.clientHello.random,
|
| ++ self.serverHello.random))
|
| ++ return serverKeyExchange
|
| ++
|
| ++ def processClientKeyExchange(self, clientKeyExchange):
|
| ++ dh_Yc = clientKeyExchange.dh_Yc
|
| ++
|
| ++ # First half of RFC 2631, Section 2.1.5. Validate the client's public
|
| ++ # key.
|
| ++ if not 2 <= dh_Yc <= self.dh_p - 1:
|
| ++ raise TLSLocalAlert(AlertDescription.illegal_parameter,
|
| ++ "Invalid dh_Yc value")
|
| ++
|
| ++ S = powMod(dh_Yc, self.dh_Xs, self.dh_p)
|
| ++ return numberToByteArray(S)
|
| +
|
| + class TLSConnection(TLSRecordLayer):
|
| + """
|
| +@@ -500,6 +597,8 @@ class TLSConnection(TLSRecordLayer):
|
| + cipherSuites += CipherSuite.getSrpAllSuites(settings)
|
| + elif certParams:
|
| + cipherSuites += CipherSuite.getCertSuites(settings)
|
| ++ # TODO: Client DHE_RSA not supported.
|
| ++ # cipherSuites += CipherSuite.getDheCertSuites(settings)
|
| + elif anonParams:
|
| + cipherSuites += CipherSuite.getAnonSuites(settings)
|
| + else:
|
| +@@ -1204,10 +1303,23 @@ class TLSConnection(TLSRecordLayer):
|
| + else: break
|
| + premasterSecret = result
|
| +
|
| +- # Perform the RSA key exchange
|
| +- elif cipherSuite in CipherSuite.certSuites:
|
| ++ # Perform the RSA or DHE_RSA key exchange
|
| ++ elif (cipherSuite in CipherSuite.certSuites or
|
| ++ cipherSuite in CipherSuite.dheCertSuites):
|
| ++ if cipherSuite in CipherSuite.certSuites:
|
| ++ keyExchange = RSAKeyExchange(cipherSuite,
|
| ++ clientHello,
|
| ++ serverHello,
|
| ++ privateKey)
|
| ++ elif cipherSuite in CipherSuite.dheCertSuites:
|
| ++ keyExchange = DHE_RSAKeyExchange(cipherSuite,
|
| ++ clientHello,
|
| ++ serverHello,
|
| ++ privateKey)
|
| ++ else:
|
| ++ assert(False)
|
| + for result in self._serverCertKeyExchange(clientHello, serverHello,
|
| +- certChain, privateKey,
|
| ++ certChain, keyExchange,
|
| + reqCert, reqCAs, cipherSuite,
|
| + settings, ocspResponse):
|
| + if result in (0,1): yield result
|
| +@@ -1268,6 +1380,7 @@ class TLSConnection(TLSRecordLayer):
|
| + cipherSuites += CipherSuite.getSrpSuites(settings)
|
| + elif certChain:
|
| + cipherSuites += CipherSuite.getCertSuites(settings)
|
| ++ cipherSuites += CipherSuite.getDheCertSuites(settings)
|
| + elif anon:
|
| + cipherSuites += CipherSuite.getAnonSuites(settings)
|
| + else:
|
| +@@ -1483,11 +1596,11 @@ class TLSConnection(TLSRecordLayer):
|
| +
|
| +
|
| + def _serverCertKeyExchange(self, clientHello, serverHello,
|
| +- serverCertChain, privateKey,
|
| ++ serverCertChain, keyExchange,
|
| + reqCert, reqCAs, cipherSuite,
|
| + settings, ocspResponse):
|
| +- #Send ServerHello, Certificate[, CertificateRequest],
|
| +- #ServerHelloDone
|
| ++ #Send ServerHello, Certificate[, ServerKeyExchange]
|
| ++ #[, CertificateRequest], ServerHelloDone
|
| + msgs = []
|
| +
|
| + # If we verify a client cert chain, return it
|
| +@@ -1497,6 +1610,9 @@ class TLSConnection(TLSRecordLayer):
|
| + msgs.append(Certificate(CertificateType.x509).create(serverCertChain))
|
| + if serverHello.status_request:
|
| + msgs.append(CertificateStatus().create(ocspResponse))
|
| ++ serverKeyExchange = keyExchange.makeServerKeyExchange()
|
| ++ if serverKeyExchange is not None:
|
| ++ msgs.append(serverKeyExchange)
|
| + if reqCert and reqCAs:
|
| + msgs.append(CertificateRequest().create(\
|
| + [ClientCertificateType.rsa_sign], reqCAs))
|
| +@@ -1555,21 +1671,13 @@ class TLSConnection(TLSRecordLayer):
|
| + else: break
|
| + clientKeyExchange = result
|
| +
|
| +- #Decrypt ClientKeyExchange
|
| +- premasterSecret = privateKey.decrypt(\
|
| +- clientKeyExchange.encryptedPreMasterSecret)
|
| +-
|
| +- # On decryption failure randomize premaster secret to avoid
|
| +- # Bleichenbacher's "million message" attack
|
| +- randomPreMasterSecret = getRandomBytes(48)
|
| +- versionCheck = (premasterSecret[0], premasterSecret[1])
|
| +- if not premasterSecret:
|
| +- premasterSecret = randomPreMasterSecret
|
| +- elif len(premasterSecret)!=48:
|
| +- premasterSecret = randomPreMasterSecret
|
| +- elif versionCheck != clientHello.client_version:
|
| +- if versionCheck != self.version: #Tolerate buggy IE clients
|
| +- premasterSecret = randomPreMasterSecret
|
| ++ #Process ClientKeyExchange
|
| ++ try:
|
| ++ premasterSecret = \
|
| ++ keyExchange.processClientKeyExchange(clientKeyExchange)
|
| ++ except TLSLocalAlert, alert:
|
| ++ for result in self._sendError(alert.description, alert.message):
|
| ++ yield result
|
| +
|
| + #Get and check CertificateVerify, if relevant
|
| + if clientCertChain:
|
|
|