OLD | NEW |
---|---|
1 # Authors: | 1 # Authors: |
2 # Trevor Perrin | 2 # Trevor Perrin |
3 # Google - added reqCAs parameter | 3 # Google - added reqCAs parameter |
4 # Google (adapted by Sam Rushing and Marcelo Fernandez) - NPN support | 4 # Google (adapted by Sam Rushing and Marcelo Fernandez) - NPN support |
5 # Dimitris Moraitis - Anon ciphersuites | 5 # Dimitris Moraitis - Anon ciphersuites |
6 # Martin von Loewis - python 3 port | 6 # Martin von Loewis - python 3 port |
7 # | 7 # |
8 # See the LICENSE file for legal information regarding use of this file. | 8 # See the LICENSE file for legal information regarding use of this file. |
9 | 9 |
10 """ | 10 """ |
11 MAIN CLASS FOR TLS LITE (START HERE!). | 11 MAIN CLASS FOR TLS LITE (START HERE!). |
12 """ | 12 """ |
13 | 13 |
14 import socket | 14 import socket |
15 from .utils.compat import formatExceptionTrace | 15 from .utils.compat import formatExceptionTrace |
16 from .tlsrecordlayer import TLSRecordLayer | 16 from .tlsrecordlayer import TLSRecordLayer |
17 from .session import Session | 17 from .session import Session |
18 from .constants import * | 18 from .constants import * |
19 from .utils.cryptomath import getRandomBytes | 19 from .utils.cryptomath import getRandomBytes |
20 from .errors import * | 20 from .errors import * |
21 from .messages import * | 21 from .messages import * |
22 from .mathtls import * | 22 from .mathtls import * |
23 from .handshakesettings import HandshakeSettings | 23 from .handshakesettings import HandshakeSettings |
24 from .utils.tackwrapper import * | 24 from .utils.tackwrapper import * |
25 | 25 |
26 | 26 |
27 class KeyExchange(object): | |
28 def __init__(self, cipherSuite, clientHello, serverHello, privateKey): | |
wtc
2014/04/02 19:11:29
Nit: it would be nice to document what privateKey
wtc
2014/04/02 19:13:46
Sorry, I forgot to update this comment. I believe
davidben
2014/04/03 18:45:48
Done.
| |
29 self.cipherSuite = cipherSuite | |
30 self.clientHello = clientHello | |
31 self.serverHello = serverHello | |
32 self.privateKey = privateKey | |
33 | |
34 def makeServerKeyExchange(): | |
wtc
2014/04/02 19:11:29
Nit: document what this method returns, and what i
davidben
2014/04/03 18:45:48
Done.
| |
35 raise NotImplementedError() | |
36 def processClientKeyExchange(clientKeyExchange): | |
wtc
2014/04/02 19:11:29
Nit: document what this method returns (the premas
davidben
2014/04/03 18:45:48
Done.
| |
37 raise NotImplementedError() | |
38 | |
39 | |
wtc
2014/04/02 19:11:29
Nit: use only one blank line here and before line
davidben
2014/04/03 18:45:48
Done. Although this code doesn't seem to be very c
| |
40 class RSAKeyExchange(KeyExchange): | |
41 def makeServerKeyExchange(self): | |
42 return None | |
43 | |
44 def processClientKeyExchange(self, clientKeyExchange): | |
45 premasterSecret = self.privateKey.decrypt(\ | |
46 clientKeyExchange.encryptedPreMasterSecret) | |
47 | |
48 # On decryption failure randomize premaster secret to avoid | |
49 # Bleichenbacher's "million message" attack | |
50 randomPreMasterSecret = getRandomBytes(48) | |
51 versionCheck = (premasterSecret[0], premasterSecret[1]) | |
52 if not premasterSecret: | |
wtc
2014/04/02 19:11:29
Hmm... On line 51 we already dereferenced premaste
davidben
2014/04/03 18:45:48
Haha. I guess that code never actually worked then
| |
53 premasterSecret = randomPreMasterSecret | |
54 elif len(premasterSecret)!=48: | |
55 premasterSecret = randomPreMasterSecret | |
56 elif versionCheck != self.clientHello.client_version: | |
57 #Tolerate buggy IE clients | |
58 if versionCheck != self.serverHello.server_version: | |
59 premasterSecret = randomPreMasterSecret | |
60 return premasterSecret | |
61 | |
62 def _hexStringToNumber(s): | |
63 s = s.replace(" ", "").replace("\n", "") | |
64 if len(s) % 2 != 0: | |
65 raise ValueError("Length is not even") | |
66 return bytesToNumber(bytearray(s.decode("hex"))) | |
67 | |
68 class DHE_RSAKeyExchange(KeyExchange): | |
69 # 2048-bit MODP Group (RFC 3526, Section 3) | |
70 dh_p = _hexStringToNumber(""" | |
71 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 | |
72 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD | |
73 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 | |
74 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED | |
75 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D | |
76 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F | |
77 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D | |
78 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B | |
79 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 | |
80 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510 | |
81 15728E5A 8AACAA68 FFFFFFFF FFFFFFFF""") | |
wtc
2014/04/02 19:11:29
Nit: should lines 71-81 be indented?
davidben
2014/04/03 18:45:48
*shrug* It does actually change what's in the stri
| |
82 dh_g = 2 | |
83 | |
84 # RFC 3526, Section 8. | |
85 strength = 160 | |
86 | |
87 def makeServerKeyExchange(self): | |
88 # Per RFC 3526, Section 1, the exponent should have double the entropy | |
89 # of the strength of the curve. | |
90 self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 / 8)) | |
91 dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p) | |
92 | |
93 serverKeyExchange = ServerKeyExchange(self.cipherSuite) | |
94 serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys) | |
95 serverKeyExchange.signature = self.privateKey.sign( | |
96 serverKeyExchange.hash(self.clientHello.random, | |
97 self.serverHello.random)) | |
98 return serverKeyExchange | |
99 | |
100 def processClientKeyExchange(self, clientKeyExchange): | |
101 dh_Yc = clientKeyExchange.dh_Yc | |
102 | |
103 # First half of RFC 2631, Section 2.1.5. | |
wtc
2014/04/02 19:11:29
Nit: Add "Validate the client's public key."
This
davidben
2014/04/03 18:45:48
Done.
| |
104 if not 2 <= dh_Yc <= self.dh_p - 1: | |
105 raise TLSLocalAlert(AlertDescription.illegal_parameter, | |
106 "Suspicious dh_Yc value") | |
wtc
2014/04/02 19:11:29
Nit: Suspicious => Invalid
davidben
2014/04/03 18:45:48
Done.
| |
107 | |
108 S = powMod(dh_Yc, self.dh_Xs, self.dh_p) | |
109 return numberToByteArray(S) | |
110 | |
27 class TLSConnection(TLSRecordLayer): | 111 class TLSConnection(TLSRecordLayer): |
28 """ | 112 """ |
29 This class wraps a socket and provides TLS handshaking and data | 113 This class wraps a socket and provides TLS handshaking and data |
30 transfer. | 114 transfer. |
31 | 115 |
32 To use this class, create a new instance, passing a connected | 116 To use this class, create a new instance, passing a connected |
33 socket into the constructor. Then call some handshake function. | 117 socket into the constructor. Then call some handshake function. |
34 If the handshake completes without raising an exception, then a TLS | 118 If the handshake completes without raising an exception, then a TLS |
35 connection has been negotiated. You can transfer data over this | 119 connection has been negotiated. You can transfer data over this |
36 connection as if it were a socket. | 120 connection as if it were a socket. |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
493 | 577 |
494 def _clientSendClientHello(self, settings, session, srpUsername, | 578 def _clientSendClientHello(self, settings, session, srpUsername, |
495 srpParams, certParams, anonParams, | 579 srpParams, certParams, anonParams, |
496 serverName, nextProtos, reqTack): | 580 serverName, nextProtos, reqTack): |
497 #Initialize acceptable ciphersuites | 581 #Initialize acceptable ciphersuites |
498 cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] | 582 cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] |
499 if srpParams: | 583 if srpParams: |
500 cipherSuites += CipherSuite.getSrpAllSuites(settings) | 584 cipherSuites += CipherSuite.getSrpAllSuites(settings) |
501 elif certParams: | 585 elif certParams: |
502 cipherSuites += CipherSuite.getCertSuites(settings) | 586 cipherSuites += CipherSuite.getCertSuites(settings) |
587 # Client DHE_RSA not supported. | |
wtc
2014/04/02 19:11:29
Nit: Add "TODO" to this comment.
davidben
2014/04/03 18:45:48
Done.
| |
588 # cipherSuites += CipherSuite.getDheCertSuites(settings) | |
503 elif anonParams: | 589 elif anonParams: |
504 cipherSuites += CipherSuite.getAnonSuites(settings) | 590 cipherSuites += CipherSuite.getAnonSuites(settings) |
505 else: | 591 else: |
506 assert(False) | 592 assert(False) |
507 | 593 |
508 #Initialize acceptable certificate types | 594 #Initialize acceptable certificate types |
509 certificateTypes = settings._getCertificateTypes() | 595 certificateTypes = settings._getCertificateTypes() |
510 | 596 |
511 #Either send ClientHello (with a resumable session)... | 597 #Either send ClientHello (with a resumable session)... |
512 if session and session.sessionID: | 598 if session and session.sessionID: |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1197 # Perform the SRP key exchange | 1283 # Perform the SRP key exchange |
1198 clientCertChain = None | 1284 clientCertChain = None |
1199 if cipherSuite in CipherSuite.srpAllSuites: | 1285 if cipherSuite in CipherSuite.srpAllSuites: |
1200 for result in self._serverSRPKeyExchange(clientHello, serverHello, | 1286 for result in self._serverSRPKeyExchange(clientHello, serverHello, |
1201 verifierDB, cipherSuite, | 1287 verifierDB, cipherSuite, |
1202 privateKey, certChain): | 1288 privateKey, certChain): |
1203 if result in (0,1): yield result | 1289 if result in (0,1): yield result |
1204 else: break | 1290 else: break |
1205 premasterSecret = result | 1291 premasterSecret = result |
1206 | 1292 |
1207 # Perform the RSA key exchange | 1293 # Perform the RSA or DHE_RSA key exchange |
1208 elif cipherSuite in CipherSuite.certSuites: | 1294 elif (cipherSuite in CipherSuite.certSuites or |
1295 cipherSuite in CipherSuite.dheCertSuites): | |
1296 if cipherSuite in CipherSuite.certSuites: | |
1297 keyExchange = RSAKeyExchange(cipherSuite, | |
1298 clientHello, | |
1299 serverHello, | |
1300 privateKey) | |
1301 elif cipherSuite in CipherSuite.dheCertSuites: | |
1302 keyExchange = DHE_RSAKeyExchange(cipherSuite, | |
1303 clientHello, | |
1304 serverHello, | |
1305 privateKey) | |
1306 else: | |
1307 assert(False) | |
1209 for result in self._serverCertKeyExchange(clientHello, serverHello, | 1308 for result in self._serverCertKeyExchange(clientHello, serverHello, |
1210 certChain, privateKey, | 1309 certChain, keyExchange, |
1211 reqCert, reqCAs, cipherSuite, | 1310 reqCert, reqCAs, cipherSuite, |
1212 settings, ocspResponse): | 1311 settings, ocspResponse): |
1213 if result in (0,1): yield result | 1312 if result in (0,1): yield result |
1214 else: break | 1313 else: break |
1215 (premasterSecret, clientCertChain) = result | 1314 (premasterSecret, clientCertChain) = result |
1216 | 1315 |
1217 # Perform anonymous Diffie Hellman key exchange | 1316 # Perform anonymous Diffie Hellman key exchange |
1218 elif cipherSuite in CipherSuite.anonSuites: | 1317 elif cipherSuite in CipherSuite.anonSuites: |
1219 for result in self._serverAnonKeyExchange(clientHello, serverHello, | 1318 for result in self._serverAnonKeyExchange(clientHello, serverHello, |
1220 cipherSuite, settings): | 1319 cipherSuite, settings): |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1261 sessionCache, anon, tlsIntolerant, fallbackSCSV) : | 1360 sessionCache, anon, tlsIntolerant, fallbackSCSV) : |
1262 #Initialize acceptable cipher suites | 1361 #Initialize acceptable cipher suites |
1263 cipherSuites = [] | 1362 cipherSuites = [] |
1264 if verifierDB: | 1363 if verifierDB: |
1265 if certChain: | 1364 if certChain: |
1266 cipherSuites += \ | 1365 cipherSuites += \ |
1267 CipherSuite.getSrpCertSuites(settings) | 1366 CipherSuite.getSrpCertSuites(settings) |
1268 cipherSuites += CipherSuite.getSrpSuites(settings) | 1367 cipherSuites += CipherSuite.getSrpSuites(settings) |
1269 elif certChain: | 1368 elif certChain: |
1270 cipherSuites += CipherSuite.getCertSuites(settings) | 1369 cipherSuites += CipherSuite.getCertSuites(settings) |
1370 cipherSuites += CipherSuite.getDheCertSuites(settings) | |
1271 elif anon: | 1371 elif anon: |
1272 cipherSuites += CipherSuite.getAnonSuites(settings) | 1372 cipherSuites += CipherSuite.getAnonSuites(settings) |
1273 else: | 1373 else: |
1274 assert(False) | 1374 assert(False) |
1275 | 1375 |
1276 #Tentatively set version to most-desirable version, so if an error | 1376 #Tentatively set version to most-desirable version, so if an error |
1277 #occurs parsing the ClientHello, this is what we'll use for the | 1377 #occurs parsing the ClientHello, this is what we'll use for the |
1278 #error alert | 1378 #error alert |
1279 self.version = settings.maxVersion | 1379 self.version = settings.maxVersion |
1280 | 1380 |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1476 u = makeU(N, A, B) | 1576 u = makeU(N, A, B) |
1477 | 1577 |
1478 #Calculate premaster secret | 1578 #Calculate premaster secret |
1479 S = powMod((A * powMod(v,u,N)) % N, b, N) | 1579 S = powMod((A * powMod(v,u,N)) % N, b, N) |
1480 premasterSecret = numberToByteArray(S) | 1580 premasterSecret = numberToByteArray(S) |
1481 | 1581 |
1482 yield premasterSecret | 1582 yield premasterSecret |
1483 | 1583 |
1484 | 1584 |
1485 def _serverCertKeyExchange(self, clientHello, serverHello, | 1585 def _serverCertKeyExchange(self, clientHello, serverHello, |
1486 serverCertChain, privateKey, | 1586 serverCertChain, keyExchange, |
1487 reqCert, reqCAs, cipherSuite, | 1587 reqCert, reqCAs, cipherSuite, |
1488 settings, ocspResponse): | 1588 settings, ocspResponse): |
1489 #Send ServerHello, Certificate[, CertificateRequest], | 1589 #Send ServerHello, Certificate[, ServerKeyExchange] |
1490 #ServerHelloDone | 1590 #[, CertificateRequest], ServerHelloDone |
1491 msgs = [] | 1591 msgs = [] |
1492 | 1592 |
1493 # If we verify a client cert chain, return it | 1593 # If we verify a client cert chain, return it |
1494 clientCertChain = None | 1594 clientCertChain = None |
1495 | 1595 |
1496 msgs.append(serverHello) | 1596 msgs.append(serverHello) |
1497 msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) | 1597 msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) |
1498 if serverHello.status_request: | 1598 if serverHello.status_request: |
1499 msgs.append(CertificateStatus().create(ocspResponse)) | 1599 msgs.append(CertificateStatus().create(ocspResponse)) |
1600 serverKeyExchange = keyExchange.makeServerKeyExchange() | |
wtc
2014/04/02 19:11:29
Nit: the function call you use to create the Serve
davidben
2014/04/03 18:45:48
Hrm. Yeah, I'm not sure we can follow that pattern
| |
1601 if serverKeyExchange is not None: | |
1602 msgs.append(serverKeyExchange) | |
1500 if reqCert and reqCAs: | 1603 if reqCert and reqCAs: |
1501 msgs.append(CertificateRequest().create(\ | 1604 msgs.append(CertificateRequest().create(\ |
1502 [ClientCertificateType.rsa_sign], reqCAs)) | 1605 [ClientCertificateType.rsa_sign], reqCAs)) |
1503 elif reqCert: | 1606 elif reqCert: |
1504 msgs.append(CertificateRequest()) | 1607 msgs.append(CertificateRequest()) |
1505 msgs.append(ServerHelloDone()) | 1608 msgs.append(ServerHelloDone()) |
1506 for result in self._sendMsgs(msgs): | 1609 for result in self._sendMsgs(msgs): |
1507 yield result | 1610 yield result |
1508 | 1611 |
1509 #From here on, the client's messages must have the right version | 1612 #From here on, the client's messages must have the right version |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1548 raise AssertionError() | 1651 raise AssertionError() |
1549 | 1652 |
1550 #Get ClientKeyExchange | 1653 #Get ClientKeyExchange |
1551 for result in self._getMsg(ContentType.handshake, | 1654 for result in self._getMsg(ContentType.handshake, |
1552 HandshakeType.client_key_exchange, | 1655 HandshakeType.client_key_exchange, |
1553 cipherSuite): | 1656 cipherSuite): |
1554 if result in (0,1): yield result | 1657 if result in (0,1): yield result |
1555 else: break | 1658 else: break |
1556 clientKeyExchange = result | 1659 clientKeyExchange = result |
1557 | 1660 |
1558 #Decrypt ClientKeyExchange | 1661 #Process ClientKeyExchange |
1559 premasterSecret = privateKey.decrypt(\ | 1662 try: |
1560 clientKeyExchange.encryptedPreMasterSecret) | 1663 premasterSecret = \ |
1561 | 1664 keyExchange.processClientKeyExchange(clientKeyExchange) |
1562 # On decryption failure randomize premaster secret to avoid | 1665 except TLSLocalAlert, e: |
1563 # Bleichenbacher's "million message" attack | 1666 for result in self._sendError(e.description, e.message): |
wtc
2014/04/02 19:11:29
Nit: rename |e| to |alert|?
davidben
2014/04/03 18:45:48
Done.
| |
1564 randomPreMasterSecret = getRandomBytes(48) | 1667 yield result |
1565 versionCheck = (premasterSecret[0], premasterSecret[1]) | |
1566 if not premasterSecret: | |
1567 premasterSecret = randomPreMasterSecret | |
1568 elif len(premasterSecret)!=48: | |
1569 premasterSecret = randomPreMasterSecret | |
1570 elif versionCheck != clientHello.client_version: | |
1571 if versionCheck != self.version: #Tolerate buggy IE clients | |
1572 premasterSecret = randomPreMasterSecret | |
1573 | 1668 |
1574 #Get and check CertificateVerify, if relevant | 1669 #Get and check CertificateVerify, if relevant |
1575 if clientCertChain: | 1670 if clientCertChain: |
1576 if self.version == (3,0): | 1671 if self.version == (3,0): |
1577 masterSecret = calcMasterSecret(self.version, premasterSecret, | 1672 masterSecret = calcMasterSecret(self.version, premasterSecret, |
1578 clientHello.random, serverHello.random) | 1673 clientHello.random, serverHello.random) |
1579 verifyBytes = self._calcSSLHandshakeHash(masterSecret, b"") | 1674 verifyBytes = self._calcSSLHandshakeHash(masterSecret, b"") |
1580 elif self.version in ((3,1), (3,2)): | 1675 elif self.version in ((3,1), (3,2)): |
1581 verifyBytes = self._handshake_md5.digest() + \ | 1676 verifyBytes = self._handshake_md5.digest() + \ |
1582 self._handshake_sha.digest() | 1677 self._handshake_sha.digest() |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1810 except TLSAlert as alert: | 1905 except TLSAlert as alert: |
1811 if not self.fault: | 1906 if not self.fault: |
1812 raise | 1907 raise |
1813 if alert.description not in Fault.faultAlerts[self.fault]: | 1908 if alert.description not in Fault.faultAlerts[self.fault]: |
1814 raise TLSFaultError(str(alert)) | 1909 raise TLSFaultError(str(alert)) |
1815 else: | 1910 else: |
1816 pass | 1911 pass |
1817 except: | 1912 except: |
1818 self._shutdown(False) | 1913 self._shutdown(False) |
1819 raise | 1914 raise |
OLD | NEW |