• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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