Index: third_party/tlslite/patches/intolerance_options.patch |
diff --git a/third_party/tlslite/patches/intolerance_options.patch b/third_party/tlslite/patches/intolerance_options.patch |
new file mode 100644 |
index 0000000000000000000000000000000000000000..110b5f6e794170cb887e4f6ef6f3de966fc686a8 |
--- /dev/null |
+++ b/third_party/tlslite/patches/intolerance_options.patch |
@@ -0,0 +1,188 @@ |
+diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py |
+index e0bc0e6..4af3791 100644 |
+--- a/third_party/tlslite/tlslite/handshakesettings.py |
++++ b/third_party/tlslite/tlslite/handshakesettings.py |
+@@ -18,6 +18,7 @@ ALL_MAC_NAMES = ["sha", "md5"] |
+ KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"] |
+ CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"] |
+ CERTIFICATE_TYPES = ["x509"] |
++TLS_INTOLERANCE_TYPES = ["alert", "close", "reset"] |
+ |
+ class HandshakeSettings(object): |
+ """This class encapsulates various parameters that can be used with |
+@@ -92,6 +93,17 @@ class HandshakeSettings(object): |
+ The default is (3,2). (WARNING: Some servers may (improperly) |
+ reject clients which offer support for TLS 1.1. In this case, |
+ try lowering maxVersion to (3,1)). |
++ |
++ @type tlsIntolerant: tuple |
++ @ivar tlsIntolerant: TLS version intolerance for servers. |
++ |
++ If tlsIntolerant is not None, the server will simulate TLS version |
++ intolerance by returning a fatal handshake_failure alert or a TCP reset to |
++ all TLS versions tlsIntolerant or higher. |
++ |
++ @type tlsIntoleranceType: str |
++ @ivar tlsIntoleranceType: How the server should react when simulating |
++ TLS intolerance. |
+ |
+ @type useExperimentalTackExtension: bool |
+ @ivar useExperimentalTackExtension: Whether to enabled TACK support. |
+@@ -109,6 +121,8 @@ class HandshakeSettings(object): |
+ self.certificateTypes = CERTIFICATE_TYPES |
+ self.minVersion = (3,0) |
+ self.maxVersion = (3,2) |
++ self.tlsIntolerant = None |
++ self.tlsIntoleranceType = 'alert' |
+ self.useExperimentalTackExtension = False |
+ |
+ # Validates the min/max fields, and certificateTypes |
+@@ -124,6 +138,8 @@ class HandshakeSettings(object): |
+ other.certificateTypes = self.certificateTypes |
+ other.minVersion = self.minVersion |
+ other.maxVersion = self.maxVersion |
++ other.tlsIntolerant = self.tlsIntolerant |
++ other.tlsIntoleranceType = self.tlsIntoleranceType |
+ |
+ if not cipherfactory.tripleDESPresent: |
+ other.cipherNames = [e for e in self.cipherNames if e != "3des"] |
+@@ -165,6 +181,10 @@ class HandshakeSettings(object): |
+ if s not in CERTIFICATE_TYPES: |
+ raise ValueError("Unknown certificate type: '%s'" % s) |
+ |
++ if other.tlsIntoleranceType not in TLS_INTOLERANCE_TYPES: |
++ raise ValueError( |
++ "Unknown TLS intolerance type: '%s'" % other.tlsIntoleranceType) |
++ |
+ if other.minVersion > other.maxVersion: |
+ raise ValueError("Versions set incorrectly") |
+ |
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py |
+index 044ad59..7c1572f 100644 |
+--- a/third_party/tlslite/tlslite/tlsconnection.py |
++++ b/third_party/tlslite/tlslite/tlsconnection.py |
+@@ -1065,7 +1065,7 @@ class TLSConnection(TLSRecordLayer): |
+ reqCAs = None, reqCertTypes = None, |
+ tacks=None, activationFlags=0, |
+ nextProtos=None, anon=False, |
+- tlsIntolerant=None, signedCertTimestamps=None, |
++ signedCertTimestamps=None, |
+ fallbackSCSV=False, ocspResponse=None): |
+ """Perform a handshake in the role of server. |
+ |
+@@ -1139,11 +1139,6 @@ class TLSConnection(TLSRecordLayer): |
+ clients through the Next-Protocol Negotiation Extension, |
+ if they support it. |
+ |
+- @type tlsIntolerant: (int, int) or None |
+- @param tlsIntolerant: If tlsIntolerant is not None, the server will |
+- simulate TLS version intolerance by returning a fatal handshake_failure |
+- alert to all TLS versions tlsIntolerant or higher. |
+- |
+ @type signedCertTimestamps: str |
+ @param signedCertTimestamps: A SignedCertificateTimestampList (as a |
+ binary 8-bit string) that will be sent as a TLS extension whenever |
+@@ -1175,7 +1170,7 @@ class TLSConnection(TLSRecordLayer): |
+ certChain, privateKey, reqCert, sessionCache, settings, |
+ checker, reqCAs, reqCertTypes, |
+ tacks=tacks, activationFlags=activationFlags, |
+- nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, |
++ nextProtos=nextProtos, anon=anon, |
+ signedCertTimestamps=signedCertTimestamps, |
+ fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse): |
+ pass |
+@@ -1187,7 +1182,6 @@ class TLSConnection(TLSRecordLayer): |
+ reqCAs=None, reqCertTypes=None, |
+ tacks=None, activationFlags=0, |
+ nextProtos=None, anon=False, |
+- tlsIntolerant=None, |
+ signedCertTimestamps=None, |
+ fallbackSCSV=False, |
+ ocspResponse=None |
+@@ -1210,7 +1204,6 @@ class TLSConnection(TLSRecordLayer): |
+ reqCAs=reqCAs, reqCertTypes=reqCertTypes, |
+ tacks=tacks, activationFlags=activationFlags, |
+ nextProtos=nextProtos, anon=anon, |
+- tlsIntolerant=tlsIntolerant, |
+ signedCertTimestamps=signedCertTimestamps, |
+ fallbackSCSV=fallbackSCSV, |
+ ocspResponse=ocspResponse) |
+@@ -1223,7 +1216,7 @@ class TLSConnection(TLSRecordLayer): |
+ settings, reqCAs, reqCertTypes, |
+ tacks, activationFlags, |
+ nextProtos, anon, |
+- tlsIntolerant, signedCertTimestamps, fallbackSCSV, |
++ signedCertTimestamps, fallbackSCSV, |
+ ocspResponse): |
+ |
+ self._handshakeStart(client=False) |
+@@ -1261,7 +1254,7 @@ class TLSConnection(TLSRecordLayer): |
+ # Handle ClientHello and resumption |
+ for result in self._serverGetClientHello(settings, certChain,\ |
+ verifierDB, sessionCache, |
+- anon, tlsIntolerant, fallbackSCSV): |
++ anon, fallbackSCSV): |
+ if result in (0,1): yield result |
+ elif result == None: |
+ self._handshakeDone(resumed=True) |
+@@ -1376,7 +1369,7 @@ class TLSConnection(TLSRecordLayer): |
+ |
+ |
+ def _serverGetClientHello(self, settings, certChain, verifierDB, |
+- sessionCache, anon, tlsIntolerant, fallbackSCSV): |
++ sessionCache, anon, fallbackSCSV): |
+ #Initialize acceptable cipher suites |
+ cipherSuites = [] |
+ if verifierDB: |
+@@ -1413,11 +1406,21 @@ class TLSConnection(TLSRecordLayer): |
+ yield result |
+ |
+ #If simulating TLS intolerance, reject certain TLS versions. |
+- elif (tlsIntolerant is not None and |
+- clientHello.client_version >= tlsIntolerant): |
+- for result in self._sendError(\ |
++ elif (settings.tlsIntolerant is not None and |
++ clientHello.client_version >= settings.tlsIntolerant): |
++ if settings.tlsIntoleranceType == "alert": |
++ for result in self._sendError(\ |
+ AlertDescription.handshake_failure): |
+- yield result |
++ yield result |
++ elif settings.tlsIntoleranceType == "close": |
++ self._abruptClose() |
++ raise TLSUnsupportedError("Simulating version intolerance") |
++ elif settings.tlsIntoleranceType == "reset": |
++ self._abruptClose(reset=True) |
++ raise TLSUnsupportedError("Simulating version intolerance") |
++ else: |
++ raise ValueError("Unknown intolerance type: '%s'" % |
++ settings.tlsIntoleranceType) |
+ |
+ #If client's version is too high, propose my highest version |
+ elif clientHello.client_version > settings.maxVersion: |
+diff --git a/third_party/tlslite/tlslite/tlsrecordlayer.py b/third_party/tlslite/tlslite/tlsrecordlayer.py |
+index 370dc9a..23c2a2f 100644 |
+--- a/third_party/tlslite/tlslite/tlsrecordlayer.py |
++++ b/third_party/tlslite/tlslite/tlsrecordlayer.py |
+@@ -19,6 +19,7 @@ from .constants import * |
+ from .utils.cryptomath import getRandomBytes |
+ |
+ import socket |
++import struct |
+ import errno |
+ import traceback |
+ |
+@@ -523,6 +524,13 @@ class TLSRecordLayer(object): |
+ self._shutdown(False) |
+ raise TLSLocalAlert(alert, errorStr) |
+ |
++ def _abruptClose(self, reset=False): |
++ if reset: |
++ #Set an SO_LINGER timeout of 0 to send a TCP RST. |
++ self.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, |
++ struct.pack('ii', 1, 0)) |
++ self._shutdown(False) |
++ |
+ def _sendMsgs(self, msgs): |
+ randomizeFirstBlock = True |
+ for msg in msgs: |