From 4ee52510ba8a6362afb3540645eccfac79bf3748 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 2 Nov 2012 00:04:08 +0100 Subject: Added gnutls_srtp_get_keys(). --- lib/ext/srtp.c | 115 +++++++++++++++++++++++++++++++++++++--- lib/includes/gnutls/gnutls.h.in | 7 +++ lib/libgnutls.map | 1 + tests/mini-dtls-srtp.c | 58 +++++++++++++++++--- 4 files changed, 166 insertions(+), 15 deletions(-) diff --git a/lib/ext/srtp.c b/lib/ext/srtp.c index f0512cefb4..e9899112aa 100644 --- a/lib/ext/srtp.c +++ b/lib/ext/srtp.c @@ -55,31 +55,49 @@ typedef struct { const char *name; gnutls_srtp_profile_t id; + unsigned int key_length; + unsigned int salt_length; } srtp_profile_st; static const srtp_profile_st profile_names[] = { { "SRTP_AES128_CM_SHA1_80", GNUTLS_SRTP_AES128_CM_SHA1_80, + 16,14 }, { "SRTP_AES128_CM_SHA1_32", GNUTLS_SRTP_AES128_CM_SHA1_32, + 16,14 }, { "SRTP_NULL_SHA1_80", GNUTLS_SRTP_NULL_SHA1_80, + 16,14 }, { "SRTP_NULL_SHA1_32", GNUTLS_SRTP_NULL_SHA1_32, + 16,14 }, { NULL, - 0 + 0,0,0 } }; +static const srtp_profile_st *get_profile (gnutls_srtp_profile_t profile) +{ + const srtp_profile_st *p = profile_names; + while (p->name != NULL) + { + if (p->id == profile) + return p; + p++; + } + return NULL; +} + static gnutls_srtp_profile_t find_profile (const char *str, const char *end) { const srtp_profile_st *prof = profile_names; @@ -141,13 +159,11 @@ int gnutls_srtp_get_profile_id (const char *name, **/ const char *gnutls_srtp_get_profile_name (gnutls_srtp_profile_t profile) { - const srtp_profile_st *p = profile_names; - while (p->name != NULL) - { - if (p->id == profile) - return p->name; - p++; - } + const srtp_profile_st *p = get_profile(profile); + + if (p != NULL) + return p->name; + return NULL; } @@ -419,6 +435,89 @@ gnutls_srtp_set_profile_direct (gnutls_session_t session, return 0; } +/** + * gnutls_srtp_get_keys: + * @session: is a #gnutls_session_t structure. + * @key_material: Space to hold the generated key material + * @key_material_size: The maximum size of the key material + * @client_key: The master client write key, pointing inside the key material + * @server_key: The master server write key, pointing inside the key material + * @client_salt: The master client write salt, pointing inside the key material + * @server_salt: The master server write salt, pointing inside the key material + * + * This is a helper function to generate the keying material for SRTP. + * It requires the space of the key material to be pre-allocated (should be at least + * 2x the maximum key size and salt size). The @client_key, @client_salt, @server_key + * and @server_salt are convenience datums that point inside the key material. The may + * be %NULL. + * + * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not sufficient, + * %GNUTLS_E_SUCCESS on success, or an error code. + * + * Since 3.1.4 + **/ +int +gnutls_srtp_get_keys (gnutls_session_t session, + void *key_material, + unsigned int key_material_size, + gnutls_datum_t *client_key, + gnutls_datum_t *client_salt, + gnutls_datum_t *server_key, + gnutls_datum_t *server_salt) +{ +int ret; +const srtp_profile_st *p; +gnutls_srtp_profile_t profile; +unsigned int msize; +uint8_t *km = key_material; + + ret = gnutls_srtp_get_selected_profile (session, &profile); + if (ret < 0) + return gnutls_assert_val(ret); + + p = get_profile(profile); + if (p == NULL) + return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM); + + msize = 2*(p->key_length+p->salt_length); + if (msize > key_material_size) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + + if (msize == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = gnutls_prf(session, sizeof("EXTRACTOR-dtls_srtp")-1, "EXTRACTOR-dtls_srtp", 0, 0, + NULL, msize, key_material); + if (ret < 0) + return gnutls_assert_val(ret); + + if (client_key) + { + client_key->data = km; + client_key->size = p->key_length; + } + + if (server_key) + { + server_key->data = km + p->key_length; + server_key->size = p->key_length; + } + + if (client_salt) + { + client_salt->data = km + 2*p->key_length; + client_salt->size = p->salt_length; + } + + if (server_salt) + { + server_salt->data = km + 2*p->key_length + p->salt_length; + server_salt->size = p->salt_length; + } + + return 0; +} + static void _gnutls_srtp_deinit_data (extension_priv_data_t priv) { diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 60726d0d1b..a64db31fe3 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -992,6 +992,13 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); const char *gnutls_srtp_get_profile_name (gnutls_srtp_profile_t profile); int gnutls_srtp_get_profile_id (const char *name, gnutls_srtp_profile_t *profile); + int gnutls_srtp_get_keys (gnutls_session_t session, + void *key_material, + unsigned int key_material_size, + gnutls_datum_t *client_key, + gnutls_datum_t *client_salt, + gnutls_datum_t *server_key, + gnutls_datum_t *server_salt); int gnutls_key_generate (gnutls_datum_t * key, unsigned int key_size); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 635e58a181..2843f26cd3 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -866,6 +866,7 @@ GNUTLS_3_1_0 { gnutls_srtp_get_selected_profile; gnutls_srtp_set_profile; gnutls_srtp_set_profile_direct; + gnutls_srtp_get_keys; } GNUTLS_3_0_0; GNUTLS_PRIVATE { diff --git a/tests/mini-dtls-srtp.c b/tests/mini-dtls-srtp.c index 8f41d619e4..76edfdf558 100644 --- a/tests/mini-dtls-srtp.c +++ b/tests/mini-dtls-srtp.c @@ -69,7 +69,8 @@ client_log_func (int level, const char *str) /* These are global */ static pid_t child; -/* A very basic DTLS client, with anonymous authentication, that exchanges heartbeats. +#define MAX_KEY_MATERIAL 64*4 +/* A very basic DTLS client, with anonymous authentication, that negotiates SRTP */ static void @@ -78,6 +79,9 @@ client (int fd, int profile) gnutls_session_t session; int ret; gnutls_anon_client_credentials_t anoncred; + uint8_t km[MAX_KEY_MATERIAL]; + char buf[2*MAX_KEY_MATERIAL]; + gnutls_datum_t cli_key, cli_salt, server_key, server_salt; /* Need to enable anonymous KX specifically. */ gnutls_global_init (); @@ -144,14 +148,33 @@ client (int fd, int profile) gnutls_protocol_get_name (gnutls_protocol_get_version (session))); -/* - ret = gnutls_prf(session, sizeof("EXTRACTOR-dtls_srtp")-1, "EXTRACTOR-dtls_srtp", 0, ctx_len, ctx, 32, out); + ret = gnutls_srtp_get_keys (session, km, sizeof(km), &cli_key, &cli_salt, &server_key, &server_salt); if (ret < 0) { gnutls_perror(ret); exit(1); } -*/ + + if (debug) + { + size_t size = sizeof(buf); + gnutls_hex_encode(&cli_key, buf, &size); + success ("Client key: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&cli_salt, buf, &size); + success ("Client salt: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&server_key, buf, &size); + success ("Server key: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&server_salt, buf, &size); + success ("Server salt: %s\n", buf); + } + + gnutls_bye (session, GNUTLS_SHUT_WR); close (fd); @@ -179,6 +202,10 @@ server (int fd, int profile) int ret; gnutls_session_t session; gnutls_anon_server_credentials_t anoncred; + uint8_t km[MAX_KEY_MATERIAL]; + char buf[2*MAX_KEY_MATERIAL]; + gnutls_datum_t cli_key, cli_salt, server_key, server_salt; + /* this must be called once in the program */ gnutls_global_init (); @@ -239,14 +266,31 @@ server (int fd, int profile) gnutls_protocol_get_name (gnutls_protocol_get_version (session))); -/* - ret = gnutls_prf(session, sizeof("EXTRACTOR-dtls_srtp")-1, "EXTRACTOR-dtls_srtp", 0, ctx_len, ctx, 32, out); + ret = gnutls_srtp_get_keys (session, km, sizeof(km), &cli_key, &cli_salt, &server_key, &server_salt); if (ret < 0) { gnutls_perror(ret); exit(1); } -*/ + + if (debug) + { + size_t size = sizeof(buf); + gnutls_hex_encode(&cli_key, buf, &size); + success ("Client key: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&cli_salt, buf, &size); + success ("Client salt: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&server_key, buf, &size); + success ("Server key: %s\n", buf); + + size = sizeof(buf); + gnutls_hex_encode(&server_salt, buf, &size); + success ("Server salt: %s\n", buf); + } /* do not wait for the peer to close the connection. */ -- cgit v1.2.1