| diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py |
| index 69e6067..1a1ace9 100644 |
| --- a/third_party/tlslite/tlslite/constants.py |
| +++ b/third_party/tlslite/tlslite/constants.py |
| @@ -31,6 +31,7 @@ class HandshakeType: |
| certificate_verify = 15 |
| client_key_exchange = 16 |
| finished = 20 |
| + certificate_status = 22 |
| next_protocol = 67 |
| encrypted_extensions = 203 |
| |
| @@ -41,8 +42,12 @@ class ContentType: |
| application_data = 23 |
| all = (20,21,22,23) |
| |
| +class CertificateStatusType: |
| + ocsp = 1 |
| + |
| class ExtensionType: # RFC 6066 / 4366 |
| server_name = 0 # RFC 6066 / 4366 |
| + status_request = 5 # RFC 6066 / 4366 |
| srp = 12 # RFC 5054 |
| cert_type = 9 # RFC 6091 |
| signed_cert_timestamps = 18 # RFC 6962 |
| diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py |
| index 876b033..9a8e5f6 100644 |
| --- a/third_party/tlslite/tlslite/messages.py |
| +++ b/third_party/tlslite/tlslite/messages.py |
| @@ -115,6 +115,7 @@ class ClientHello(HandshakeMsg): |
| self.server_name = bytearray(0) |
| 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, srpUsername=None, |
| @@ -188,6 +189,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) |
| index2 = p.index |
| @@ -254,6 +268,7 @@ class ServerHello(HandshakeMsg): |
| self.next_protos = None |
| self.channel_id = False |
| self.signed_cert_timestamps = None |
| + self.status_request = False |
| |
| def create(self, version, random, session_id, cipher_suite, |
| certificate_type, tackExt, next_protos_advertised): |
| @@ -346,6 +361,9 @@ class ServerHello(HandshakeMsg): |
| if self.signed_cert_timestamps: |
| w2.add(ExtensionType.signed_cert_timestamps, 2) |
| w2.addVarSeq(bytearray(self.signed_cert_timestamps), 1, 2) |
| + if self.status_request: |
| + w2.add(ExtensionType.status_request, 2) |
| + w2.add(0, 2) |
| if len(w2.bytes): |
| w.add(len(w2.bytes), 2) |
| w.bytes += w2.bytes |
| @@ -403,6 +421,37 @@ class Certificate(HandshakeMsg): |
| raise AssertionError() |
| return self.postWrite(w) |
| |
| +class CertificateStatus(HandshakeMsg): |
| + def __init__(self): |
| + HandshakeMsg.__init__(self, HandshakeType.certificate_status) |
| + |
| + 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 |
| + p.stopLengthCheck() |
| + return self |
| + |
| + def write(self): |
| + w = Writer() |
| + w.add(CertificateStatusType.ocsp, 1) |
| + w.addVarSeq(bytearray(self.ocsp_response), 1, 3) |
| + return self.postWrite(w) |
| + |
| class CertificateRequest(HandshakeMsg): |
| def __init__(self, version): |
| HandshakeMsg.__init__(self, HandshakeType.certificate_request) |
| diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py |
| index 0563fb5f..5d508ed 100644 |
| --- a/third_party/tlslite/tlslite/tlsconnection.py |
| +++ b/third_party/tlslite/tlslite/tlsconnection.py |
| @@ -970,7 +970,7 @@ class TLSConnection(TLSRecordLayer): |
| tacks=None, activationFlags=0, |
| nextProtos=None, anon=False, |
| tlsIntolerant=None, signedCertTimestamps=None, |
| - fallbackSCSV=False): |
| + fallbackSCSV=False, ocspResponse=None): |
| """Perform a handshake in the role of server. |
| |
| This function performs an SSL or TLS handshake. Depending on |
| @@ -1054,6 +1054,16 @@ class TLSConnection(TLSRecordLayer): |
| TLS_FALLBACK_SCSV and thus reject connections using less than the |
| server's maximum TLS version that include this cipher suite. |
| |
| + @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. |
| @@ -1067,7 +1077,7 @@ class TLSConnection(TLSRecordLayer): |
| tacks=tacks, activationFlags=activationFlags, |
| nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, |
| signedCertTimestamps=signedCertTimestamps, |
| - fallbackSCSV=fallbackSCSV): |
| + fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse): |
| pass |
| |
| |
| @@ -1079,7 +1089,8 @@ class TLSConnection(TLSRecordLayer): |
| nextProtos=None, anon=False, |
| tlsIntolerant=None, |
| signedCertTimestamps=None, |
| - fallbackSCSV=False |
| + fallbackSCSV=False, |
| + ocspResponse=None |
| ): |
| """Start a server handshake operation on the TLS connection. |
| |
| @@ -1101,7 +1112,8 @@ class TLSConnection(TLSRecordLayer): |
| nextProtos=nextProtos, anon=anon, |
| tlsIntolerant=tlsIntolerant, |
| signedCertTimestamps=signedCertTimestamps, |
| - fallbackSCSV=fallbackSCSV) |
| + fallbackSCSV=fallbackSCSV, |
| + ocspResponse=ocspResponse) |
| for result in self._handshakeWrapperAsync(handshaker, checker): |
| yield result |
| |
| @@ -1111,7 +1123,8 @@ class TLSConnection(TLSRecordLayer): |
| settings, reqCAs, |
| tacks, activationFlags, |
| nextProtos, anon, |
| - tlsIntolerant, signedCertTimestamps, fallbackSCSV): |
| + tlsIntolerant, signedCertTimestamps, fallbackSCSV, |
| + ocspResponse): |
| |
| self._handshakeStart(client=False) |
| |
| @@ -1181,6 +1194,8 @@ class TLSConnection(TLSRecordLayer): |
| serverHello.channel_id = clientHello.channel_id |
| if clientHello.support_signed_cert_timestamps: |
| serverHello.signed_cert_timestamps = signedCertTimestamps |
| + if clientHello.status_request: |
| + serverHello.status_request = ocspResponse |
| |
| # Perform the SRP key exchange |
| clientCertChain = None |
| @@ -1197,7 +1212,7 @@ class TLSConnection(TLSRecordLayer): |
| for result in self._serverCertKeyExchange(clientHello, serverHello, |
| certChain, privateKey, |
| reqCert, reqCAs, cipherSuite, |
| - settings): |
| + settings, ocspResponse): |
| if result in (0,1): yield result |
| else: break |
| (premasterSecret, clientCertChain) = result |
| @@ -1475,7 +1490,7 @@ class TLSConnection(TLSRecordLayer): |
| def _serverCertKeyExchange(self, clientHello, serverHello, |
| serverCertChain, privateKey, |
| reqCert, reqCAs, cipherSuite, |
| - settings): |
| + settings, ocspResponse): |
| #Send ServerHello, Certificate[, CertificateRequest], |
| #ServerHelloDone |
| msgs = [] |
| @@ -1485,6 +1500,8 @@ class TLSConnection(TLSRecordLayer): |
| |
| msgs.append(serverHello) |
| msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) |
| + if serverHello.status_request: |
| + msgs.append(CertificateStatus().create(ocspResponse)) |
| if reqCert and reqCAs: |
| msgs.append(CertificateRequest().create(\ |
| [ClientCertificateType.rsa_sign], reqCAs)) |