Chromium Code Reviews| 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 |