]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added support for TLS Keying Material Exporters [RFC-5705]
authorDaniel Kubec <niel@rtfm.cz>
Thu, 12 Mar 2015 14:14:20 +0000 (15:14 +0100)
committerDavid Sommerseth <davids@redhat.com>
Fri, 9 Oct 2015 22:02:40 +0000 (00:02 +0200)
Keying Material Exporter [RFC-5705] allow additional keying material to be
derived from existing TLS channel. This exported keying material can then be
used for a variety of purposes.

[DS: Updated man page to document both upper and lower length boundaries]

Signed-off-by: Daniel Kubec <niel@rtfm.cz>
Signed-off-by: David Sommerseth <davids@redhat.com>
Acked-by: Steffan Karger <steffan.karger@fox-it.com
Acked-by: David Sommerseth <davids@redhat.com>
doc/openvpn.8
src/openvpn/init.c
src/openvpn/options.c
src/openvpn/options.h
src/openvpn/ssl.c
src/openvpn/ssl_backend.h
src/openvpn/ssl_common.h
src/openvpn/ssl_openssl.c
src/openvpn/ssl_polarssl.c

index e213f5afb42d92d823bbf06f19fc32553af6579e..829b09cd83ffacbc3009e46648e49a1c498ba538 100644 (file)
@@ -2757,6 +2757,18 @@ client\-connect), then
 every module and script must return success (0) in order for
 the connection to be authenticated.
 .\"*********************************************************
+.TP
+.B \-\-keying-material-exporter label len
+Save Exported Keying Material [RFC5705] of len bytes (must be
+between 16 and 4095 bytes) using label in environment
+(exported_keying_material) for use by plugins in
+OPENVPN_PLUGIN_TLS_FINAL callback.
+
+Note that exporter labels have the potential to collide with existing PRF
+labels. In order to prevent this, labels MUST begin with "EXPORTER".
+
+This option requires OpenSSL 1.0.1 or newer.
+.\"*********************************************************
 .SS Server Mode
 Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode
 is supported, and can be enabled with the
index 3decd2367c101c0cd4ee4c730bad0d5b38fd429b..c32a809d6d161fde54fe5efd1389dfc548754e4d 100644 (file)
@@ -2279,6 +2279,22 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
   to.comp_options = options->comp;
 #endif
 
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+  if (options->keying_material_exporter_label)
+    {
+      to.ekm_size = options->keying_material_exporter_length;
+      if (to.ekm_size < 16 || to.ekm_size > 4095)
+          to.ekm_size = 0;
+
+      to.ekm_label = options->keying_material_exporter_label;
+      to.ekm_label_size = strlen(to.ekm_label);
+    }
+  else
+    {
+      to.ekm_size = 0;
+    }
+#endif
+
   /* TLS handshake authentication (--tls-auth) */
   if (options->tls_auth_file)
     {
index de4fa38ebe7fcc2b29d4e38637e4b2eb4f7bbb0b..7906f46fd69cd9c2fb98d10e6602b1280a7cff69 100644 (file)
@@ -610,6 +610,10 @@ static const char usage_message[] =
 #ifdef ENABLE_X509_TRACK
   "--x509-track x  : Save peer X509 attribute x in environment for use by\n"
   "                  plugins and management interface.\n"
+#endif
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+  "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n"
+  "                  of len bytes (min. 16 bytes) using label in environment for use by plugins.\n"
 #endif
   "--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
   "                  explicit key usage, you can specify more than one value.\n"
@@ -7066,6 +7070,29 @@ add_option (struct options *options,
       options->use_peer_id = true;
       options->peer_id = atoi(p[1]);
     }
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+  else if (streq (p[0], "keying-material-exporter") && p[1] && p[2])
+    {
+      int ekm_length = positive_atoi (p[2]);
+
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+
+      if (strncmp(p[1], "EXPORTER", 8))
+        {
+          msg (msglevel, "Keying material exporter label must begin with "
+                         "\"EXPORTER\"");
+          goto err;
+        }
+      if (ekm_length < 16 || ekm_length > 4095)
+        {
+          msg (msglevel, "Invalid keying material exporter length");
+          goto err;
+        }
+
+      options->keying_material_exporter_label = p[1];
+      options->keying_material_exporter_length = ekm_length;
+    }
+#endif
   else
     {
       int i;
index abec83f7ebb649eaf6110eb274603d8b4fac2da3..c642aa0df6248315780119bc60cf013af4608f4a 100644 (file)
@@ -591,6 +591,12 @@ struct options
 
   bool use_peer_id;
   uint32_t peer_id;
+
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+  /* Keying Material Exporters [RFC 5705] */
+  const char *keying_material_exporter_label;
+  int keying_material_exporter_length;
+#endif
 };
 
 #define streq(x, y) (!strcmp((x), (y)))
index 529d14dae4be76adcd49a274c5bbe5eb30618f66..86eda77c09ad57ce68505966ef16ef83aad9ed21 100644 (file)
@@ -2160,8 +2160,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
    */
   if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
     {
+      key_state_export_keying_material(&ks->ks_ssl, session);
+
       if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
        ks->authenticated = false;
+
+      setenv_del (session->opt->es, "exported_keying_material");
     }
 
   /*
index b0777bf54dfdcef080da938078cf31ddb59ee72f..99930e58611b2f6cd049997695aeeb498011dd3b 100644 (file)
@@ -334,6 +334,19 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
  */
 void key_state_ssl_free(struct key_state_ssl *ks_ssl);
 
+/**
+ * Keying Material Exporters [RFC 5705] allows additional keying material to be
+ * derived from existing TLS channel. This exported keying material can then be
+ * used for a variety of purposes.
+ *
+ * @param ks_ssl       The SSL channel's state info
+ * @param session      The session associated with the given key_state
+ */
+
+void
+key_state_export_keying_material(struct key_state_ssl *ks_ssl,
+    struct tls_session *session) __attribute__((nonnull));
+
 /**************************************************************************/
 /** @addtogroup control_tls
  *  @{ */
index 95cd2f7d93d1df01efb1ae5354676337fbd3bb8e..86e4ac8adeab04bd4d83df8cafc8e97d64e0be1e 100644 (file)
@@ -317,6 +317,11 @@ struct tls_options
 
   /* --gremlin bits */
   int gremlin;
+
+  /* Keying Material Exporter [RFC 5705] parameters */
+  const char *ekm_label;
+  size_t ekm_label_size;
+  size_t ekm_size;
 };
 
 /** @addtogroup control_processor
index a38c41b8172400354cf075315a623abad6838c00..c08d4fe41e68a82ae176bf518d0a2ba7e12cddd3 100644 (file)
@@ -133,6 +133,39 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx)
   return NULL != ctx->ctx;
 }
 
+void
+key_state_export_keying_material(struct key_state_ssl *ssl,
+                                 struct tls_session *session)
+{
+  if (session->opt->ekm_size > 0)
+    {
+#if (OPENSSL_VERSION_NUMBER >= 0x10001000)
+      unsigned int size = session->opt->ekm_size;
+      unsigned char ekm[size];
+
+      if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm),
+          session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
+       {
+         struct gc_arena gc = gc_new();
+         unsigned int len = (size * 2) + 2;
+
+         const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc);
+         setenv_str (session->opt->es, "exported_keying_material", key);
+
+         dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s",
+              __func__, key);
+
+         gc_free(&gc);
+       }
+      else
+       {
+         msg (M_WARN, "WARNING: Export keying material failed!");
+         setenv_del (session->opt->es, "exported_keying_material");
+       }
+#endif
+    }
+}
+
 /*
  * Print debugging information on SSL/TLS session negotiation.
  */
index 20567354d576936464e7c591d95c0ea9113aff15..cd77aa57692fb5dd679db597a118a39b44252bdb 100644 (file)
@@ -148,6 +148,12 @@ tls_ctx_initialised(struct tls_root_ctx *ctx)
   return ctx->initialised;
 }
 
+void
+key_state_export_keying_material(struct key_state_ssl *ssl,
+                                 struct tls_session *session)
+{
+}
+
 void
 tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
 {