| diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py |
| index 6429c66..8720de6 100644 |
| --- a/third_party/tlslite/tlslite/constants.py |
| +++ b/third_party/tlslite/tlslite/constants.py |
| @@ -45,6 +45,7 @@ class ExtensionType: # RFC 6066 / 4366 |
| server_name = 0 # RFC 6066 / 4366 |
| srp = 12 # RFC 5054 |
| cert_type = 9 # RFC 6091 |
| + signed_cert_timestamps = 18 # RFC 6962 |
| tack = 0xF300 |
| supports_npn = 13172 |
| channel_id = 30032 |
| diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py |
| index 4fa9d96..876b033 100644 |
| --- a/third_party/tlslite/tlslite/messages.py |
| +++ b/third_party/tlslite/tlslite/messages.py |
| @@ -114,6 +114,7 @@ class ClientHello(HandshakeMsg): |
| self.supports_npn = False |
| self.server_name = bytearray(0) |
| self.channel_id = False |
| + self.support_signed_cert_timestamps = False |
| |
| def create(self, version, random, session_id, cipher_suites, |
| certificate_types=None, srpUsername=None, |
| @@ -183,6 +184,10 @@ class ClientHello(HandshakeMsg): |
| break |
| elif extType == ExtensionType.channel_id: |
| self.channel_id = True |
| + elif extType == ExtensionType.signed_cert_timestamps: |
| + if extLength: |
| + raise SyntaxError() |
| + self.support_signed_cert_timestamps = True |
| else: |
| _ = p.getFixBytes(extLength) |
| index2 = p.index |
| @@ -248,6 +253,7 @@ class ServerHello(HandshakeMsg): |
| self.next_protos_advertised = None |
| self.next_protos = None |
| self.channel_id = False |
| + self.signed_cert_timestamps = None |
| |
| def create(self, version, random, session_id, cipher_suite, |
| certificate_type, tackExt, next_protos_advertised): |
| @@ -337,6 +343,9 @@ class ServerHello(HandshakeMsg): |
| if self.channel_id: |
| w2.add(ExtensionType.channel_id, 2) |
| w2.add(0, 2) |
| + if self.signed_cert_timestamps: |
| + w2.add(ExtensionType.signed_cert_timestamps, 2) |
| + w2.addVarSeq(bytearray(self.signed_cert_timestamps), 1, 2) |
| if len(w2.bytes): |
| w.add(len(w2.bytes), 2) |
| w.bytes += w2.bytes |
| diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py |
| index b0400f8..4dedc5f 100644 |
| --- a/third_party/tlslite/tlslite/tlsconnection.py |
| +++ b/third_party/tlslite/tlslite/tlsconnection.py |
| @@ -969,7 +969,7 @@ class TLSConnection(TLSRecordLayer): |
| reqCAs = None, |
| tacks=None, activationFlags=0, |
| nextProtos=None, anon=False, |
| - tlsIntolerant=None): |
| + tlsIntolerant=None, signedCertTimestamps=None): |
| """Perform a handshake in the role of server. |
| |
| This function performs an SSL or TLS handshake. Depending on |
| @@ -1043,6 +1043,11 @@ class TLSConnection(TLSRecordLayer): |
| 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 |
| + the client announces support for the extension. |
| + |
| @raise socket.error: If a socket error occurs. |
| @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed |
| without a preceding alert. |
| @@ -1054,7 +1059,8 @@ class TLSConnection(TLSRecordLayer): |
| certChain, privateKey, reqCert, sessionCache, settings, |
| checker, reqCAs, |
| tacks=tacks, activationFlags=activationFlags, |
| - nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant): |
| + nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, |
| + signedCertTimestamps=signedCertTimestamps): |
| pass |
| |
| |
| @@ -1064,7 +1070,8 @@ class TLSConnection(TLSRecordLayer): |
| reqCAs=None, |
| tacks=None, activationFlags=0, |
| nextProtos=None, anon=False, |
| - tlsIntolerant=None |
| + tlsIntolerant=None, |
| + signedCertTimestamps=None |
| ): |
| """Start a server handshake operation on the TLS connection. |
| |
| @@ -1084,7 +1091,8 @@ class TLSConnection(TLSRecordLayer): |
| reqCAs=reqCAs, |
| tacks=tacks, activationFlags=activationFlags, |
| nextProtos=nextProtos, anon=anon, |
| - tlsIntolerant=tlsIntolerant) |
| + tlsIntolerant=tlsIntolerant, |
| + signedCertTimestamps=signedCertTimestamps) |
| for result in self._handshakeWrapperAsync(handshaker, checker): |
| yield result |
| |
| @@ -1094,7 +1102,7 @@ class TLSConnection(TLSRecordLayer): |
| settings, reqCAs, |
| tacks, activationFlags, |
| nextProtos, anon, |
| - tlsIntolerant): |
| + tlsIntolerant, signedCertTimestamps): |
| |
| self._handshakeStart(client=False) |
| |
| @@ -1115,6 +1123,9 @@ class TLSConnection(TLSRecordLayer): |
| raise ValueError("tackpy is not loaded") |
| if not settings or not settings.useExperimentalTackExtension: |
| raise ValueError("useExperimentalTackExtension not enabled") |
| + if signedCertTimestamps and not certChain: |
| + raise ValueError("Caller passed signedCertTimestamps but no " |
| + "certChain") |
| |
| if not settings: |
| settings = HandshakeSettings() |
| @@ -1159,6 +1170,8 @@ class TLSConnection(TLSRecordLayer): |
| cipherSuite, CertificateType.x509, tackExt, |
| nextProtos) |
| serverHello.channel_id = clientHello.channel_id |
| + if clientHello.support_signed_cert_timestamps: |
| + serverHello.signed_cert_timestamps = signedCertTimestamps |
| |
| # Perform the SRP key exchange |
| clientCertChain = None |