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..07ee862a190cecf2ad40ab0735b277c2182d5cb3 100644 |
--- a/third_party/tlslite/tlslite/tlsconnection.py |
+++ b/third_party/tlslite/tlslite/tlsconnection.py |
@@ -24,6 +24,78 @@ from .handshakesettings import HandshakeSettings |
from .utils.tackwrapper import * |
+class KeyExchange(object): |
+ def __init__(self, cipherSuite, clientHello, serverHello, privateKey): |
+ self.cipherSuite = cipherSuite |
+ self.clientHello = clientHello |
+ self.serverHello = serverHello |
+ self.privateKey = privateKey |
+ |
+ def makeServerKeyExchange(): |
+ raise NotImplementedError() |
+ def processClientKeyExchange(clientKeyExchange): |
+ raise NotImplementedError() |
+ |
+ |
+class RSAKeyExchange(KeyExchange): |
+ def makeServerKeyExchange(self): |
+ return None |
Ryan Sleevi
2014/03/31 20:43:57
is None right? Should it be NotImplemented?
davidben
2014/03/31 20:58:20
RSA doesn't send a ServerKeyExchange. This method
|
+ |
+ def processClientKeyExchange(self, clientKeyExchange): |
+ premasterSecret = self.privateKey.decrypt(\ |
+ clientKeyExchange.encryptedPreMasterSecret) |
+ |
+ # On decryption failure randomize premaster secret to avoid |
+ # Bleichenbacher's "million message" attack |
Ryan Sleevi
2014/03/31 20:43:57
heheheh.
This doesn't really do that, but ok [Yes
davidben
2014/03/31 20:58:20
:-P I make no claims as to whether that comment wa
wtc
2014/04/02 03:34:20
If self.privateKey.decrypt does RSA blinding, then
|
+ randomPreMasterSecret = getRandomBytes(48) |
+ versionCheck = (premasterSecret[0], premasterSecret[1]) |
+ if not premasterSecret: |
+ premasterSecret = randomPreMasterSecret |
+ elif len(premasterSecret)!=48: |
+ premasterSecret = randomPreMasterSecret |
+ elif versionCheck != self.clientHello.client_version: |
+ #Tolerate buggy IE clients |
wtc
2014/04/01 22:00:01
This is a very old bug of IE. I suspect this bug h
davidben
2014/04/01 23:25:18
Yeah, this block was just moved over. I can also j
wtc
2014/04/02 03:34:20
It's fine to keep this. We should only drop this i
|
+ if versionCheck != self.serverHello.server_version: |
wtc
2014/04/01 22:00:01
Is self.serverHello.server_version correct? The or
davidben
2014/04/01 23:25:18
Should be. I made sure it passed all tlslite's ori
|
+ premasterSecret = randomPreMasterSecret |
+ return premasterSecret |
+ |
+class DHE_RSAKeyExchange(KeyExchange): |
+ # Generated with openssl dhparam 1024 -text. Generating a new one each time |
+ # in Python is far far far too slow. |
wtc
2014/04/01 22:00:01
IMPORTANT: please use one of the well-known DH gro
davidben
2014/04/01 23:25:18
Done.
|
+ dh_p = bytesToNumber( |
+ bytearray( |
+ "\x00\x88\xc4\xdc\x2a\xd9\xba\x8d\x24\x69\x7f\xe4\xd4\xeb\x62" |
+ "\x04\x43\xe8\x31\x08\x30\xa8\xe4\x24\x0f\xa7\xc3\xff\x84\x52" |
+ "\x44\x4a\x1b\x8c\x88\x16\xa6\x17\x90\xac\x21\x34\xfb\xc5\xff" |
+ "\x90\x46\x32\x29\xfa\x9d\xd3\x36\x05\xc2\x86\xcf\xde\x77\x68" |
+ "\x4c\xe3\xb0\x34\x55\xce\x27\x85\x46\x94\xad\x0c\xef\x11\x53" |
+ "\x61\x50\x0c\x3e\x7b\x8a\x3c\xa0\x52\x6c\xb2\xa5\x84\xf7\xa9" |
+ "\xdc\x9d\x57\x60\xd0\x89\xc6\x14\x39\x54\xce\x20\xcc\x2d\xe9" |
+ "\x90\xeb\xe7\x42\xf1\x03\x60\x5b\x06\x2f\x51\x97\x01\xc2\x1d" |
+ "\xfa\xb3\xfe\x02\x4b\xee\xd1\x65\xcb")) |
+ dh_g = 2 |
+ |
+ def makeServerKeyExchange(self): |
+ self.dh_Xs = bytesToNumber(getRandomBytes(1024 / 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 |
+ |
+ if dh_Yc % self.dh_p == 0: |
wtc
2014/04/01 22:00:01
Is this check recommended by RFC 5246? I'm just cu
davidben
2014/04/01 23:25:18
I just copied the DH code from _serverAnonKeyExcha
|
+ raise TLSLocalAlert(AlertDescription.illegal_parameter, |
+ "Suspicious dh_Yc value") |
+ |
+ S = powMod(dh_Yc, self.dh_Xs, self.dh_p) |
+ return numberToByteArray(S) |
+ |
class TLSConnection(TLSRecordLayer): |
""" |
This class wraps a socket and provides TLS handshaking and data |
@@ -500,6 +572,8 @@ class TLSConnection(TLSRecordLayer): |
cipherSuites += CipherSuite.getSrpAllSuites(settings) |
elif certParams: |
cipherSuites += CipherSuite.getCertSuites(settings) |
+ # Client DHE_RSA not supported. |
+ # cipherSuites += CipherSuite.getDheCertSuites(settings) |
elif anonParams: |
cipherSuites += CipherSuite.getAnonSuites(settings) |
else: |
@@ -1205,9 +1279,22 @@ class TLSConnection(TLSRecordLayer): |
premasterSecret = result |
# Perform the RSA key exchange |
wtc
2014/04/01 22:00:01
Nit: this comment should say "Perform the RSA or D
davidben
2014/04/01 23:25:18
Done.
|
- elif cipherSuite in CipherSuite.certSuites: |
+ 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 +1355,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,7 +1571,7 @@ class TLSConnection(TLSRecordLayer): |
def _serverCertKeyExchange(self, clientHello, serverHello, |
- serverCertChain, privateKey, |
+ serverCertChain, keyExchange, |
reqCert, reqCAs, cipherSuite, |
settings, ocspResponse): |
#Send ServerHello, Certificate[, CertificateRequest], |
wtc
2014/04/01 22:00:01
Nit: add the optional ServerKeyExchange method to
davidben
2014/04/01 23:25:18
Done.
|
@@ -1497,6 +1585,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 +1646,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, e: |
+ for result in self._sendError(alert.description, alert.message): |
wtc
2014/04/01 22:00:01
IMPORTANT: Should |alert| be |e|?
davidben
2014/04/01 23:25:18
Oops. Done.
|
+ yield result |
#Get and check CertificateVerify, if relevant |
if clientCertChain: |