Update Token Binding code to the latest drafts
draft-ietf-tokbind-protocol-10:
- The TokenBinding.signature now closes over the token binding type.
- Public key serialization is length prefixed to support parsing unknown key types.
draft-ietf-tokbind-negotiation-05:
- Require Renegotiation Indication
draft-ietf-tokbind-https-06:
- Sec-Token-Binding header base64 shouldn't include pad characters.
- Include-Referred-Token-Binding-ID header's value is case insensitive.
This also updates the tls and quic code to indicate support for draft version 10.
BUG=467312
Review-Url: https://codereview.chromium.org/2337253004
Cr-Original-Commit-Position: refs/heads/master@{#419981}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 78e6d2b3325b16d8b637b9457a775557e1ec7e0e
diff --git a/README.chromium b/README.chromium
index aa3a901..c2d1f27 100644
--- a/README.chromium
+++ b/README.chromium
@@ -53,3 +53,6 @@
- patches/save_randoms.patch: Save client and server randoms when resuming
sessions.
- patches/alpn.path: Implement Application-Layer Protocol Negotiation Extension.
+- patches/token_binding_version.patch: Update Token Binding version number.
+- patches/renegotiation_indication.patch: Implement the renegotiation
+ indication extension (RFC 5746) without supporting renegotiation.
diff --git a/patches/renegotiation_indication.patch b/patches/renegotiation_indication.patch
new file mode 100644
index 0000000..69a1d7b
--- /dev/null
+++ b/patches/renegotiation_indication.patch
@@ -0,0 +1,86 @@
+diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
+index e9743e4..82e8c07 100644
+--- a/third_party/tlslite/tlslite/constants.py
++++ b/third_party/tlslite/tlslite/constants.py
+@@ -61,6 +61,7 @@ class ExtensionType: # RFC 6066 / 4366
+ tack = 0xF300
+ supports_npn = 13172
+ channel_id = 30032
++ renegotiation_info = 0xFF01 # RFC 5746
+
+ class HashAlgorithm:
+ none = 0
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index 1ce9320..ac7e563 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -140,6 +140,7 @@ class ClientHello(HandshakeMsg):
+ self.tb_client_params = []
+ self.support_signed_cert_timestamps = False
+ self.status_request = False
++ self.ri = False
+
+ def create(self, version, random, session_id, cipher_suites,
+ certificate_types=None, srpUsername=None,
+@@ -244,12 +245,20 @@ class ClientHello(HandshakeMsg):
+ # request_extensions in the OCSP request.
+ p.getFixBytes(extLength)
+ self.status_request = True
++ elif extType == ExtensionType.renegotiation_info:
++ # We don't support renegotiation, so if we receive this
++ # extension, it should contain a single null byte.
++ if extLength != 1 or p.getFixBytes(extLength)[0] != 0:
++ raise SyntaxError()
++ self.ri = True
+ else:
+ _ = p.getFixBytes(extLength)
+ index2 = p.index
+ if index2 - index1 != extLength:
+ raise SyntaxError("Bad length for extension_data")
+ soFar += 4 + extLength
++ if CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV in self.cipher_suites:
++ self.ri = True
+ p.stopLengthCheck()
+ return self
+
+@@ -327,6 +336,7 @@ class ServerHello(HandshakeMsg):
+ self.tb_params = None
+ self.signed_cert_timestamps = None
+ self.status_request = False
++ self.send_ri = False
+
+ def create(self, version, random, session_id, cipher_suite,
+ certificate_type, tackExt, alpn_proto_selected,
+@@ -432,6 +442,10 @@ class ServerHello(HandshakeMsg):
+ if self.status_request:
+ w2.add(ExtensionType.status_request, 2)
+ w2.add(0, 2)
++ if self.send_ri:
++ w2.add(ExtensionType.renegotiation_info, 2)
++ w2.add(1, 2)
++ w2.add(0, 1)
+ if len(w2.bytes):
+ w.add(len(w2.bytes), 2)
+ w.bytes += w2.bytes
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index de5d580..8ba1c6e 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -1370,6 +1370,8 @@ class TLSConnection(TLSRecordLayer):
+ serverHello.signed_cert_timestamps = signedCertTimestamps
+ if clientHello.status_request:
+ serverHello.status_request = ocspResponse
++ if clientHello.ri:
++ serverHello.send_ri = True
+
+ # Perform the SRP key exchange
+ clientCertChain = None
+@@ -1583,6 +1585,8 @@ class TLSConnection(TLSRecordLayer):
+ if param in settings.supportedTokenBindingParams:
+ serverHello.tb_params = param
+ break
++ if clientHello.ri:
++ serverHello.send_ri = True
+ for result in self._sendMsg(serverHello):
+ yield result
+
diff --git a/patches/token_binding_version.patch b/patches/token_binding_version.patch
new file mode 100644
index 0000000..72567d5
--- /dev/null
+++ b/patches/token_binding_version.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index 1ce9320..ac7e563 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -223,7 +224,7 @@ class ClientHello(HandshakeMsg):
+ p2 = Parser(tokenBindingBytes)
+ ver_minor = p2.get(1)
+ ver_major = p2.get(1)
+- if (ver_major, ver_minor) >= (0, 6):
++ if (ver_major, ver_minor) >= (0, 10):
+ p2.startLengthCheck(1)
+ while not p2.atLengthCheck():
+ self.tb_client_params.append(p2.get(1))
+@@ -421,7 +431,7 @@ class ServerHello(HandshakeMsg):
+ w2.add(4, 2)
+ # version
+ w2.add(0, 1)
+- w2.add(6, 1)
++ w2.add(10, 1)
+ # length of params (defined as variable length <1..2^8-1>, but in
+ # this context the server can only send a single value.
+ w2.add(1, 1)
diff --git a/tlslite/constants.py b/tlslite/constants.py
index e9743e4..82e8c07 100644
--- a/tlslite/constants.py
+++ b/tlslite/constants.py
@@ -61,6 +61,7 @@
tack = 0xF300
supports_npn = 13172
channel_id = 30032
+ renegotiation_info = 0xFF01 # RFC 5746
class HashAlgorithm:
none = 0
diff --git a/tlslite/messages.py b/tlslite/messages.py
index 1ce9320..ac7e563 100644
--- a/tlslite/messages.py
+++ b/tlslite/messages.py
@@ -140,6 +140,7 @@
self.tb_client_params = []
self.support_signed_cert_timestamps = False
self.status_request = False
+ self.ri = False
def create(self, version, random, session_id, cipher_suites,
certificate_types=None, srpUsername=None,
@@ -223,7 +224,7 @@
p2 = Parser(tokenBindingBytes)
ver_minor = p2.get(1)
ver_major = p2.get(1)
- if (ver_major, ver_minor) >= (0, 6):
+ if (ver_major, ver_minor) >= (0, 10):
p2.startLengthCheck(1)
while not p2.atLengthCheck():
self.tb_client_params.append(p2.get(1))
@@ -244,12 +245,20 @@
# request_extensions in the OCSP request.
p.getFixBytes(extLength)
self.status_request = True
+ elif extType == ExtensionType.renegotiation_info:
+ # We don't support renegotiation, so if we receive this
+ # extension, it should contain a single null byte.
+ if extLength != 1 or p.getFixBytes(extLength)[0] != 0:
+ raise SyntaxError()
+ self.ri = True
else:
_ = p.getFixBytes(extLength)
index2 = p.index
if index2 - index1 != extLength:
raise SyntaxError("Bad length for extension_data")
soFar += 4 + extLength
+ if CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV in self.cipher_suites:
+ self.ri = True
p.stopLengthCheck()
return self
@@ -327,6 +336,7 @@
self.tb_params = None
self.signed_cert_timestamps = None
self.status_request = False
+ self.send_ri = False
def create(self, version, random, session_id, cipher_suite,
certificate_type, tackExt, alpn_proto_selected,
@@ -421,7 +431,7 @@
w2.add(4, 2)
# version
w2.add(0, 1)
- w2.add(6, 1)
+ w2.add(10, 1)
# length of params (defined as variable length <1..2^8-1>, but in
# this context the server can only send a single value.
w2.add(1, 1)
@@ -432,6 +442,10 @@
if self.status_request:
w2.add(ExtensionType.status_request, 2)
w2.add(0, 2)
+ if self.send_ri:
+ w2.add(ExtensionType.renegotiation_info, 2)
+ w2.add(1, 2)
+ w2.add(0, 1)
if len(w2.bytes):
w.add(len(w2.bytes), 2)
w.bytes += w2.bytes
diff --git a/tlslite/tlsconnection.py b/tlslite/tlsconnection.py
index de5d580..8ba1c6e 100644
--- a/tlslite/tlsconnection.py
+++ b/tlslite/tlsconnection.py
@@ -1370,6 +1370,8 @@
serverHello.signed_cert_timestamps = signedCertTimestamps
if clientHello.status_request:
serverHello.status_request = ocspResponse
+ if clientHello.ri:
+ serverHello.send_ri = True
# Perform the SRP key exchange
clientCertChain = None
@@ -1583,6 +1585,8 @@
if param in settings.supportedTokenBindingParams:
serverHello.tb_params = param
break
+ if clientHello.ri:
+ serverHello.send_ri = True
for result in self._sendMsg(serverHello):
yield result