summaryrefslogtreecommitdiffstats
path: root/third_party/tlslite
diff options
context:
space:
mode:
authorekasper@google.com <ekasper@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-17 00:25:51 +0000
committerekasper@google.com <ekasper@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-17 00:25:51 +0000
commitc9feb5fdfc7df5f0e30710b58b95a887ac27125d (patch)
tree807e19c1ccd5a312086a0fc5e67746d0c10947ad /third_party/tlslite
parenta399a758b43c578203f26d592fdca2e47b9c6165 (diff)
downloadchromium_src-c9feb5fdfc7df5f0e30710b58b95a887ac27125d.zip
chromium_src-c9feb5fdfc7df5f0e30710b58b95a887ac27125d.tar.gz
chromium_src-c9feb5fdfc7df5f0e30710b58b95a887ac27125d.tar.bz2
Extract Certificate Transparency SCTs from stapled OCSP responses
BUG=309578 Review URL: https://codereview.chromium.org/102613006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@241083 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tlslite')
-rw-r--r--third_party/tlslite/README.chromium1
-rw-r--r--third_party/tlslite/patches/status_request.patch208
-rw-r--r--third_party/tlslite/tlslite/TLSConnection.py29
-rw-r--r--third_party/tlslite/tlslite/constants.py5
-rw-r--r--third_party/tlslite/tlslite/messages.py53
5 files changed, 289 insertions, 7 deletions
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index ec2fad8..ed0d793 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -38,3 +38,4 @@ Local Modifications:
Certificate Timestamps over a TLS extension.
- patches/fallback_scsv.patch: add support for TLS_FALLBACK_SCSV. See
https://tools.ietf.org/html/draft-bmoeller-tls-downgrade-scsv-01
+- patches/status_request.patch: add support for sending stapled OCSP responses.
diff --git a/third_party/tlslite/patches/status_request.patch b/third_party/tlslite/patches/status_request.patch
new file mode 100644
index 0000000..15f01d4
--- /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
diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py
index c5722d6..0c34536 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
@@ -1027,6 +1027,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.
@@ -1037,7 +1047,7 @@ class TLSConnection(TLSRecordLayer):
for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
checker, reqCAs, tlsIntolerant, signedCertTimestamps,
- fallbackSCSV):
+ fallbackSCSV, ocspResponse):
pass
@@ -1046,7 +1056,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
@@ -1066,7 +1076,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
@@ -1075,7 +1086,7 @@ class TLSConnection(TLSRecordLayer):
certChain, privateKey, reqCert,
sessionCache, settings, reqCAs,
tlsIntolerant, signedCertTimestamps,
- fallbackSCSV):
+ fallbackSCSV, ocspResponse):
self._handshakeStart(client=False)
@@ -1452,10 +1463,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