diff --git a/ext/srtp/gstsrtpenc.c b/ext/srtp/gstsrtpenc.c index fffaebb296..5248c1f1aa 100644 --- a/ext/srtp/gstsrtpenc.c +++ b/ext/srtp/gstsrtpenc.c @@ -100,6 +100,10 @@ * the clients will start with a rollover counter of 0 which will * probably be incorrect if the stream has been transmitted for a * while to other clients. + * + * This element supports sending with a single Master Key, it is possible to set the + * Master Key Identifier (MKI) using the "mki" property. If this property is set, the MKI + * will be added to every buffer. */ #include "gstsrtpenc.h" @@ -152,7 +156,8 @@ enum PROP_RANDOM_KEY, PROP_REPLAY_WINDOW_SIZE, PROP_ALLOW_REPEAT_TX, - PROP_STATS + PROP_STATS, + PROP_MKI }; typedef struct ProcessBufferItData @@ -318,6 +323,13 @@ gst_srtp_enc_class_init (GstSrtpEncClass * klass) g_object_class_install_property (gobject_class, PROP_STATS, g_param_spec_boxed ("stats", "Statistics", "Various statistics", GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +#ifdef HAVE_SRTP2 + g_object_class_install_property (gobject_class, PROP_MKI, + g_param_spec_boxed ("mki", "MKI", + "Master key Identifier (NULL means no MKI)", GST_TYPE_BUFFER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_PLAYING)); +#endif /** * GstSrtpEnc::soft-limit: @@ -372,6 +384,12 @@ gst_srtp_enc_create_session (GstSrtpEnc * filter) srtp_policy_t policy; GstMapInfo map; guchar tmp[1]; +#ifdef HAVE_SRTP2 + srtp_master_key_t mkey; + srtp_master_key_t *mkey_ptr = &mkey; + gboolean has_mki = FALSE; + GstMapInfo mki_map; +#endif memset (&policy, 0, sizeof (srtp_policy_t)); @@ -416,6 +434,29 @@ gst_srtp_enc_create_session (GstSrtpEnc * filter) policy.key = tmp; } +#ifdef HAVE_SRTP2 + if (filter->mki) { + if (!gst_buffer_map (filter->mki, &mki_map, GST_MAP_READ)) { + GST_OBJECT_UNLOCK (filter); + GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS, ("Could not map MKI"), + (NULL)); + GST_OBJECT_LOCK (filter); + + ret = srtp_err_status_fail; + goto done; + } + has_mki = TRUE; + + policy.num_master_keys = 1; + policy.keys = &mkey_ptr; + mkey.key = policy.key; + policy.key = NULL; + + mkey.mki_id = (guchar *) mki_map.data; + mkey.mki_size = mki_map.size; + } +#endif + policy.ssrc.value = 0; policy.ssrc.type = ssrc_any_outbound; policy.next = NULL; @@ -429,9 +470,17 @@ gst_srtp_enc_create_session (GstSrtpEnc * filter) ret = srtp_create (&filter->session, &policy); filter->first_session = FALSE; +#ifdef HAVE_SRTP2 +done: + + if (has_mki) + gst_buffer_unmap (filter->mki, &mki_map); +#endif + if (HAS_CRYPTO (filter)) gst_buffer_unmap (filter->key, &map); + return ret; } @@ -595,9 +644,8 @@ gst_srtp_enc_dispose (GObject * object) } gst_iterator_free (it); - if (filter->key) - gst_buffer_unref (filter->key); - filter->key = NULL; + gst_buffer_replace (&filter->key, NULL); + gst_buffer_replace (&filter->mki, NULL); if (filter->ssrcs_set) g_hash_table_unref (filter->ssrcs_set); @@ -658,8 +706,7 @@ gst_srtp_enc_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_MKEY: - if (filter->key) - gst_buffer_unref (filter->key); + gst_clear_buffer (&filter->key); filter->key = g_value_dup_boxed (value); filter->key_changed = TRUE; GST_INFO_OBJECT (object, "Set property: key=[%p]", filter->key); @@ -697,7 +744,14 @@ gst_srtp_enc_set_property (GObject * object, guint prop_id, case PROP_ALLOW_REPEAT_TX: filter->allow_repeat_tx = g_value_get_boolean (value); break; - +#ifdef HAVE_SRTP2 + case PROP_MKI: + gst_clear_buffer (&filter->mki); + filter->mki = g_value_dup_boxed (value); + filter->key_changed = TRUE; + GST_INFO_OBJECT (object, "Set property: mki=[%p]", filter->mki); + break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -742,6 +796,12 @@ gst_srtp_enc_get_property (GObject * object, guint prop_id, case PROP_STATS: g_value_take_boxed (value, gst_srtp_enc_create_stats (filter)); break; +#ifdef HAVE_SRTP2 + case PROP_MKI: + if (filter->mki) + g_value_set_boxed (value, filter->mki); + break; +#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -816,6 +876,11 @@ gst_srtp_enc_sink_setcaps (GstPad * pad, GstSrtpEnc * filter, if (HAS_CRYPTO (filter)) gst_structure_set (ps, "srtp-key", GST_TYPE_BUFFER, filter->key, NULL); +#ifdef HAVE_SRTP2 + if (filter->mki) + gst_structure_set (ps, "mki", GST_TYPE_BUFFER, filter->mki, NULL); +#endif + /* Add srtp-specific params to source caps */ gst_structure_set (ps, "srtp-cipher", G_TYPE_STRING, @@ -894,7 +959,7 @@ gst_srtp_enc_sink_query (GstPad * pad, GstObject * parent, GstQuery * query, else gst_structure_set_name (ps, "application/x-rtp"); gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher", "srtp-auth", - "srtcp-cipher", "srtcp-auth", NULL); + "srtcp-cipher", "srtcp-auth", "mki", NULL); } gst_query_set_caps_result (query, ret); @@ -1059,11 +1124,19 @@ gst_srtp_enc_process_buffer (GstSrtpEnc * filter, GstPad * pad, ret = GST_FLOW_FLUSHING; goto fail; } - +#ifdef HAVE_SRTP2 + if (is_rtcp) + err = srtp_protect_rtcp_mki (filter->session, mapout.data, &size, + (filter->mki != NULL), 0); + else + err = srtp_protect_mki (filter->session, mapout.data, &size, + (filter->mki != NULL), 0); +#else if (is_rtcp) err = srtp_protect_rtcp (filter->session, mapout.data, &size); else err = srtp_protect (filter->session, mapout.data, &size); +#endif GST_OBJECT_UNLOCK (filter); diff --git a/ext/srtp/gstsrtpenc.h b/ext/srtp/gstsrtpenc.h index 5c64e0b3ee..df2f8fd300 100644 --- a/ext/srtp/gstsrtpenc.h +++ b/ext/srtp/gstsrtpenc.h @@ -76,6 +76,7 @@ struct _GstSrtpEnc guint rtp_auth; guint rtcp_cipher; guint rtcp_auth; + GstBuffer *mki; srtp_t session; gboolean first_session;