Browse code

Added support for TLS Keying Material Exporters [RFC-5705]

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>

Daniel Kubec authored on 2015/03/12 23:14:20
Showing 9 changed files
... ...
@@ -2757,6 +2757,18 @@ client\-connect), then
2757 2757
 every module and script must return success (0) in order for
2758 2758
 the connection to be authenticated.
2759 2759
 .\"*********************************************************
2760
+.TP
2761
+.B \-\-keying-material-exporter label len
2762
+Save Exported Keying Material [RFC5705] of len bytes (must be
2763
+between 16 and 4095 bytes) using label in environment
2764
+(exported_keying_material) for use by plugins in
2765
+OPENVPN_PLUGIN_TLS_FINAL callback.
2766
+
2767
+Note that exporter labels have the potential to collide with existing PRF
2768
+labels. In order to prevent this, labels MUST begin with "EXPORTER".
2769
+
2770
+This option requires OpenSSL 1.0.1 or newer.
2771
+.\"*********************************************************
2760 2772
 .SS Server Mode
2761 2773
 Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode
2762 2774
 is supported, and can be enabled with the
... ...
@@ -2279,6 +2279,22 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
2279 2279
   to.comp_options = options->comp;
2280 2280
 #endif
2281 2281
 
2282
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
2283
+  if (options->keying_material_exporter_label)
2284
+    {
2285
+      to.ekm_size = options->keying_material_exporter_length;
2286
+      if (to.ekm_size < 16 || to.ekm_size > 4095)
2287
+          to.ekm_size = 0;
2288
+
2289
+      to.ekm_label = options->keying_material_exporter_label;
2290
+      to.ekm_label_size = strlen(to.ekm_label);
2291
+    }
2292
+  else
2293
+    {
2294
+      to.ekm_size = 0;
2295
+    }
2296
+#endif
2297
+
2282 2298
   /* TLS handshake authentication (--tls-auth) */
2283 2299
   if (options->tls_auth_file)
2284 2300
     {
... ...
@@ -611,6 +611,10 @@ static const char usage_message[] =
611 611
   "--x509-track x  : Save peer X509 attribute x in environment for use by\n"
612 612
   "                  plugins and management interface.\n"
613 613
 #endif
614
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
615
+  "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n"
616
+  "                  of len bytes (min. 16 bytes) using label in environment for use by plugins.\n"
617
+#endif
614 618
   "--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
615 619
   "                  explicit key usage, you can specify more than one value.\n"
616 620
   "                  value should be given in hex format.\n"
... ...
@@ -7066,6 +7070,29 @@ add_option (struct options *options,
7066 7066
       options->use_peer_id = true;
7067 7067
       options->peer_id = atoi(p[1]);
7068 7068
     }
7069
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
7070
+  else if (streq (p[0], "keying-material-exporter") && p[1] && p[2])
7071
+    {
7072
+      int ekm_length = positive_atoi (p[2]);
7073
+
7074
+      VERIFY_PERMISSION (OPT_P_GENERAL);
7075
+
7076
+      if (strncmp(p[1], "EXPORTER", 8))
7077
+        {
7078
+          msg (msglevel, "Keying material exporter label must begin with "
7079
+                         "\"EXPORTER\"");
7080
+          goto err;
7081
+        }
7082
+      if (ekm_length < 16 || ekm_length > 4095)
7083
+        {
7084
+          msg (msglevel, "Invalid keying material exporter length");
7085
+          goto err;
7086
+        }
7087
+
7088
+      options->keying_material_exporter_label = p[1];
7089
+      options->keying_material_exporter_length = ekm_length;
7090
+    }
7091
+#endif
7069 7092
   else
7070 7093
     {
7071 7094
       int i;
... ...
@@ -591,6 +591,12 @@ struct options
591 591
 
592 592
   bool use_peer_id;
593 593
   uint32_t peer_id;
594
+
595
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
596
+  /* Keying Material Exporters [RFC 5705] */
597
+  const char *keying_material_exporter_label;
598
+  int keying_material_exporter_length;
599
+#endif
594 600
 };
595 601
 
596 602
 #define streq(x, y) (!strcmp((x), (y)))
... ...
@@ -2160,8 +2160,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
2160 2160
    */
2161 2161
   if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
2162 2162
     {
2163
+      key_state_export_keying_material(&ks->ks_ssl, session);
2164
+
2163 2165
       if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
2164 2166
 	ks->authenticated = false;
2167
+
2168
+      setenv_del (session->opt->es, "exported_keying_material");
2165 2169
     }
2166 2170
 
2167 2171
   /*
... ...
@@ -334,6 +334,19 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
334 334
  */
335 335
 void key_state_ssl_free(struct key_state_ssl *ks_ssl);
336 336
 
337
+/**
338
+ * Keying Material Exporters [RFC 5705] allows additional keying material to be
339
+ * derived from existing TLS channel. This exported keying material can then be
340
+ * used for a variety of purposes.
341
+ *
342
+ * @param ks_ssl       The SSL channel's state info
343
+ * @param session      The session associated with the given key_state
344
+ */
345
+
346
+void
347
+key_state_export_keying_material(struct key_state_ssl *ks_ssl,
348
+    struct tls_session *session) __attribute__((nonnull));
349
+
337 350
 /**************************************************************************/
338 351
 /** @addtogroup control_tls
339 352
  *  @{ */
... ...
@@ -317,6 +317,11 @@ struct tls_options
317 317
 
318 318
   /* --gremlin bits */
319 319
   int gremlin;
320
+
321
+  /* Keying Material Exporter [RFC 5705] parameters */
322
+  const char *ekm_label;
323
+  size_t ekm_label_size;
324
+  size_t ekm_size;
320 325
 };
321 326
 
322 327
 /** @addtogroup control_processor
... ...
@@ -133,6 +133,39 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx)
133 133
   return NULL != ctx->ctx;
134 134
 }
135 135
 
136
+void
137
+key_state_export_keying_material(struct key_state_ssl *ssl,
138
+                                 struct tls_session *session)
139
+{
140
+  if (session->opt->ekm_size > 0)
141
+    {
142
+#if (OPENSSL_VERSION_NUMBER >= 0x10001000)
143
+      unsigned int size = session->opt->ekm_size;
144
+      unsigned char ekm[size];
145
+
146
+      if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm),
147
+          session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
148
+       {
149
+         struct gc_arena gc = gc_new();
150
+         unsigned int len = (size * 2) + 2;
151
+
152
+         const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc);
153
+         setenv_str (session->opt->es, "exported_keying_material", key);
154
+
155
+         dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s",
156
+              __func__, key);
157
+
158
+         gc_free(&gc);
159
+       }
160
+      else
161
+       {
162
+         msg (M_WARN, "WARNING: Export keying material failed!");
163
+         setenv_del (session->opt->es, "exported_keying_material");
164
+       }
165
+#endif
166
+    }
167
+}
168
+
136 169
 /*
137 170
  * Print debugging information on SSL/TLS session negotiation.
138 171
  */
... ...
@@ -149,6 +149,12 @@ tls_ctx_initialised(struct tls_root_ctx *ctx)
149 149
 }
150 150
 
151 151
 void
152
+key_state_export_keying_material(struct key_state_ssl *ssl,
153
+                                 struct tls_session *session)
154
+{
155
+}
156
+
157
+void
152 158
 tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
153 159
 {
154 160
 }