mirror of
https://github.com/OpenVPN/openvpn.git
synced 2024-09-20 12:02:28 +02:00
Refactor key_state_export_keying_material functions
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 success, -1 is also an error. Signed-off-by: Arne Schwabe <arne@rfc2549.org> 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 <arne@rfc2549.org> Acked-by: Steffan Karger <steffan@karger.me> Message-Id: <20200814145153.12895-1-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg20739.html Signed-off-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
parent
62560e2a29
commit
10abd656a3
@ -2412,6 +2412,40 @@ error:
|
|||||||
return false;
|
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
|
* Handle reading key data, peer-info, username/password, OCC
|
||||||
* from the TLS control channel (cleartext).
|
* 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)
|
if ((ks->authenticated > KS_AUTH_FALSE)
|
||||||
&& plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
|
&& 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)
|
if (plugin_call(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -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
|
* derived from existing TLS channel. This exported keying material can then be
|
||||||
* used for a variety of purposes.
|
* 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
|
* @param session The session associated with the given key_state
|
||||||
|
* @param label The 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
|
||||||
|
* @returns The exported key material, the caller may zero the
|
||||||
|
* string but should not free it
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
unsigned char*
|
||||||
key_state_export_keying_material(struct key_state_ssl *ks_ssl,
|
key_state_export_keying_material(struct tls_session *session,
|
||||||
struct tls_session *session) __attribute__((nonnull));
|
const char* label, size_t label_size,
|
||||||
|
size_t ekm_size,
|
||||||
|
struct gc_arena *gc) __attribute__((nonnull));
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/** @addtogroup control_tls
|
/** @addtogroup control_tls
|
||||||
|
@ -206,52 +206,55 @@ mbedtls_ssl_export_keys_cb(void *p_expkey, const unsigned char *ms,
|
|||||||
{
|
{
|
||||||
struct tls_session *session = p_expkey;
|
struct tls_session *session = p_expkey;
|
||||||
struct key_state_ssl *ks_ssl = &session->key[KS_PRIMARY].ks_ssl;
|
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,
|
static_assert(sizeof(ks_ssl->ctx->session->master)
|
||||||
true, NULL);
|
== sizeof(cache->master_secret), "master size mismatch");
|
||||||
|
|
||||||
memcpy(client_server_random, client_random, 32);
|
memcpy(cache->client_server_random, client_random, 32);
|
||||||
memcpy(client_server_random + 32, server_random, 32);
|
memcpy(cache->client_server_random + 32, server_random, 32);
|
||||||
|
memcpy(cache->master_secret, ms, sizeof(cache->master_secret));
|
||||||
|
cache->tls_prf_type = tls_prf_type;
|
||||||
|
|
||||||
const size_t ms_len = sizeof(ks_ssl->ctx->session->master);
|
return true;
|
||||||
int ret = mbedtls_ssl_tls_prf(tls_prf_type, ms, ms_len,
|
}
|
||||||
session->opt->ekm_label, client_server_random,
|
|
||||||
sizeof(client_server_random), ks_ssl->exported_key_material,
|
|
||||||
session->opt->ekm_size);
|
|
||||||
|
|
||||||
if (!mbed_ok(ret))
|
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)
|
||||||
|
{
|
||||||
|
ASSERT(strlen(label) == label_size);
|
||||||
|
|
||||||
|
struct tls_key_cache *cache = &session->key[KS_PRIMARY].ks_ssl.tls_key_cache;
|
||||||
|
|
||||||
|
/* If the type is NONE, we either have no cached secrets or
|
||||||
|
* there is no PRF, in both cases we cannot generate key material */
|
||||||
|
if (cache->tls_prf_type == MBEDTLS_SSL_TLS_PRF_NONE)
|
||||||
{
|
{
|
||||||
secure_memzero(ks_ssl->exported_key_material, session->opt->ekm_size);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
secure_memzero(client_server_random, sizeof(client_server_random));
|
unsigned char *ekm = (unsigned char *) gc_malloc(ekm_size, true, gc);
|
||||||
|
int ret = mbedtls_ssl_tls_prf(cache->tls_prf_type, cache->master_secret,
|
||||||
|
sizeof(cache->master_secret),
|
||||||
|
label, cache->client_server_random,
|
||||||
|
sizeof(cache->client_server_random),
|
||||||
|
ekm, ekm_size);
|
||||||
|
|
||||||
return ret;
|
if (mbed_ok(ret))
|
||||||
|
{
|
||||||
|
return ekm;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
secure_memzero(ekm, session->opt->ekm_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_EXPORT_KEYING_MATERIAL */
|
#endif /* HAVE_EXPORT_KEYING_MATERIAL */
|
||||||
|
|
||||||
void
|
|
||||||
key_state_export_keying_material(struct key_state_ssl *ssl,
|
|
||||||
struct tls_session *session)
|
|
||||||
{
|
|
||||||
if (ssl->exported_key_material)
|
|
||||||
{
|
|
||||||
unsigned int size = session->opt->ekm_size;
|
|
||||||
struct gc_arena gc = gc_new();
|
|
||||||
unsigned int len = (size * 2) + 2;
|
|
||||||
|
|
||||||
const char *key = format_hex_ex(ssl->exported_key_material,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
|
tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags)
|
||||||
{
|
{
|
||||||
@ -1178,7 +1181,7 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
|
|||||||
{
|
{
|
||||||
if (ks_ssl)
|
if (ks_ssl)
|
||||||
{
|
{
|
||||||
free(ks_ssl->exported_key_material);
|
CLEAR(ks_ssl->tls_key_cache);
|
||||||
|
|
||||||
if (ks_ssl->ctx)
|
if (ks_ssl->ctx)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,15 @@ struct external_context {
|
|||||||
void *sign_ctx;
|
void *sign_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** struct to cache TLS secrets for keying material exporter (RFC 5705).
|
||||||
|
* The constants (64 and 48) are inherent to TLS version and
|
||||||
|
* the whole keying material export will likely change when they change */
|
||||||
|
struct tls_key_cache {
|
||||||
|
unsigned char client_server_random[64];
|
||||||
|
mbedtls_tls_prf_types tls_prf_type;
|
||||||
|
unsigned char master_secret[48];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure that wraps the TLS context. Contents differ depending on the
|
* Structure that wraps the TLS context. Contents differ depending on the
|
||||||
* SSL library used.
|
* SSL library used.
|
||||||
@ -114,8 +123,7 @@ struct key_state_ssl {
|
|||||||
mbedtls_ssl_context *ctx; /**< mbedTLS connection context */
|
mbedtls_ssl_context *ctx; /**< mbedTLS connection context */
|
||||||
bio_ctx *bio_ctx;
|
bio_ctx *bio_ctx;
|
||||||
|
|
||||||
/** Keying material exporter cache (RFC 5705). */
|
struct tls_key_cache tls_key_cache;
|
||||||
uint8_t *exported_key_material;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -158,35 +158,26 @@ tls_ctx_initialised(struct tls_root_ctx *ctx)
|
|||||||
return NULL != ctx->ctx;
|
return NULL != ctx->ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
unsigned char*
|
||||||
key_state_export_keying_material(struct key_state_ssl *ssl,
|
key_state_export_keying_material(struct tls_session *session,
|
||||||
struct tls_session *session)
|
const char* label, size_t label_size,
|
||||||
|
size_t ekm_size,
|
||||||
|
struct gc_arena *gc)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (session->opt->ekm_size > 0)
|
unsigned char *ekm = (unsigned char *) gc_malloc(ekm_size, true, gc);
|
||||||
|
|
||||||
|
SSL* ssl = session->key[KS_PRIMARY].ks_ssl.ssl;
|
||||||
|
|
||||||
|
if (SSL_export_keying_material(ssl, ekm, ekm_size, label,
|
||||||
|
label_size, NULL, 0, 0) == 1)
|
||||||
{
|
{
|
||||||
unsigned int size = session->opt->ekm_size;
|
return ekm;
|
||||||
struct gc_arena gc = gc_new();
|
}
|
||||||
unsigned char *ekm = (unsigned char *) gc_malloc(size, true, &gc);
|
else
|
||||||
|
{
|
||||||
if (SSL_export_keying_material(ssl->ssl, ekm, size,
|
secure_memzero(ekm, ekm_size);
|
||||||
session->opt->ekm_label,
|
return NULL;
|
||||||
session->opt->ekm_label_size,
|
|
||||||
NULL, 0, 0))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg(M_WARN, "WARNING: Export keying material failed!");
|
|
||||||
setenv_del(session->opt->es, "exported_keying_material");
|
|
||||||
}
|
|
||||||
gc_free(&gc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user