mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
srtpdec: Add support for MKI
Add support for MKIs which allow multiple keys to be used with a single SRTP stream. https://bugzilla.gnome.org/show_bug.cgi?id=797305
This commit is contained in:
parent
5b179991bc
commit
46b5756d30
1 changed files with 212 additions and 21 deletions
|
@ -96,6 +96,13 @@
|
||||||
* other means. If no rollover counter is provided by the user, 0 is
|
* other means. If no rollover counter is provided by the user, 0 is
|
||||||
* used by default.
|
* used by default.
|
||||||
*
|
*
|
||||||
|
* It is possible to receive a stream protected by multiple master keys, each buffer
|
||||||
|
* then contains a Master Key Identifier (MKI) to identify which key was used for this
|
||||||
|
* buffer. If multiple keys are needed, the first key can be specified in the caps as
|
||||||
|
* "srtp-key=(buffer)key1data, mki=(buffer)mki1data", then the second one can be given in
|
||||||
|
* the same caps as "srtp-key2=(buffer)key2data, mki2=(buffer)mki2data", and more can
|
||||||
|
* be added up to 15.
|
||||||
|
*
|
||||||
* ## Example pipelines
|
* ## Example pipelines
|
||||||
* |[
|
* |[
|
||||||
* gst-launch-1.0 udpsrc port=5004 caps='application/x-srtp, payload=(int)8, ssrc=(uint)1356955624, srtp-key=(buffer)012345678901234567890123456789012345678901234567890123456789, srtp-cipher=(string)aes-128-icm, srtp-auth=(string)hmac-sha1-80, srtcp-cipher=(string)aes-128-icm, srtcp-auth=(string)hmac-sha1-80' ! srtpdec ! rtppcmadepay ! alawdec ! pulsesink
|
* gst-launch-1.0 udpsrc port=5004 caps='application/x-srtp, payload=(int)8, ssrc=(uint)1356955624, srtp-key=(buffer)012345678901234567890123456789012345678901234567890123456789, srtp-cipher=(string)aes-128-icm, srtp-auth=(string)hmac-sha1-80, srtcp-cipher=(string)aes-128-icm, srtcp-auth=(string)hmac-sha1-80' ! srtpdec ! rtppcmadepay ! alawdec ! pulsesink
|
||||||
|
@ -217,8 +224,17 @@ struct _GstSrtpDecSsrcStream
|
||||||
GstSrtpAuthType rtp_auth;
|
GstSrtpAuthType rtp_auth;
|
||||||
GstSrtpCipherType rtcp_cipher;
|
GstSrtpCipherType rtcp_cipher;
|
||||||
GstSrtpAuthType rtcp_auth;
|
GstSrtpAuthType rtcp_auth;
|
||||||
|
GArray *keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
struct GstSrtpDecKey
|
||||||
|
{
|
||||||
|
GstBuffer *mki;
|
||||||
|
GstBuffer *key;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STREAM_HAS_CRYPTO(stream) \
|
#define STREAM_HAS_CRYPTO(stream) \
|
||||||
(stream->rtp_cipher != GST_SRTP_CIPHER_NULL || \
|
(stream->rtp_cipher != GST_SRTP_CIPHER_NULL || \
|
||||||
stream->rtcp_cipher != GST_SRTP_CIPHER_NULL || \
|
stream->rtcp_cipher != GST_SRTP_CIPHER_NULL || \
|
||||||
|
@ -512,6 +528,17 @@ find_stream_by_ssrc (GstSrtpDec * filter, guint32 ssrc)
|
||||||
return g_hash_table_lookup (filter->streams, GUINT_TO_POINTER (ssrc));
|
return g_hash_table_lookup (filter->streams, GUINT_TO_POINTER (ssrc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
static void
|
||||||
|
clear_key (gpointer data)
|
||||||
|
{
|
||||||
|
struct GstSrtpDecKey *key = data;
|
||||||
|
|
||||||
|
gst_clear_buffer (&key->mki);
|
||||||
|
gst_clear_buffer (&key->key);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* get info from buffer caps
|
/* get info from buffer caps
|
||||||
*/
|
*/
|
||||||
|
@ -565,8 +592,62 @@ get_stream_from_caps (GstSrtpDec * filter, GstCaps * caps, guint32 ssrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gst_structure_get (s, "srtp-key", GST_TYPE_BUFFER, &buf, NULL) || !buf) {
|
if (gst_structure_get (s, "srtp-key", GST_TYPE_BUFFER, &buf, NULL) || !buf) {
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
GstBuffer *mki = NULL;
|
||||||
|
guint i;
|
||||||
|
gsize mki_size = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (filter, "Got key [%p] for SSRC %u", buf, ssrc);
|
GST_DEBUG_OBJECT (filter, "Got key [%p] for SSRC %u", buf, ssrc);
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
if (gst_structure_get (s, "mki", GST_TYPE_BUFFER, &mki, NULL) && mki) {
|
||||||
|
struct GstSrtpDecKey key = {.mki = mki,.key = buf };
|
||||||
|
|
||||||
|
mki_size = gst_buffer_get_size (mki);
|
||||||
|
if (mki_size > SRTP_MAX_MKI_LEN) {
|
||||||
|
GST_WARNING_OBJECT (filter, "MKI is longer than allowed (%zu > %d).",
|
||||||
|
mki_size, SRTP_MAX_MKI_LEN);
|
||||||
|
gst_buffer_unref (mki);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->keys =
|
||||||
|
g_array_sized_new (FALSE, TRUE, sizeof (struct GstSrtpDecKey), 2);
|
||||||
|
g_array_set_clear_func (stream->keys, clear_key);
|
||||||
|
|
||||||
|
g_array_append_val (stream->keys, key);
|
||||||
|
|
||||||
|
/* Append more MKIs */
|
||||||
|
for (i = 1; i < SRTP_MAX_NUM_MASTER_KEYS; i++) {
|
||||||
|
char mki_id[16];
|
||||||
|
char key_id[16];
|
||||||
|
g_snprintf (mki_id, 16, "mki%d", i + 1);
|
||||||
|
g_snprintf (key_id, 16, "srtp-key%d", i + 1);
|
||||||
|
|
||||||
|
if (gst_structure_get (s, mki_id, GST_TYPE_BUFFER, &mki,
|
||||||
|
key_id, GST_TYPE_BUFFER, &buf, NULL)) {
|
||||||
|
if (gst_buffer_get_size (mki) != mki_size) {
|
||||||
|
GST_WARNING_OBJECT (filter,
|
||||||
|
"MKIs need to all have the same size (first was %zu,"
|
||||||
|
" current is %zu).", mki_size, gst_buffer_get_size (mki));
|
||||||
|
gst_buffer_unref (mki);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
key.mki = mki;
|
||||||
|
key.key = buf;
|
||||||
|
g_array_append_val (stream->keys, key);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
stream->key = buf;
|
stream->key = buf;
|
||||||
|
}
|
||||||
} else if (STREAM_HAS_CRYPTO (stream)) {
|
} else if (STREAM_HAS_CRYPTO (stream)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -603,6 +684,10 @@ init_session_stream (GstSrtpDec * filter, guint32 ssrc,
|
||||||
srtp_policy_t policy;
|
srtp_policy_t policy;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
guchar tmp[1];
|
guchar tmp[1];
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
GstMapInfo *key_maps = NULL;
|
||||||
|
GstMapInfo *mki_maps = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
memset (&policy, 0, sizeof (srtp_policy_t));
|
memset (&policy, 0, sizeof (srtp_policy_t));
|
||||||
|
|
||||||
|
@ -616,6 +701,31 @@ init_session_stream (GstSrtpDec * filter, guint32 ssrc,
|
||||||
set_crypto_policy_cipher_auth (stream->rtcp_cipher, stream->rtcp_auth,
|
set_crypto_policy_cipher_auth (stream->rtcp_cipher, stream->rtcp_auth,
|
||||||
&policy.rtcp);
|
&policy.rtcp);
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
if (stream->keys) {
|
||||||
|
guint i;
|
||||||
|
srtp_master_key_t *keys;
|
||||||
|
|
||||||
|
keys = g_alloca (sizeof (srtp_master_key_t) * stream->keys->len);
|
||||||
|
policy.keys = g_alloca (sizeof (gpointer) * stream->keys->len);
|
||||||
|
key_maps = g_alloca (sizeof (GstMapInfo) * stream->keys->len);
|
||||||
|
mki_maps = g_alloca (sizeof (GstMapInfo) * stream->keys->len);
|
||||||
|
|
||||||
|
for (i = 0; i < stream->keys->len; i++) {
|
||||||
|
struct GstSrtpDecKey *key =
|
||||||
|
&g_array_index (stream->keys, struct GstSrtpDecKey, i);
|
||||||
|
policy.keys[i] = &keys[i];
|
||||||
|
|
||||||
|
gst_buffer_map (key->mki, &mki_maps[i], GST_MAP_READ);
|
||||||
|
gst_buffer_map (key->key, &key_maps[i], GST_MAP_READ);
|
||||||
|
|
||||||
|
policy.keys[i]->key = (guchar *) key_maps[i].data;
|
||||||
|
policy.keys[i]->mki_id = (guchar *) mki_maps[i].data;
|
||||||
|
policy.keys[i]->mki_size = mki_maps[i].size;
|
||||||
|
}
|
||||||
|
policy.num_master_keys = stream->keys->len;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if (stream->key) {
|
if (stream->key) {
|
||||||
gst_buffer_map (stream->key, &map, GST_MAP_READ);
|
gst_buffer_map (stream->key, &map, GST_MAP_READ);
|
||||||
policy.key = (guchar *) map.data;
|
policy.key = (guchar *) map.data;
|
||||||
|
@ -639,6 +749,20 @@ init_session_stream (GstSrtpDec * filter, guint32 ssrc,
|
||||||
if (stream->key)
|
if (stream->key)
|
||||||
gst_buffer_unmap (stream->key, &map);
|
gst_buffer_unmap (stream->key, &map);
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
if (key_maps) {
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < stream->keys->len; i++) {
|
||||||
|
struct GstSrtpDecKey *key = &g_array_index (stream->keys,
|
||||||
|
struct GstSrtpDecKey, i);
|
||||||
|
gst_buffer_unmap (key->mki, &mki_maps[i]);
|
||||||
|
gst_buffer_unmap (key->key, &key_maps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ret == srtp_err_status_ok) {
|
if (ret == srtp_err_status_ok) {
|
||||||
srtp_err_status_t status;
|
srtp_err_status_t status;
|
||||||
|
|
||||||
|
@ -706,9 +830,71 @@ free_stream (GstSrtpDecSsrcStream * stream)
|
||||||
{
|
{
|
||||||
if (stream->key)
|
if (stream->key)
|
||||||
gst_buffer_unref (stream->key);
|
gst_buffer_unref (stream->key);
|
||||||
|
if (stream->keys)
|
||||||
|
g_array_free (stream->keys, TRUE);
|
||||||
g_slice_free (GstSrtpDecSsrcStream, stream);
|
g_slice_free (GstSrtpDecSsrcStream, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
buffers_are_equal (GstBuffer * a, GstBuffer * b)
|
||||||
|
{
|
||||||
|
GstMapInfo info;
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (a == NULL || b == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (gst_buffer_get_size (a) != gst_buffer_get_size (b))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (gst_buffer_map (a, &info, GST_MAP_READ)) {
|
||||||
|
gboolean equal;
|
||||||
|
|
||||||
|
equal = (gst_buffer_memcmp (b, 0, info.data, info.size) == 0);
|
||||||
|
gst_buffer_unmap (a, &info);
|
||||||
|
|
||||||
|
return equal;
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
keys_are_equal (GArray * a, GArray * b)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (a == NULL || b == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (a->len != b->len)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < a->len; i++) {
|
||||||
|
struct GstSrtpDecKey *key_a = &g_array_index (a,
|
||||||
|
struct GstSrtpDecKey, i);
|
||||||
|
struct GstSrtpDecKey *key_b = &g_array_index (b,
|
||||||
|
struct GstSrtpDecKey, i);
|
||||||
|
|
||||||
|
if (!buffers_are_equal (key_a->mki, key_b->mki))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!buffers_are_equal (key_a->key, key_b->key))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
#else
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Create new stream from params in caps
|
/* Create new stream from params in caps
|
||||||
*/
|
*/
|
||||||
static GstSrtpDecSsrcStream *
|
static GstSrtpDecSsrcStream *
|
||||||
|
@ -730,23 +916,11 @@ update_session_stream_from_caps (GstSrtpDec * filter, guint32 ssrc,
|
||||||
stream->rtcp_cipher == old_stream->rtcp_cipher &&
|
stream->rtcp_cipher == old_stream->rtcp_cipher &&
|
||||||
stream->rtp_auth == old_stream->rtp_auth &&
|
stream->rtp_auth == old_stream->rtp_auth &&
|
||||||
stream->rtcp_auth == old_stream->rtcp_auth &&
|
stream->rtcp_auth == old_stream->rtcp_auth &&
|
||||||
stream->key && old_stream->key &&
|
((stream->keys && keys_are_equal (stream->keys, old_stream->keys)) ||
|
||||||
gst_buffer_get_size (stream->key) ==
|
buffers_are_equal (stream->key, old_stream->key))) {
|
||||||
gst_buffer_get_size (old_stream->key)) {
|
|
||||||
GstMapInfo info;
|
|
||||||
|
|
||||||
if (gst_buffer_map (old_stream->key, &info, GST_MAP_READ)) {
|
|
||||||
gboolean equal;
|
|
||||||
|
|
||||||
equal = (gst_buffer_memcmp (stream->key, 0, info.data, info.size) == 0);
|
|
||||||
gst_buffer_unmap (old_stream->key, &info);
|
|
||||||
|
|
||||||
if (equal) {
|
|
||||||
free_stream (stream);
|
free_stream (stream);
|
||||||
return old_stream;
|
return old_stream;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove existing stream, if any */
|
/* Remove existing stream, if any */
|
||||||
gst_srtp_dec_remove_stream (filter, ssrc);
|
gst_srtp_dec_remove_stream (filter, ssrc);
|
||||||
|
@ -853,7 +1027,7 @@ gst_srtp_dec_sink_setcaps (GstPad * pad, GstObject * parent,
|
||||||
caps = gst_caps_copy (caps);
|
caps = gst_caps_copy (caps);
|
||||||
ps = gst_caps_get_structure (caps, 0);
|
ps = gst_caps_get_structure (caps, 0);
|
||||||
gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher", "srtp-auth",
|
gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher", "srtp-auth",
|
||||||
"srtcp-cipher", "srtcp-auth", NULL);
|
"srtcp-cipher", "srtcp-auth", "mki", NULL);
|
||||||
|
|
||||||
if (is_rtcp)
|
if (is_rtcp)
|
||||||
gst_structure_set_name (ps, "application/x-rtcp");
|
gst_structure_set_name (ps, "application/x-rtcp");
|
||||||
|
@ -967,7 +1141,7 @@ gst_srtp_dec_sink_query (GstPad * pad, GstObject * parent, GstQuery * query,
|
||||||
else
|
else
|
||||||
gst_structure_set_name (ps, "application/x-rtp");
|
gst_structure_set_name (ps, "application/x-rtp");
|
||||||
gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher",
|
gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher",
|
||||||
"srtp-auth", "srtcp-cipher", "srtcp-auth", NULL);
|
"srtp-auth", "srtcp-cipher", "srtcp-auth", "mki", NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1159,9 +1333,16 @@ unprotect:
|
||||||
|
|
||||||
gst_srtp_init_event_reporter ();
|
gst_srtp_init_event_reporter ();
|
||||||
|
|
||||||
if (is_rtcp)
|
if (is_rtcp) {
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
GstSrtpDecSsrcStream *stream = find_stream_by_ssrc (filter, ssrc);
|
||||||
|
|
||||||
|
err = srtp_unprotect_rtcp_mki (filter->session, map.data, &size,
|
||||||
|
stream && stream->keys);
|
||||||
|
#else
|
||||||
err = srtp_unprotect_rtcp (filter->session, map.data, &size);
|
err = srtp_unprotect_rtcp (filter->session, map.data, &size);
|
||||||
else {
|
#endif
|
||||||
|
} else {
|
||||||
#ifndef HAVE_SRTP2
|
#ifndef HAVE_SRTP2
|
||||||
/* If ROC has changed, we know we need to set the initial RTP
|
/* If ROC has changed, we know we need to set the initial RTP
|
||||||
* sequence number too. */
|
* sequence number too. */
|
||||||
|
@ -1188,7 +1369,17 @@ unprotect:
|
||||||
filter->roc_changed = FALSE;
|
filter->roc_changed = FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SRTP2
|
||||||
|
{
|
||||||
|
GstSrtpDecSsrcStream *stream = find_stream_by_ssrc (filter, ssrc);
|
||||||
|
|
||||||
|
err = srtp_unprotect_mki (filter->session, map.data, &size,
|
||||||
|
stream && stream->keys);
|
||||||
|
}
|
||||||
|
#else
|
||||||
err = srtp_unprotect (filter->session, map.data, &size);
|
err = srtp_unprotect (filter->session, map.data, &size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (filter);
|
GST_OBJECT_UNLOCK (filter);
|
||||||
|
|
Loading…
Reference in a new issue