| Index: third_party/tlslite/tlslite/tlsconnection.py
|
| diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
|
| index 20cd85bc90f31b456ec45c5d23a746123b962346..e6f7820dc6f0f0badd98222ce5b8f6a3a6c24e8c 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:
|
|
|