1 diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py 2 index e0bc0e6..0d4ccf2 100644 3 --- a/third_party/tlslite/tlslite/handshakesettings.py 4 +++ b/third_party/tlslite/tlslite/handshakesettings.py 5 @@ -18,6 +18,7 @@ ALL_MAC_NAMES = ["sha", "md5"] 6 KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"] 7 CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"] 8 CERTIFICATE_TYPES = ["x509"] 9 +TLS_INTOLERANCE_TYPES = ["alert", "close", "reset"] 10 11 class HandshakeSettings(object): 12 """This class encapsulates various parameters that can be used with 13 @@ -92,6 +93,21 @@ class HandshakeSettings(object): 14 The default is (3,2). (WARNING: Some servers may (improperly) 15 reject clients which offer support for TLS 1.1. In this case, 16 try lowering maxVersion to (3,1)). 17 + 18 + @type tlsIntolerant: tuple 19 + @ivar tlsIntolerant: The TLS ClientHello version which the server 20 + simulates intolerance of. 21 + 22 + If tlsIntolerant is not None, the server will simulate TLS version 23 + intolerance by aborting the handshake in response to all TLS versions 24 + tlsIntolerant or higher. 25 + 26 + @type tlsIntoleranceType: str 27 + @ivar tlsIntoleranceType: How the server should react when simulating TLS 28 + intolerance. 29 + 30 + The allowed values are "alert" (return a fatal handshake_failure alert), 31 + "close" (abruptly close the connection), and "reset" (send a TCP reset). 32 33 @type useExperimentalTackExtension: bool 34 @ivar useExperimentalTackExtension: Whether to enabled TACK support. 35 @@ -109,6 +125,8 @@ class HandshakeSettings(object): 36 self.certificateTypes = CERTIFICATE_TYPES 37 self.minVersion = (3,0) 38 self.maxVersion = (3,2) 39 + self.tlsIntolerant = None 40 + self.tlsIntoleranceType = 'alert' 41 self.useExperimentalTackExtension = False 42 43 # Validates the min/max fields, and certificateTypes 44 @@ -124,6 +142,8 @@ class HandshakeSettings(object): 45 other.certificateTypes = self.certificateTypes 46 other.minVersion = self.minVersion 47 other.maxVersion = self.maxVersion 48 + other.tlsIntolerant = self.tlsIntolerant 49 + other.tlsIntoleranceType = self.tlsIntoleranceType 50 51 if not cipherfactory.tripleDESPresent: 52 other.cipherNames = [e for e in self.cipherNames if e != "3des"] 53 @@ -165,6 +185,10 @@ class HandshakeSettings(object): 54 if s not in CERTIFICATE_TYPES: 55 raise ValueError("Unknown certificate type: '%s'" % s) 56 57 + if other.tlsIntoleranceType not in TLS_INTOLERANCE_TYPES: 58 + raise ValueError( 59 + "Unknown TLS intolerance type: '%s'" % other.tlsIntoleranceType) 60 + 61 if other.minVersion > other.maxVersion: 62 raise ValueError("Versions set incorrectly") 63 64 diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py 65 index 044ad59..7c1572f 100644 66 --- a/third_party/tlslite/tlslite/tlsconnection.py 67 +++ b/third_party/tlslite/tlslite/tlsconnection.py 68 @@ -1065,7 +1065,7 @@ class TLSConnection(TLSRecordLayer): 69 reqCAs = None, reqCertTypes = None, 70 tacks=None, activationFlags=0, 71 nextProtos=None, anon=False, 72 - tlsIntolerant=None, signedCertTimestamps=None, 73 + signedCertTimestamps=None, 74 fallbackSCSV=False, ocspResponse=None): 75 """Perform a handshake in the role of server. 76 77 @@ -1139,11 +1139,6 @@ class TLSConnection(TLSRecordLayer): 78 clients through the Next-Protocol Negotiation Extension, 79 if they support it. 80 81 - @type tlsIntolerant: (int, int) or None 82 - @param tlsIntolerant: If tlsIntolerant is not None, the server will 83 - simulate TLS version intolerance by returning a fatal handshake_failure 84 - alert to all TLS versions tlsIntolerant or higher. 85 - 86 @type signedCertTimestamps: str 87 @param signedCertTimestamps: A SignedCertificateTimestampList (as a 88 binary 8-bit string) that will be sent as a TLS extension whenever 89 @@ -1175,7 +1170,7 @@ class TLSConnection(TLSRecordLayer): 90 certChain, privateKey, reqCert, sessionCache, settings, 91 checker, reqCAs, reqCertTypes, 92 tacks=tacks, activationFlags=activationFlags, 93 - nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, 94 + nextProtos=nextProtos, anon=anon, 95 signedCertTimestamps=signedCertTimestamps, 96 fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse): 97 pass 98 @@ -1187,7 +1182,6 @@ class TLSConnection(TLSRecordLayer): 99 reqCAs=None, reqCertTypes=None, 100 tacks=None, activationFlags=0, 101 nextProtos=None, anon=False, 102 - tlsIntolerant=None, 103 signedCertTimestamps=None, 104 fallbackSCSV=False, 105 ocspResponse=None 106 @@ -1210,7 +1204,6 @@ class TLSConnection(TLSRecordLayer): 107 reqCAs=reqCAs, reqCertTypes=reqCertTypes, 108 tacks=tacks, activationFlags=activationFlags, 109 nextProtos=nextProtos, anon=anon, 110 - tlsIntolerant=tlsIntolerant, 111 signedCertTimestamps=signedCertTimestamps, 112 fallbackSCSV=fallbackSCSV, 113 ocspResponse=ocspResponse) 114 @@ -1223,7 +1216,7 @@ class TLSConnection(TLSRecordLayer): 115 settings, reqCAs, reqCertTypes, 116 tacks, activationFlags, 117 nextProtos, anon, 118 - tlsIntolerant, signedCertTimestamps, fallbackSCSV, 119 + signedCertTimestamps, fallbackSCSV, 120 ocspResponse): 121 122 self._handshakeStart(client=False) 123 @@ -1261,7 +1254,7 @@ class TLSConnection(TLSRecordLayer): 124 # Handle ClientHello and resumption 125 for result in self._serverGetClientHello(settings, certChain,\ 126 verifierDB, sessionCache, 127 - anon, tlsIntolerant, fallbackSCSV): 128 + anon, fallbackSCSV): 129 if result in (0,1): yield result 130 elif result == None: 131 self._handshakeDone(resumed=True) 132 @@ -1376,7 +1369,7 @@ class TLSConnection(TLSRecordLayer): 133 134 135 def _serverGetClientHello(self, settings, certChain, verifierDB, 136 - sessionCache, anon, tlsIntolerant, fallbackSCSV): 137 + sessionCache, anon, fallbackSCSV): 138 #Initialize acceptable cipher suites 139 cipherSuites = [] 140 if verifierDB: 141 @@ -1413,11 +1406,21 @@ class TLSConnection(TLSRecordLayer): 142 yield result 143 144 #If simulating TLS intolerance, reject certain TLS versions. 145 - elif (tlsIntolerant is not None and 146 - clientHello.client_version >= tlsIntolerant): 147 - for result in self._sendError(\ 148 + elif (settings.tlsIntolerant is not None and 149 + clientHello.client_version >= settings.tlsIntolerant): 150 + if settings.tlsIntoleranceType == "alert": 151 + for result in self._sendError(\ 152 AlertDescription.handshake_failure): 153 - yield result 154 + yield result 155 + elif settings.tlsIntoleranceType == "close": 156 + self._abruptClose() 157 + raise TLSUnsupportedError("Simulating version intolerance") 158 + elif settings.tlsIntoleranceType == "reset": 159 + self._abruptClose(reset=True) 160 + raise TLSUnsupportedError("Simulating version intolerance") 161 + else: 162 + raise ValueError("Unknown intolerance type: '%s'" % 163 + settings.tlsIntoleranceType) 164 165 #If client's version is too high, propose my highest version 166 elif clientHello.client_version > settings.maxVersion: 167 diff --git a/third_party/tlslite/tlslite/tlsrecordlayer.py b/third_party/tlslite/tlslite/tlsrecordlayer.py 168 index 370dc9a..23c2a2f 100644 169 --- a/third_party/tlslite/tlslite/tlsrecordlayer.py 170 +++ b/third_party/tlslite/tlslite/tlsrecordlayer.py 171 @@ -19,6 +19,7 @@ from .constants import * 172 from .utils.cryptomath import getRandomBytes 173 174 import socket 175 +import struct 176 import errno 177 import traceback 178 179 @@ -523,6 +524,13 @@ class TLSRecordLayer(object): 180 self._shutdown(False) 181 raise TLSLocalAlert(alert, errorStr) 182 183 + def _abruptClose(self, reset=False): 184 + if reset: 185 + #Set an SO_LINGER timeout of 0 to send a TCP RST. 186 + self.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 187 + struct.pack('ii', 1, 0)) 188 + self._shutdown(False) 189 + 190 def _sendMsgs(self, msgs): 191 randomizeFirstBlock = True 192 for msg in msgs: 193