summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/openvpn.812
-rw-r--r--src/openvpn/init.c16
-rw-r--r--src/openvpn/options.c27
-rw-r--r--src/openvpn/options.h6
-rw-r--r--src/openvpn/ssl.c4
-rw-r--r--src/openvpn/ssl_backend.h13
-rw-r--r--src/openvpn/ssl_common.h5
-rw-r--r--src/openvpn/ssl_openssl.c33
-rw-r--r--src/openvpn/ssl_polarssl.c6
9 files changed, 122 insertions, 0 deletions
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index e213f5a..829b09c 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -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
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 3decd23..c32a809 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -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)
{
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index de4fa38..7906f46 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -611,6 +611,10 @@ static const char usage_message[] =
"--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"
" value should be given in hex format.\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;
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index abec83f..c642aa0 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -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)))
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 529d14d..86eda77 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -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");
}
/*
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index b0777bf..99930e5 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -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
* @{ */
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index 95cd2f7..86e4ac8 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -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
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index a38c41b..c08d4fe 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -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.
*/
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index 2056735..cd77aa5 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -149,6 +149,12 @@ tls_ctx_initialised(struct tls_root_ctx *ctx)
}
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)
{
}