blob: cfd7f6f19c614ecd56a099930ef0ac8dfe8dacd6 [file] [log] [blame]
diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
index d132b78..ceaa903 100755
--- a/third_party/tlslite/tlslite/constants.py
+++ b/third_party/tlslite/tlslite/constants.py
@@ -30,6 +30,7 @@ class HandshakeType:
certificate_verify = 15
client_key_exchange = 16
finished = 20
+ certificate_status = 22
next_protocol = 67
encrypted_extensions = 203
@@ -40,8 +41,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 5a2cd6c..532d86b 100755
--- a/third_party/tlslite/tlslite/messages.py
+++ b/third_party/tlslite/tlslite/messages.py
@@ -114,6 +114,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,
@@ -187,6 +188,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
@@ -253,6 +267,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):
@@ -345,6 +360,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
@@ -402,6 +420,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):
HandshakeMsg.__init__(self, HandshakeType.certificate_request)
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
index bd92161..b9797d2 100755
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -967,7 +967,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
@@ -1051,6 +1051,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.
@@ -1064,7 +1074,7 @@ class TLSConnection(TLSRecordLayer):
tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant,
signedCertTimestamps=signedCertTimestamps,
- fallbackSCSV=fallbackSCSV):
+ fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse):
pass
@@ -1076,7 +1086,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.
@@ -1098,7 +1109,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
@@ -1108,7 +1120,8 @@ class TLSConnection(TLSRecordLayer):
settings, reqCAs,
tacks, activationFlags,
nextProtos, anon,
- tlsIntolerant, signedCertTimestamps, fallbackSCSV):
+ tlsIntolerant, signedCertTimestamps, fallbackSCSV,
+ ocspResponse):
self._handshakeStart(client=False)
@@ -1178,6 +1191,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
@@ -1194,7 +1209,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
@@ -1471,7 +1486,7 @@ class TLSConnection(TLSRecordLayer):
def _serverCertKeyExchange(self, clientHello, serverHello,
serverCertChain, privateKey,
reqCert, reqCAs, cipherSuite,
- settings):
+ settings, ocspResponse):
#Send ServerHello, Certificate[, CertificateRequest],
#ServerHelloDone
msgs = []
@@ -1481,6 +1496,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))