| diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py |
| index 8720de6..69e6067 100644 |
| --- a/third_party/tlslite/tlslite/constants.py |
| +++ b/third_party/tlslite/tlslite/constants.py |
| @@ -107,6 +107,7 @@ class AlertDescription: |
| protocol_version = 70 |
| insufficient_security = 71 |
| internal_error = 80 |
| + inappropriate_fallback = 86 |
| user_canceled = 90 |
| no_renegotiation = 100 |
| unknown_psk_identity = 115 |
| @@ -118,6 +119,9 @@ class CipherSuite: |
| # We actually don't do any renegotiation, but this |
| # prevents renegotiation attacks |
| TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF |
| + |
| + # draft-ietf-tls-downgrade-scsv-03 |
| + TLS_FALLBACK_SCSV = 0x5600 |
| |
| TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A |
| TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D |
| diff --git a/third_party/tlslite/tlslite/errors.py b/third_party/tlslite/tlslite/errors.py |
| index 22c298c..001ef33 100644 |
| --- a/third_party/tlslite/tlslite/errors.py |
| +++ b/third_party/tlslite/tlslite/errors.py |
| @@ -63,6 +63,7 @@ class TLSAlert(TLSError): |
| AlertDescription.protocol_version: "protocol_version",\ |
| AlertDescription.insufficient_security: "insufficient_security",\ |
| AlertDescription.internal_error: "internal_error",\ |
| + AlertDescription.inappropriate_fallback: "inappropriate_fallback",\ |
| AlertDescription.user_canceled: "user_canceled",\ |
| AlertDescription.no_renegotiation: "no_renegotiation",\ |
| AlertDescription.unknown_psk_identity: "unknown_psk_identity"} |
| diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py |
| index 4dedc5f..0563fb5f 100644 |
| --- a/third_party/tlslite/tlslite/tlsconnection.py |
| +++ b/third_party/tlslite/tlslite/tlsconnection.py |
| @@ -969,7 +969,8 @@ class TLSConnection(TLSRecordLayer): |
| reqCAs = None, |
| tacks=None, activationFlags=0, |
| nextProtos=None, anon=False, |
| - tlsIntolerant=None, signedCertTimestamps=None): |
| + tlsIntolerant=None, signedCertTimestamps=None, |
| + fallbackSCSV=False): |
| """Perform a handshake in the role of server. |
| |
| This function performs an SSL or TLS handshake. Depending on |
| @@ -1048,6 +1049,11 @@ class TLSConnection(TLSRecordLayer): |
| binary 8-bit string) that will be sent as a TLS extension whenever |
| the client announces support for the extension. |
| |
| + @type fallbackSCSV: bool |
| + @param fallbackSCSV: if true, the server will implement |
| + TLS_FALLBACK_SCSV and thus reject connections using less than the |
| + server's maximum TLS version that include this cipher suite. |
| + |
| @raise socket.error: If a socket error occurs. |
| @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed |
| without a preceding alert. |
| @@ -1060,7 +1066,8 @@ class TLSConnection(TLSRecordLayer): |
| checker, reqCAs, |
| tacks=tacks, activationFlags=activationFlags, |
| nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, |
| - signedCertTimestamps=signedCertTimestamps): |
| + signedCertTimestamps=signedCertTimestamps, |
| + fallbackSCSV=fallbackSCSV): |
| pass |
| |
| |
| @@ -1071,7 +1078,8 @@ class TLSConnection(TLSRecordLayer): |
| tacks=None, activationFlags=0, |
| nextProtos=None, anon=False, |
| tlsIntolerant=None, |
| - signedCertTimestamps=None |
| + signedCertTimestamps=None, |
| + fallbackSCSV=False |
| ): |
| """Start a server handshake operation on the TLS connection. |
| |
| @@ -1092,7 +1100,8 @@ class TLSConnection(TLSRecordLayer): |
| tacks=tacks, activationFlags=activationFlags, |
| nextProtos=nextProtos, anon=anon, |
| tlsIntolerant=tlsIntolerant, |
| - signedCertTimestamps=signedCertTimestamps) |
| + signedCertTimestamps=signedCertTimestamps, |
| + fallbackSCSV=fallbackSCSV) |
| for result in self._handshakeWrapperAsync(handshaker, checker): |
| yield result |
| |
| @@ -1102,7 +1111,7 @@ class TLSConnection(TLSRecordLayer): |
| settings, reqCAs, |
| tacks, activationFlags, |
| nextProtos, anon, |
| - tlsIntolerant, signedCertTimestamps): |
| + tlsIntolerant, signedCertTimestamps, fallbackSCSV): |
| |
| self._handshakeStart(client=False) |
| |
| @@ -1137,7 +1146,7 @@ class TLSConnection(TLSRecordLayer): |
| # Handle ClientHello and resumption |
| for result in self._serverGetClientHello(settings, certChain,\ |
| verifierDB, sessionCache, |
| - anon, tlsIntolerant): |
| + anon, tlsIntolerant, fallbackSCSV): |
| if result in (0,1): yield result |
| elif result == None: |
| self._handshakeDone(resumed=True) |
| @@ -1237,7 +1246,7 @@ class TLSConnection(TLSRecordLayer): |
| |
| |
| def _serverGetClientHello(self, settings, certChain, verifierDB, |
| - sessionCache, anon, tlsIntolerant): |
| + sessionCache, anon, tlsIntolerant, fallbackSCSV): |
| #Initialize acceptable cipher suites |
| cipherSuites = [] |
| if verifierDB: |
| @@ -1283,6 +1292,14 @@ class TLSConnection(TLSRecordLayer): |
| elif clientHello.client_version > settings.maxVersion: |
| self.version = settings.maxVersion |
| |
| + #Detect if the client performed an inappropriate fallback. |
| + elif fallbackSCSV and clientHello.client_version < settings.maxVersion: |
| + self.version = clientHello.client_version |
| + if CipherSuite.TLS_FALLBACK_SCSV in clientHello.cipher_suites: |
| + for result in self._sendError(\ |
| + AlertDescription.inappropriate_fallback): |
| + yield result |
| + |
| else: |
| #Set the version to the client's version |
| self.version = clientHello.client_version |