Set Token-Binding HTTP header

Adds a new method to SSLClientSocket to get the Token Binding from an SSL
connection where Token Binding was negotiated, and uses that to add the
Set-Token-Binding HTTP header (only when Token Binding was negotiated).

BUG=467312

Review URL: https://codereview.chromium.org/1378613004

Cr-Original-Commit-Position: refs/heads/master@{#371347}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: b7441ef2effe86324798710a82d8a006f5eb1395
diff --git a/README.chromium b/README.chromium
index e995e95..3bc992d 100644
--- a/README.chromium
+++ b/README.chromium
@@ -45,3 +45,7 @@
   binding negotiation TLS extension (draft-ietf-tokbind-negotiation-00)
 - patches/disable_channel_id.patch: Add flag to HandshakeSettings to allow
   for disabling channel id.
+- patches/exported_keying_material.patch: Add method to Session to get
+  exported keying material (RFC 5705) for use in e.g. Token Binding.
+- patches/token_binding_resumption.patch: Fix token binding negotiation
+  extension to work on session resumption.
diff --git a/patches/exported_keying_material.patch b/patches/exported_keying_material.patch
new file mode 100644
index 0000000..9d4ed9c
--- /dev/null
+++ b/patches/exported_keying_material.patch
@@ -0,0 +1,56 @@
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 7363a30..e42b362 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -181,6 +181,8 @@ class TLSConnection(TLSRecordLayer):
+         @type sock: L{socket.socket}
+         """
+         TLSRecordLayer.__init__(self, sock)
++        self.clientRandom = b""
++        self.serverRandom = b""
+ 
+     #*********************************************************
+     # Client Handshake Functions
+@@ -606,6 +608,9 @@ class TLSConnection(TLSRecordLayer):
+                 else: break
+         masterSecret = result
+         
++        self.clientRandom = clientHello.random
++        self.serverRandom = serverHello.random
++
+         # Create the session object which is used for resumptions
+         self.session = Session()
+         self.session.create(masterSecret, serverHello.session_id, cipherSuite,
+@@ -1398,6 +1403,9 @@ class TLSConnection(TLSRecordLayer):
+                 else: break
+         masterSecret = result
+ 
++        self.clientRandom = clientHello.random
++        self.serverRandom = serverHello.random
++
+         #Create the session object
+         self.session = Session()
+         if cipherSuite in CipherSuite.certAllSuites:        
+@@ -2013,3 +2025,22 @@ class TLSConnection(TLSRecordLayer):
+             except:
+                 self._shutdown(False)
+                 raise
++
++
++    def exportKeyingMaterial(self, label, context, use_context, length):
++        """Returns the exported keying material as defined in RFC 5705."""
++
++        seed = self.clientRandom + self.serverRandom
++        if use_context:
++            if len(context) > 65535:
++                raise ValueError("Context is too long")
++            seed += bytearray(2)
++            seed[len(seed) - 2] = len(context) >> 8
++            seed[len(seed) - 1] = len(context) & 0xFF
++            seed += context
++        if self.version in ((3,1), (3,2)):
++            return PRF(self.session.masterSecret, label, seed, length)
++        elif self.version == (3,3):
++            return PRF_1_2(self.session.masterSecret, label, seed, length)
++        else:
++            raise AssertionError()
diff --git a/patches/token_binding_resumption.patch b/patches/token_binding_resumption.patch
new file mode 100644
index 0000000..5d856b2
--- /dev/null
+++ b/patches/token_binding_resumption.patch
@@ -0,0 +1,15 @@
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 6a53282..6e26fdd 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -1536,6 +1536,10 @@ class TLSConnection(TLSRecordLayer):
+                 serverHello.extended_master_secret = \
+                     clientHello.extended_master_secret and \
+                     settings.enableExtendedMasterSecret
++                for param in clientHello.tb_client_params:
++                    if param in settings.supportedTokenBindingParams:
++                          serverHello.tb_params = param
++                          break
+                 for result in self._sendMsg(serverHello):
+                     yield result
+ 
diff --git a/tlslite/tlsconnection.py b/tlslite/tlsconnection.py
index 7363a30..e42b362 100644
--- a/tlslite/tlsconnection.py
+++ b/tlslite/tlsconnection.py
@@ -181,6 +181,8 @@
         @type sock: L{socket.socket}
         """
         TLSRecordLayer.__init__(self, sock)
+        self.clientRandom = b""
+        self.serverRandom = b""
 
     #*********************************************************
     # Client Handshake Functions
@@ -606,6 +608,9 @@
                 else: break
         masterSecret = result
         
+        self.clientRandom = clientHello.random
+        self.serverRandom = serverHello.random
+
         # Create the session object which is used for resumptions
         self.session = Session()
         self.session.create(masterSecret, serverHello.session_id, cipherSuite,
@@ -1398,6 +1403,9 @@
                 else: break
         masterSecret = result
 
+        self.clientRandom = clientHello.random
+        self.serverRandom = serverHello.random
+
         #Create the session object
         self.session = Session()
         if cipherSuite in CipherSuite.certAllSuites:        
@@ -1536,6 +1544,10 @@
                 serverHello.extended_master_secret = \
                     clientHello.extended_master_secret and \
                     settings.enableExtendedMasterSecret
+                for param in clientHello.tb_client_params:
+                    if param in settings.supportedTokenBindingParams:
+                          serverHello.tb_params = param
+                          break
                 for result in self._sendMsg(serverHello):
                     yield result
 
@@ -2013,3 +2025,22 @@
             except:
                 self._shutdown(False)
                 raise
+
+
+    def exportKeyingMaterial(self, label, context, use_context, length):
+        """Returns the exported keying material as defined in RFC 5705."""
+
+        seed = self.clientRandom + self.serverRandom
+        if use_context:
+            if len(context) > 65535:
+                raise ValueError("Context is too long")
+            seed += bytearray(2)
+            seed[len(seed) - 2] = len(context) >> 8
+            seed[len(seed) - 1] = len(context) & 0xFF
+            seed += context
+        if self.version in ((3,1), (3,2)):
+            return PRF(self.session.masterSecret, label, seed, length)
+        elif self.version == (3,3):
+            return PRF_1_2(self.session.masterSecret, label, seed, length)
+        else:
+            raise AssertionError()