blob: b6de396f9ecafb8dabf5004de805f6d55445b69b [file] [log] [blame]
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))