blob: 2aee3c6f8d593b78a030586f4dd2babfc4a73fce [file] [log] [blame]
diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py
index 7998e2e..2e9e06d 100644
--- a/third_party/tlslite/tlslite/handshakesettings.py
+++ b/third_party/tlslite/tlslite/handshakesettings.py
@@ -19,6 +19,7 @@ ALL_MAC_NAMES = ["sha", "sha256", "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
@@ -91,6 +92,21 @@ class HandshakeSettings(object):
version, a protocol_version alert will be signalled. The default is (3,3).
(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: The TLS ClientHello version which the server
+ simulates intolerance of.
+
+ If tlsIntolerant is not None, the server will simulate TLS version
+ intolerance by aborting the handshake in response to all TLS versions
+ tlsIntolerant or higher.
+
+ @type tlsIntoleranceType: str
+ @ivar tlsIntoleranceType: How the server should react when simulating TLS
+ intolerance.
+
+ The allowed values are "alert" (return a fatal handshake_failure alert),
+ "close" (abruptly close the connection), and "reset" (send a TCP reset).
@type useExperimentalTackExtension: bool
@ivar useExperimentalTackExtension: Whether to enabled TACK support.
@@ -108,6 +124,8 @@ class HandshakeSettings(object):
self.certificateTypes = CERTIFICATE_TYPES
self.minVersion = (3,1)
self.maxVersion = (3,3)
+ self.tlsIntolerant = None
+ self.tlsIntoleranceType = 'alert'
self.useExperimentalTackExtension = False
# Validates the min/max fields, and certificateTypes
@@ -123,6 +141,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"]
@@ -164,6 +184,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 f8547d5..4f3ba1c 100644
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -1073,7 +1073,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.
@@ -1147,11 +1147,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
@@ -1183,7 +1178,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
@@ -1195,7 +1190,6 @@ class TLSConnection(TLSRecordLayer):
reqCAs=None, reqCertTypes=None,
tacks=None, activationFlags=0,
nextProtos=None, anon=False,
- tlsIntolerant=None,
signedCertTimestamps=None,
fallbackSCSV=False,
ocspResponse=None
@@ -1218,7 +1212,6 @@ class TLSConnection(TLSRecordLayer):
reqCAs=reqCAs, reqCertTypes=reqCertTypes,
tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon,
- tlsIntolerant=tlsIntolerant,
signedCertTimestamps=signedCertTimestamps,
fallbackSCSV=fallbackSCSV,
ocspResponse=ocspResponse)
@@ -1231,7 +1224,7 @@ class TLSConnection(TLSRecordLayer):
settings, reqCAs, reqCertTypes,
tacks, activationFlags,
nextProtos, anon,
- tlsIntolerant, signedCertTimestamps, fallbackSCSV,
+ signedCertTimestamps, fallbackSCSV,
ocspResponse):
self._handshakeStart(client=False)
@@ -1269,7 +1262,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)
@@ -1384,7 +1377,7 @@ class TLSConnection(TLSRecordLayer):
def _serverGetClientHello(self, settings, certChain, verifierDB,
- sessionCache, anon, tlsIntolerant, fallbackSCSV):
+ sessionCache, anon, fallbackSCSV):
#Initialize acceptable cipher suites
cipherSuites = []
if verifierDB:
@@ -1421,11 +1414,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 3584726..eda11e6 100644
--- a/third_party/tlslite/tlslite/tlsrecordlayer.py
+++ b/third_party/tlslite/tlslite/tlsrecordlayer.py
@@ -20,6 +20,7 @@ from .constants import *
from .utils.cryptomath import getRandomBytes
import socket
+import struct
import errno
import traceback
@@ -527,6 +528,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: