Re: [Openvpn-devel] [PATCH v3 1/3] Refactor key_state_export_keying_material functions

2020-08-21 Thread Steffan Karger
Hi,

On 14-08-2020 16:51, Arne Schwabe wrote:
> This refactors the common code between mbed SSL and OpenSSL into
> export_user_keying_material and also prepares the backend functions
> to export more than one key.
> 
> Also fix checking the return value of SSL_export_keying_material
> only 1 is a sucess, -1 is also an error.
> 
> Signed-off-by: Arne Schwabe 
> 
> Patch V2: Cache secrets for mbed TLS instead generating all ekms
>   in the call back function
> 
> Patch V3: comment is no longer a lie. (fixed doxygen)
> 
> Signed-off-by: Arne Schwabe 
> ---
>  src/openvpn/ssl.c | 36 ++-
>  src/openvpn/ssl_backend.h | 20 +++
>  src/openvpn/ssl_mbedtls.c | 73 ---
>  src/openvpn/ssl_mbedtls.h | 12 +--
>  src/openvpn/ssl_openssl.c | 43 +--
>  5 files changed, 114 insertions(+), 70 deletions(-)
> 
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index f16114c2..3fcaa25f 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -2412,6 +2412,40 @@ error:
>  return false;
>  }
>  
> +static void
> +export_user_keying_material(struct key_state_ssl *ssl,
> +struct tls_session *session)
> +{
> +if (session->opt->ekm_size > 0)
> +{
> +unsigned int size = session->opt->ekm_size;
> +struct gc_arena gc = gc_new();
> +
> +unsigned char *ekm;
> +if ((ekm = key_state_export_keying_material(session,
> +session->opt->ekm_label,
> +
> session->opt->ekm_label_size,
> +session->opt->ekm_size,
> +&gc)))
> +{
> +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);
> +secure_memzero(ekm, size);
> +}
> +else
> +{
> +msg(M_WARN, "WARNING: Export keying material failed!");
> +setenv_del(session->opt->es, "exported_keying_material");
> +}
> +gc_free(&gc);
> +}
> +}
> +
>  /**
>   * Handle reading key data, peer-info, username/password, OCC
>   * from the TLS control channel (cleartext).
> @@ -2541,7 +2575,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi 
> *multi, struct tls_sessio
>  if ((ks->authenticated > KS_AUTH_FALSE)
>  && plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
>  {
> -key_state_export_keying_material(&ks->ks_ssl, session);
> +export_user_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)
>  {
> diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
> index 7f52ab1e..cf9fba25 100644
> --- a/src/openvpn/ssl_backend.h
> +++ b/src/openvpn/ssl_backend.h
> @@ -394,13 +394,21 @@ void backend_tls_ctx_reload_crl(struct tls_root_ctx 
> *ssl_ctx,
>   * 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));
> + * @param labelThe label to use when exporting the key
> + * @param label_size   The size of the label to use when exporting the key
> + * @param ekm_size THe size of the exported/returned key material
> + * @param gc   gc_arena that might be used to allocate the string
> + * returned
> + * @returnsThe exported key material, the caller may zero the
> + * string but should not free it
> + */
> +
> +unsigned char*
> +key_state_export_keying_material(struct tls_session *session,
> + const char* label, size_t label_size,
> + size_t ekm_size,
> + struct gc_arena *gc) 
> __attribute__((nonnull));
>  
>  /**/
>  /** @addtogroup control_tls
> diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
> index 9c874788..4287b59e 100644
> --- a/src/openvpn/ssl_mbedtls.c
> +++ b/src/openvpn/ssl_mbedtls.c
> @@ -206,51 +206,54 @@ mbedtls_ssl_export_keys_cb(void *p_expkey, const 
> unsigned char *ms,
>  {
>  struct tls_session *session = p_expkey;
>  struct key_state_ssl *ks_ssl =

[Openvpn-devel] [PATCH v3 1/3] Refactor key_state_export_keying_material functions

2020-08-14 Thread Arne Schwabe
This refactors the common code between mbed SSL and OpenSSL into
export_user_keying_material and also prepares the backend functions
to export more than one key.

Also fix checking the return value of SSL_export_keying_material
only 1 is a sucess, -1 is also an error.

Signed-off-by: Arne Schwabe 

Patch V2: Cache secrets for mbed TLS instead generating all ekms
  in the call back function

Patch V3: comment is no longer a lie. (fixed doxygen)

Signed-off-by: Arne Schwabe 
---
 src/openvpn/ssl.c | 36 ++-
 src/openvpn/ssl_backend.h | 20 +++
 src/openvpn/ssl_mbedtls.c | 73 ---
 src/openvpn/ssl_mbedtls.h | 12 +--
 src/openvpn/ssl_openssl.c | 43 +--
 5 files changed, 114 insertions(+), 70 deletions(-)

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index f16114c2..3fcaa25f 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -2412,6 +2412,40 @@ error:
 return false;
 }
 
+static void
+export_user_keying_material(struct key_state_ssl *ssl,
+struct tls_session *session)
+{
+if (session->opt->ekm_size > 0)
+{
+unsigned int size = session->opt->ekm_size;
+struct gc_arena gc = gc_new();
+
+unsigned char *ekm;
+if ((ekm = key_state_export_keying_material(session,
+session->opt->ekm_label,
+
session->opt->ekm_label_size,
+session->opt->ekm_size,
+&gc)))
+{
+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);
+secure_memzero(ekm, size);
+}
+else
+{
+msg(M_WARN, "WARNING: Export keying material failed!");
+setenv_del(session->opt->es, "exported_keying_material");
+}
+gc_free(&gc);
+}
+}
+
 /**
  * Handle reading key data, peer-info, username/password, OCC
  * from the TLS control channel (cleartext).
@@ -2541,7 +2575,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi 
*multi, struct tls_sessio
 if ((ks->authenticated > KS_AUTH_FALSE)
 && plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
 {
-key_state_export_keying_material(&ks->ks_ssl, session);
+export_user_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)
 {
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 7f52ab1e..cf9fba25 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -394,13 +394,21 @@ void backend_tls_ctx_reload_crl(struct tls_root_ctx 
*ssl_ctx,
  * 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));
+ * @param labelThe label to use when exporting the key
+ * @param label_size   The size of the label to use when exporting the key
+ * @param ekm_size THe size of the exported/returned key material
+ * @param gc   gc_arena that might be used to allocate the string
+ * returned
+ * @returnsThe exported key material, the caller may zero the
+ * string but should not free it
+ */
+
+unsigned char*
+key_state_export_keying_material(struct tls_session *session,
+ const char* label, size_t label_size,
+ size_t ekm_size,
+ struct gc_arena *gc) __attribute__((nonnull));
 
 /**/
 /** @addtogroup control_tls
diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
index 9c874788..4287b59e 100644
--- a/src/openvpn/ssl_mbedtls.c
+++ b/src/openvpn/ssl_mbedtls.c
@@ -206,51 +206,54 @@ mbedtls_ssl_export_keys_cb(void *p_expkey, const unsigned 
char *ms,
 {
 struct tls_session *session = p_expkey;
 struct key_state_ssl *ks_ssl = &session->key[KS_PRIMARY].ks_ssl;
-unsigned char client_server_random[64];
+struct tls_key_cache *cache = &ks_ssl->tls_key_cache;
 
-ks_ssl->exported_key_material = gc_malloc(session->opt->ekm_size,
-  true, NULL);
+static_assert(sizeof(