rtspsrc: create and send the RTCP encryption key

Create and make a key for encrypting the RTCP packets back to the server
and wrap this in a MIKEY message that we send as a header in the SETUP
request.
This commit is contained in:
Wim Taymans 2014-03-25 17:47:49 +01:00
parent a52b7eadfd
commit 2edd450369
2 changed files with 124 additions and 2 deletions

View file

@ -1517,6 +1517,7 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
}
if (stream->channelpad[i])
gst_object_unref (stream->channelpad[i]);
if (stream->udpsink[i]) {
gst_element_set_state (stream->udpsink[i], GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (src), stream->udpsink[i]);
@ -1533,12 +1534,16 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
if (stream->added)
gst_element_remove_pad (GST_ELEMENT_CAST (src), stream->srcpad);
}
if (stream->srtpenc)
gst_object_unref (stream->srtpenc);
if (stream->srtpdec)
gst_object_unref (stream->srtpdec);
if (stream->key)
gst_buffer_unref (stream->key);
if (stream->rtcppad)
gst_object_unref (stream->rtcppad);
if (stream->session)
g_object_unref (stream->session);
if (stream->srtpdec)
gst_object_unref (stream->srtpdec);
g_free (stream);
}
@ -2955,6 +2960,7 @@ request_key (GstElement * srtpdec, guint ssrc, GstRTSPStream * stream)
static GstElement *
request_rtp_decoder (GstElement * rtpbin, guint session, GstRTSPStream * stream)
{
GST_DEBUG ("decoder session %u, stream %p, %d", session, stream, stream->id);
if (stream->id != session)
return NULL;
@ -2975,6 +2981,38 @@ request_rtp_decoder (GstElement * rtpbin, guint session, GstRTSPStream * stream)
return gst_object_ref (stream->srtpdec);
}
static GstElement *
request_rtcp_encoder (GstElement * rtpbin, guint session,
GstRTSPStream * stream)
{
gchar *name;
GstPad *pad;
GST_DEBUG ("decoder session %u, stream %p, %d", session, stream, stream->id);
if (stream->id != session)
return NULL;
if (stream->profile != GST_RTSP_PROFILE_SAVP &&
stream->profile != GST_RTSP_PROFILE_SAVPF)
return NULL;
if (stream->srtpenc == NULL) {
name = g_strdup_printf ("srtpenc_%u", session);
stream->srtpenc = gst_element_factory_make ("srtpenc", name);
g_free (name);
/* key has been made before */
g_object_set (stream->srtpenc, "key", stream->key, NULL);
}
name = g_strdup_printf ("rtcp_sink_%d", session);
pad = gst_element_get_request_pad (stream->srtpenc, name);
g_free (name);
gst_object_unref (pad);
return gst_object_ref (stream->srtpenc);
}
/* try to get and configure a manager */
static gboolean
gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
@ -3074,6 +3112,8 @@ gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
(GCallback) request_rtp_decoder, stream);
g_signal_connect (src->manager, "request-rtcp-decoder",
(GCallback) request_rtp_decoder, stream);
g_signal_connect (src->manager, "request-rtcp-encoder",
(GCallback) request_rtcp_encoder, stream);
/* we stream directly to the manager, get some pads. Each RTSP stream goes
* into a separate RTP session. */
@ -5762,6 +5802,79 @@ failed:
}
}
static gchar *
gst_rtspsrc_stream_make_keymgmt (GstRTSPSrc * src, GstRTSPStream * stream)
{
GBytes *bytes;
gchar *result, *base64;
guint8 *key_data;
const guint8 *data;
gsize size;
guint i;
GstMIKEYMessage *msg;
GstMIKEYPayload *payload;
guint8 byte;
#define KEY_SIZE 30
key_data = g_malloc (KEY_SIZE);
for (i = 0; i < KEY_SIZE; i += 4)
GST_WRITE_UINT32_BE (key_data + i, g_random_int ());
if (stream->key)
gst_buffer_unref (stream->key);
stream->key = gst_buffer_new_wrapped (key_data, KEY_SIZE);
msg = gst_mikey_message_new ();
/* unencrypted MIKEY message, we send this over TLS so this is allowed */
gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT,
FALSE, GST_MIKEY_PRF_MIKEY_1, 0, GST_MIKEY_MAP_TYPE_SRTP);
/* add policy '0' for our SSRC */
gst_mikey_message_add_cs_srtp (msg, 0, stream->ssrc, 0);
/* timestamp is now */
gst_mikey_message_add_t_now_ntp_utc (msg);
/* add some random data */
gst_mikey_message_add_rand_len (msg, 16);
/* the policy '0' is SRTP */
payload = gst_mikey_payload_new (GST_MIKEY_PT_SP);
gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP);
/* only AES-CM is supported */
byte = 1;
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte);
/* only HMAC-SHA1 */
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1,
&byte);
/* we enable encryption on RTP and RTCP */
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1,
&byte);
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1,
&byte);
/* we enable authentication on RTP and RTCP */
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1,
&byte);
gst_mikey_message_add_payload (msg, payload);
/* add the key in KEMAC */
gst_mikey_message_add_kemac (msg, GST_MIKEY_ENC_NULL, KEY_SIZE, key_data,
GST_MIKEY_MAC_NULL, NULL);
/* now serialize this to bytes */
bytes = gst_mikey_message_to_bytes (msg);
gst_mikey_message_free (msg);
/* and make it into base64 */
data = g_bytes_get_data (bytes, &size);
base64 = g_base64_encode (data, size);
g_bytes_unref (bytes);
result = g_strdup_printf ("prot=mikey; uri=\"%s\"; data=\"%s\"",
stream->conninfo.location, base64);
g_free (base64);
return result;
}
/* Perform the SETUP request for all the streams.
*
* We ask the server for a specific transport, which initially includes all the
@ -5939,6 +6052,13 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
/* select transport */
gst_rtsp_message_take_header (&request, GST_RTSP_HDR_TRANSPORT, transports);
/* set up keys */
if (stream->profile == GST_RTSP_PROFILE_SAVP ||
stream->profile == GST_RTSP_PROFILE_SAVPF) {
hval = gst_rtspsrc_stream_make_keymgmt (src, stream);
gst_rtsp_message_take_header (&request, GST_RTSP_HDR_KEYMGMT, hval);
}
/* if the user wants a non default RTP packet size we add the blocksize
* parameter */
if (src->rtp_blocksize > 0) {

View file

@ -137,6 +137,8 @@ struct _GstRTSPStream {
guint32 seqbase;
guint64 timebase;
GstElement *srtpdec;
GstBuffer *key;
GstElement *srtpenc;
/* per stream connection */
GstRTSPConnInfo conninfo;