summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ext/srtp.c115
-rw-r--r--lib/includes/gnutls/gnutls.h.in7
-rw-r--r--lib/libgnutls.map1
-rw-r--r--tests/mini-dtls-srtp.c58
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.
*/