diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index c2907cd..8b57419 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -2307,6 +2307,16 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
      length prefix */
   socket_adjust_frame_parameters (&to.frame, options->ce.proto);
 
+  /* Checking for required parameters for Channel Bindings */
+  to.binding_key_size = options->keying_material_exporter_length;
+
+  to.kme_label = (uint8_t*)options->keying_material_exporter_label;
+  to.kme_label_size = to.kme_label ? strlen(to.kme_label) : 0;
+
+  to.binding_key_size = options->keying_material_exporter_length;
+  to.binding_key_gen = (to.kme_label_size && to.binding_key_size >= 20) ?
+                        true : false;
+
   /*
    * Initialize OpenVPN's master TLS-mode object.
    */
@@ -2315,6 +2325,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
 
   if (flags & CF_INIT_TLS_AUTH_STANDALONE)
     c->c2.tls_auth_standalone = tls_auth_standalone_init (&to, &c->c2.gc);
+
 }
 
 static void
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 18cb354..5323cd7 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -6966,6 +6966,24 @@ add_option (struct options *options,
       options->persist_mode = 1;
     }
 #endif
+  else if (streq (p[0], "keying-material-exporter-label") && p[1])
+    {
+      if (strncmp(p[1], "EXPORTER", 8))
+        {
+          msg (msglevel, "keying material exporter labels SHOULD begin with \"EXPORTER\"");
+          goto err;
+        }
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+
+      options->keying_material_exporter_label = p[1];
+    }
+  else if (streq (p[0], "keying-material-exporter-length"))
+    {
+      int len = positive_atoi (p[1]);
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+
+      options->keying_material_exporter_length = len;
+    }
   else
     {
       int i;
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index ec1d091..f5609f9 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -30,26 +30,28 @@
 #ifndef OPTIONS_H
 #define OPTIONS_H
 
+/*
+ * Maximum number of parameters associated with an option,
+ * including the option name itself.
+ */
+
+#define MAX_PARMS 16
+
 #include "basic.h"
 #include "common.h"
 #include "mtu.h"
 #include "route.h"
 #include "tun.h"
 #include "socket.h"
+#include "comp.h"
+#include "ssl_common.h"
 #include "plugin.h"
 #include "manage.h"
 #include "proxy.h"
-#include "comp.h"
 #include "pushlist.h"
 #include "clinat.h"
 
 /*
- * Maximum number of parameters associated with an option,
- * including the option name itself.
- */
-#define MAX_PARMS 16
-
-/*
  * Max size of options line and parameter.
  */
 #define OPTION_PARM_SIZE 256
@@ -600,6 +602,10 @@ struct options
   bool show_net_up;
   int route_method;
 #endif
+
+  /* Keying Material Exporters [RFC 5705] */
+  const char *keying_material_exporter_label;
+  int keying_material_exporter_length;
 };
 
 #define streq(x, y) (!strcmp((x), (y)))
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index d4acc0f..f093011 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1,13 +1,14 @@
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
- *             session authentication and key exchange,
+ *             session authentication, key exchange and channel bindings,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
  *  Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
  *  Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>
+ *  Copyright (C) 2014 Daniel Kubec <niel@rtfm.cz>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -1454,6 +1455,67 @@ tls1_PRF(uint8_t *label,
   gc_free (&gc);
 }
 
+/*                                                                              
+ * Use the tls1_keying_material_exporter for generating channel Binding Key
+ * based on Keying Material Exporters RFC[5705]
+ *
+ * Labels here have the same definition as in TLS, i.e., an ASCII string
+ * with no terminating NULL.  Label values beginning with "EXPERIMENTAL"
+ * MAY be used for private use without registration.  All other label
+ * values MUST be registered via Specification Required as described by
+ * RFC 5226 [RFC5226].  Note that exporter labels have the potential to
+ * collide with existing PRF labels.  In order to prevent this, labels
+ * SHOULD begin with "EXPORTER".  This is not a MUST because there are
+ * existing uses that have labels which do not begin with this prefix.
+ *
+ * The output is a pseudorandom bit string of length bytes generated
+ * from the master_secret.  (This construction allows for
+ * interoperability with older exporter-type constructions which do not
+ * use context values, e.g., [RFC5281]).
+ *
+ * If no context is provided, it then computes:
+ * 
+ *	PRF(SecurityParameters.master_secret, label,
+ *	    SecurityParameters.client_random +
+ *	    SecurityParameters.server_random)[length]
+ *
+ * If context is provided, it computes:
+ *
+ *	PRF(SecurityParameters.master_secret, label,
+ *	    SecurityParameters.client_random +                               
+ *	    SecurityParameters.server_random +                               
+ *	    context_value_length + context_value)[length] 
+ */
+
+static void                                                                     
+tls1_keying_material_exporter(uint8_t *master, int master_len,
+                              uint8_t *label, int label_len,
+                              const uint8_t *client_random, int client_random_len,
+                              const uint8_t *server_random, int server_random_len,
+                              const uint8_t *context_value, int context_value_len,
+                              uint8_t *out, int out_len)
+{
+  struct buffer seed = alloc_buf (master_len
+                                + label_len
+                                + client_random_len
+                                + server_random_len);
+
+  ASSERT (buf_write (&seed, label, label_len));
+  ASSERT (buf_write (&seed, client_random, client_random_len));
+  ASSERT (buf_write (&seed, server_random, server_random_len));
+
+  if (context_value)
+    ASSERT (buf_write (&seed, context_value, context_value_len));
+
+  /* compute PRF */                                                             
+  tls1_PRF (BPTR(&seed), BLEN(&seed), master, master_len, out, out_len);        
+
+  buf_clear (&seed);
+  free_buf (&seed);
+
+  VALGRIND_MAKE_READABLE ((void *)out, out_len);
+}
+
 static void
 openvpn_PRF (const uint8_t *secret,
 	     int secret_len,
@@ -1492,45 +1554,117 @@ openvpn_PRF (const uint8_t *secret,
   VALGRIND_MAKE_READABLE ((void *)output, output_len);
 }
 
+/*
+ * Generated Binding Key based on Keying Material Exporters [RFC 5705]
+ */
+static bool
+generate_key_binding(uint8_t *master,
+                     int master_len,
+                     struct key_ctx_bi *key,
+                     const struct key_type *key_type,
+                     const struct key_source2 *key_src,
+                     uint8_t *label, int label_len,
+                     uint8_t *binding_key, int binding_key_len)
+{
+  const char *context_value = KEY_EXPANSION_ID " binding key";
+  struct gc_arena gc = gc_new ();
+
+  tls1_keying_material_exporter(master, master_len,
+                                label, label_len,
+                                key_src->client.random2,
+                                sizeof(key_src->client.random2),
+                                key_src->server.random2,
+                                sizeof(key_src->server.random2),
+                                context_value,
+                                strlen(context_value),
+                                binding_key, binding_key_len);
+
+  dmsg (D_SHOW_KEY_SOURCE, "tls_binding_key: %s",
+        format_hex (binding_key, binding_key_len, 0, &gc));
+  gc_free (&gc);
+  return true;
+}
+
+/* Channel ID identifies TLS Session across negotiations */
+static void
+generate_channel_id(uint8_t *master,
+                    int master_len,
+                    struct key_ctx_bi *key,
+                    const struct key_type *key_type,
+                    const struct key_source2 *key_src,
+                    uint8_t *id,
+                    int id_len)
+{
+  struct gc_arena gc = gc_new ();
+
+  openvpn_PRF (master,
+               master_len,
+               KEY_EXPANSION_ID " channel id",
+               key_src->client.random2,
+               sizeof(key_src->client.random2),
+               key_src->server.random2,
+               sizeof(key_src->server.random2),
+               NULL,
+               NULL,
+               id,
+               id_len);
+
+  dmsg (D_SHOW_KEY_SOURCE, "tls_channel_id: %s",
+        format_hex (id, id_len, 0, &gc));
+
+  gc_free (&gc);
+}
+
+static void
+generate_master_secret(struct key_ctx_bi *key,
+                       const struct key_type *key_type,
+                       const struct key_source2 *key_src,
+                       uint8_t *master,
+                       unsigned int master_size)
+{
+  /* compute master secret */
+  openvpn_PRF (key_src->client.pre_master,
+               sizeof(key_src->client.pre_master),
+               KEY_EXPANSION_ID " master secret",
+               key_src->client.random1,
+               sizeof(key_src->client.random1),
+               key_src->server.random1,
+               sizeof(key_src->server.random1),
+               NULL,
+               NULL,
+               master,
+               master_size);
+
+  key_source2_print (key_src);
+
+}
+
 /* 
  * Using source entropy from local and remote hosts, mix into
  * master key.
  */
 static bool
-generate_key_expansion (struct key_ctx_bi *key,
+generate_key_expansion (uint8_t *master,
+			int master_len,
+			struct key_ctx_bi *key,
 			const struct key_type *key_type,
 			const struct key_source2 *key_src,
 			const struct session_id *client_sid,
 			const struct session_id *server_sid,
 			bool server)
 {
-  uint8_t master[48];
   struct key2 key2;
   bool ret = false;
   int i;
 
-  CLEAR (master);
   CLEAR (key2);
 
   /* debugging print of source key material */
   key_source2_print (key_src);
 
-  /* compute master secret */
-  openvpn_PRF (key_src->client.pre_master,
-	       sizeof(key_src->client.pre_master),
-	       KEY_EXPANSION_ID " master secret",
-	       key_src->client.random1,
-	       sizeof(key_src->client.random1),
-	       key_src->server.random1,
-	       sizeof(key_src->server.random1),
-	       NULL,
-	       NULL,
-	       master,
-	       sizeof(master));
-  
   /* compute key expansion */
   openvpn_PRF (master,
-	       sizeof(master),
+	       master_len,
 	       KEY_EXPANSION_ID " key expansion",
 	       key_src->client.random2,
 	       sizeof(key_src->client.random2),
@@ -1869,6 +2003,10 @@ static bool
 key_method_2_write (struct buffer *buf, struct tls_session *session)
 {
   struct key_state *ks = &session->key[KS_PRIMARY]; 	   /* primary key */
+  struct gc_arena gc = gc_new ();
+  uint8_t master_secret[48];                                            
+
+  CLEAR(master_secret);
 
   ASSERT (session->opt->key_method == 2);
   ASSERT (buf_init (buf, 0));
@@ -1919,30 +2057,96 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
   /*
    * generate tunnel keys if server
    */
-  if (session->opt->server)
+  
+  if (!session->opt->server)
+    goto done;
+
+  session->negotiations++;
+
+  if (ks->authenticated)
     {
-      if (ks->authenticated)
-	{
-	  if (!generate_key_expansion (&ks->key,
-				       &session->opt->key_type,
-				       ks->key_src,
-				       &ks->session_id_remote,
-				       &session->session_id,
-				       true))
-	    {
-	      msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
-	      goto error;
-	    }
-	}
-		      
-      CLEAR (*ks->key_src);
+       generate_master_secret(&ks->key,
+                              &session->opt->key_type,
+                              ks->key_src,
+                              master_secret,
+                              sizeof(master_secret));
+
+       /*
+        * Generate channel id identifies TLS Session across (re)negotiations$
+        */
+       if (session->negotiations == 1)
+           generate_channel_id(master_secret,
+                               sizeof(master_secret),
+                               &ks->key,
+                               &session->opt->key_type,
+                               ks->key_src,
+                               session->channel_id,
+                               sizeof(session->channel_id));
+
     }
 
+  /*
+   * Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final
+   * veto opportunity over authentication decision.
+   */
+  if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
+    {
+      setenv_str(session->opt->es, "tls_channel_id",
+                 format_hex (session->channel_id, sizeof(session->channel_id), 0, &gc));
+
+      /* Channel Binding Key based on Keying Material Derivate [RFC 5705] */
+      if (session->opt->binding_key_gen)
+        {
+          char *binding_key = gc_malloc (session->opt->binding_key_size, false, &gc);
+
+          if (!generate_key_binding (master_secret,
+                                     sizeof(master_secret),
+                                     &ks->key,
+                                     &session->opt->key_type,
+                                     ks->key_src,
+                                     session->opt->kme_label,
+                                     session->opt->kme_label_size,
+                                     binding_key,
+                                     session->opt->binding_key_size))
+            {
+              msg (D_TLS_ERRORS, "TLS Error: generate_key_binding failed");
+              goto error;
+            }
+            else
+            {
+              setenv_str(session->opt->es, "tls_binding_key",
+                         format_hex (binding_key,
+                                     session->opt->binding_key_size, 0, &gc));
+            }
+    }
+
+    if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+	ks->authenticated = false;
+  }
+
+  if (!generate_key_expansion (master_secret,
+                               sizeof(master_secret),
+                               &ks->key,
+                               &session->opt->key_type,
+                               ks->key_src,
+                               &ks->session_id_remote,
+                               &session->session_id,
+                               true))
+  {
+    msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
+    goto error;
+  }
+
+  CLEAR (*ks->key_src);
+
+done:
+  gc_free (&gc);
   return true;
 
  error:
   msg (D_TLS_ERRORS, "TLS Error: Key Method #2 write failed");
   CLEAR (*ks->key_src);
+  gc_free (&gc);
   return false;
 }
 
@@ -2017,6 +2221,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
   struct gc_arena gc = gc_new ();
   char *options;
   struct user_pass *up;
+  uint8_t master_secret[48];   /* master secret */
+
+  CLEAR(master_secret);
 
   /* allocate temporary objects */
   ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
@@ -2120,39 +2327,97 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
 
   buf_clear (buf);
 
+  /*                                                                            
+   * Generate keys if client because server_random is not ready here for the
+   * server end-point                                           
+   */
+  if (session->opt->server)
+    goto done;
+
+  session->negotiations++;
+
+  /* 
+   * Generate master secret here because it is used in
+   * generate_binding_key(), generate_channel_id() and generate_key_expansion()
+   */
+  generate_master_secret(&ks->key,
+                         &session->opt->key_type,
+                         ks->key_src,
+                         master_secret,
+                         sizeof(master_secret));
+  /*
+   * Generate channel id identifies TLS Session across (re)negotiations
+   */
+  if (session->negotiations == 1)
+    generate_channel_id(master_secret,
+                        sizeof(master_secret),
+                        &ks->key,
+                        &session->opt->key_type,
+                        ks->key_src,
+                        session->channel_id,
+                        sizeof(session->channel_id));
   /*
    * Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final
    * veto opportunity over authentication decision.
    */
   if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
     {
+      setenv_str(session->opt->es, "tls_channel_id",
+                 format_hex (session->channel_id, sizeof(session->channel_id), 0, &gc));
+
+      /* Channel Binding Key based on Keying Material Derivate [RFC 5705] */
+      if (session->opt->binding_key_gen) 
+        {
+          char *binding_key = gc_malloc (session->opt->binding_key_size, false, &gc);
+
+          if (!generate_key_binding (master_secret, 
+                                     sizeof(master_secret),
+                                     &ks->key,
+                                     &session->opt->key_type,
+                                     ks->key_src,
+                                     session->opt->kme_label,
+                                     session->opt->kme_label_size,
+                                     binding_key,
+                                     session->opt->binding_key_size))
+          {
+            msg (D_TLS_ERRORS, "TLS Error: generate_key_binding failed");
+            goto error;
+          }
+          else
+          {
+            setenv_str(session->opt->es, "tls_binding_key", 
+                       format_hex (binding_key, 
+                                   session->opt->binding_key_size, 0, &gc));
+          }
+      }
+
       if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
 	ks->authenticated = false;
     }
 
   /*
-   * Generate tunnel keys if client
+   * Generate tunnel keys 
    */
-  if (!session->opt->server)
-    {
-      if (!generate_key_expansion (&ks->key,
-				   &session->opt->key_type,
-				   ks->key_src,
-				   &session->session_id,
-				   &ks->session_id_remote,
-				   false))
-	{
-	  msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed");
-	  goto error;
-	}
-		      
-      CLEAR (*ks->key_src);
+  if (!generate_key_expansion (master_secret,
+                               sizeof(master_secret),
+                               &ks->key,
+                               &session->opt->key_type,
+                               ks->key_src,
+                               &session->session_id,
+                               &ks->session_id_remote,
+                               false))
+    {
+      msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed");
+      goto error;
     }
+		      
+  CLEAR (*ks->key_src);
 
+done:
   gc_free (&gc);
   return true;
 
- error:
+error:
   CLEAR (*ks->key_src);
   buf_clear (buf);
   gc_free (&gc);
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index 04ba789..9af68bc 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -314,6 +314,12 @@ struct tls_options
 
   /* --gremlin bits */
   int gremlin;
+
+  /* Keying Material Exporter [RFC 5705] parameters */
+  uint8_t *kme_label;
+  int kme_label_size;
+  bool binding_key_gen; /* true when binding key should be generated */
+  int binding_key_size;
 };
 
 /** @addtogroup control_processor
@@ -359,6 +365,12 @@ struct tls_session
   struct crypto_options tls_auth;
   struct packet_id tls_auth_pid;
 
+  /* number of negotiations for this session */
+  unsigned int negotiations;
+
+  /* channel_id identifies TLS session across (re)negotiations */
+  uint8_t channel_id[32];                 
+
   int initial_opcode;		/* our initial P_ opcode */
   struct session_id session_id;	/* our random session ID */
   int key_id;			/* increments with each soft reset (for key renegotiation) */
