| Index: third_party/tlslite/patches/status_request.patch
|
| diff --git a/third_party/tlslite/patches/status_request.patch b/third_party/tlslite/patches/status_request.patch
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..15f01d42809edf3fea8347da8d1f225d08798077
|
| --- /dev/null
|
| +++ b/third_party/tlslite/patches/status_request.patch
|
| @@ -0,0 +1,208 @@
|
| +diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py
|
| +index e6ce187..94ee5eb 100644
|
| +--- a/third_party/tlslite/tlslite/TLSConnection.py
|
| ++++ b/third_party/tlslite/tlslite/TLSConnection.py
|
| +@@ -937,8 +937,8 @@ class TLSConnection(TLSRecordLayer):
|
| + certChain=None, privateKey=None, reqCert=False,
|
| + sessionCache=None, settings=None, checker=None,
|
| + reqCAs=None, tlsIntolerant=0,
|
| +- signedCertTimestamps=None,
|
| +- fallbackSCSV=False):
|
| ++ signedCertTimestamps=None, fallbackSCSV=False,
|
| ++ ocspResponse=None):
|
| + """Perform a handshake in the role of server.
|
| +
|
| + This function performs an SSL or TLS handshake. Depending on
|
| +@@ -1014,6 +1014,16 @@ class TLSConnection(TLSRecordLayer):
|
| + binary 8-bit string) that will be sent as a TLS extension whenever
|
| + the client announces support for the extension.
|
| +
|
| ++ @type ocspResponse: str
|
| ++ @param ocspResponse: An OCSP response (as a binary 8-bit string) that
|
| ++ will be sent stapled in the handshake whenever the client announces
|
| ++ support for the status_request extension.
|
| ++ Note that the response is sent independent of the ClientHello
|
| ++ status_request extension contents, and is thus only meant for testing
|
| ++ environments. Real OCSP stapling is more complicated as it requires
|
| ++ choosing a suitable response based on the ClientHello status_request
|
| ++ extension contents.
|
| ++
|
| + @raise socket.error: If a socket error occurs.
|
| + @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
|
| + without a preceding alert.
|
| +@@ -1024,7 +1034,7 @@ class TLSConnection(TLSRecordLayer):
|
| + for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
|
| + certChain, privateKey, reqCert, sessionCache, settings,
|
| + checker, reqCAs, tlsIntolerant, signedCertTimestamps,
|
| +- fallbackSCSV):
|
| ++ fallbackSCSV, ocspResponse):
|
| + pass
|
| +
|
| +
|
| +@@ -1033,7 +1043,7 @@ class TLSConnection(TLSRecordLayer):
|
| + sessionCache=None, settings=None, checker=None,
|
| + reqCAs=None, tlsIntolerant=0,
|
| + signedCertTimestamps=None,
|
| +- fallbackSCSV=False):
|
| ++ fallbackSCSV=False, ocspResponse=None):
|
| + """Start a server handshake operation on the TLS connection.
|
| +
|
| + This function returns a generator which behaves similarly to
|
| +@@ -1053,7 +1063,8 @@ class TLSConnection(TLSRecordLayer):
|
| + reqCAs=reqCAs,
|
| + tlsIntolerant=tlsIntolerant,
|
| + signedCertTimestamps=signedCertTimestamps,
|
| +- fallbackSCSV=fallbackSCSV)
|
| ++ fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse)
|
| ++
|
| + for result in self._handshakeWrapperAsync(handshaker, checker):
|
| + yield result
|
| +
|
| +@@ -1062,7 +1073,7 @@ class TLSConnection(TLSRecordLayer):
|
| + certChain, privateKey, reqCert,
|
| + sessionCache, settings, reqCAs,
|
| + tlsIntolerant, signedCertTimestamps,
|
| +- fallbackSCSV):
|
| ++ fallbackSCSV, ocspResponse):
|
| +
|
| + self._handshakeStart(client=False)
|
| +
|
| +@@ -1439,10 +1450,14 @@ class TLSConnection(TLSRecordLayer):
|
| + sessionID, cipherSuite, certificateType)
|
| + serverHello.channel_id = clientHello.channel_id
|
| + if clientHello.support_signed_cert_timestamps:
|
| +- serverHello.signed_cert_timestamps = signedCertTimestamps
|
| ++ serverHello.signed_cert_timestamps = signedCertTimestamps
|
| ++ serverHello.status_request = (clientHello.status_request and
|
| ++ ocspResponse)
|
| + doingChannelID = clientHello.channel_id
|
| + msgs.append(serverHello)
|
| + msgs.append(Certificate(certificateType).create(serverCertChain))
|
| ++ if serverHello.status_request:
|
| ++ msgs.append(CertificateStatus().create(ocspResponse))
|
| + if reqCert and reqCAs:
|
| + msgs.append(CertificateRequest().create([], reqCAs))
|
| + elif reqCert:
|
| +diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
|
| +index 23e3dcb..d027ef5 100644
|
| +--- a/third_party/tlslite/tlslite/constants.py
|
| ++++ b/third_party/tlslite/tlslite/constants.py
|
| +@@ -22,6 +22,7 @@ class HandshakeType:
|
| + certificate_verify = 15
|
| + client_key_exchange = 16
|
| + finished = 20
|
| ++ certificate_status = 22
|
| + encrypted_extensions = 203
|
| +
|
| + class ContentType:
|
| +@@ -31,7 +32,11 @@ class ContentType:
|
| + application_data = 23
|
| + all = (20,21,22,23)
|
| +
|
| ++class CertificateStatusType:
|
| ++ ocsp = 1
|
| ++
|
| + class ExtensionType:
|
| ++ status_request = 5 # OCSP stapling
|
| + signed_cert_timestamps = 18 # signed_certificate_timestamp in RFC 6962
|
| + channel_id = 30031
|
| +
|
| +diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
|
| +index 296f422..497ef60 100644
|
| +--- a/third_party/tlslite/tlslite/messages.py
|
| ++++ b/third_party/tlslite/tlslite/messages.py
|
| +@@ -132,6 +132,7 @@ class ClientHello(HandshakeMsg):
|
| + self.srp_username = None # a string
|
| + self.channel_id = False
|
| + self.support_signed_cert_timestamps = False
|
| ++ self.status_request = False
|
| +
|
| + def create(self, version, random, session_id, cipher_suites,
|
| + certificate_types=None, srp_username=None):
|
| +@@ -182,6 +183,19 @@ class ClientHello(HandshakeMsg):
|
| + if extLength:
|
| + raise SyntaxError()
|
| + self.support_signed_cert_timestamps = True
|
| ++ elif extType == ExtensionType.status_request:
|
| ++ # Extension contents are currently ignored.
|
| ++ # According to RFC 6066, this is not strictly forbidden
|
| ++ # (although it is suboptimal):
|
| ++ # Servers that receive a client hello containing the
|
| ++ # "status_request" extension MAY return a suitable
|
| ++ # certificate status response to the client along with
|
| ++ # their certificate. If OCSP is requested, they
|
| ++ # SHOULD use the information contained in the extension
|
| ++ # when selecting an OCSP responder and SHOULD include
|
| ++ # request_extensions in the OCSP request.
|
| ++ p.getFixBytes(extLength)
|
| ++ self.status_request = True
|
| + else:
|
| + p.getFixBytes(extLength)
|
| + soFar += 4 + extLength
|
| +@@ -230,6 +244,7 @@ class ServerHello(HandshakeMsg):
|
| + self.compression_method = 0
|
| + self.channel_id = False
|
| + self.signed_cert_timestamps = None
|
| ++ self.status_request = False
|
| +
|
| + def create(self, version, random, session_id, cipher_suite,
|
| + certificate_type):
|
| +@@ -282,6 +297,9 @@ class ServerHello(HandshakeMsg):
|
| + if self.signed_cert_timestamps:
|
| + extLength += 4 + len(self.signed_cert_timestamps)
|
| +
|
| ++ if self.status_request:
|
| ++ extLength += 4
|
| ++
|
| + if extLength != 0:
|
| + w.add(extLength, 2)
|
| +
|
| +@@ -299,6 +317,10 @@ class ServerHello(HandshakeMsg):
|
| + w.add(ExtensionType.signed_cert_timestamps, 2)
|
| + w.addVarSeq(stringToBytes(self.signed_cert_timestamps), 1, 2)
|
| +
|
| ++ if self.status_request:
|
| ++ w.add(ExtensionType.status_request, 2)
|
| ++ w.add(0, 2)
|
| ++
|
| + return HandshakeMsg.postWrite(self, w, trial)
|
| +
|
| + class Certificate(HandshakeMsg):
|
| +@@ -367,6 +389,37 @@ class Certificate(HandshakeMsg):
|
| + raise AssertionError()
|
| + return HandshakeMsg.postWrite(self, w, trial)
|
| +
|
| ++class CertificateStatus(HandshakeMsg):
|
| ++ def __init__(self):
|
| ++ self.contentType = ContentType.handshake
|
| ++
|
| ++ def create(self, ocsp_response):
|
| ++ self.ocsp_response = ocsp_response
|
| ++ return self
|
| ++
|
| ++ # Defined for the sake of completeness, even though we currently only
|
| ++ # support sending the status message (server-side), not requesting
|
| ++ # or receiving it (client-side).
|
| ++ def parse(self, p):
|
| ++ p.startLengthCheck(3)
|
| ++ status_type = p.get(1)
|
| ++ # Only one type is specified, so hardwire it.
|
| ++ if status_type != CertificateStatusType.ocsp:
|
| ++ raise SyntaxError()
|
| ++ ocsp_response = p.getVarBytes(3)
|
| ++ if not ocsp_response:
|
| ++ # Can't be empty
|
| ++ raise SyntaxError()
|
| ++ self.ocsp_response = ocsp_response
|
| ++ return self
|
| ++
|
| ++ def write(self, trial=False):
|
| ++ w = HandshakeMsg.preWrite(self, HandshakeType.certificate_status,
|
| ++ trial)
|
| ++ w.add(CertificateStatusType.ocsp, 1)
|
| ++ w.addVarSeq(stringToBytes(self.ocsp_response), 1, 3)
|
| ++ return HandshakeMsg.postWrite(self, w, trial)
|
| ++
|
| + class CertificateRequest(HandshakeMsg):
|
| + def __init__(self):
|
| + self.contentType = ContentType.handshake
|
|
|