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 |