stream: add SRTP support

Install srtp encoder and decoder elements in rtpbin
Add MIKEY in SDP
This commit is contained in:
Wim Taymans 2014-03-13 17:35:21 +01:00
parent bfbf393925
commit 3d6175c745
5 changed files with 205 additions and 2 deletions

View file

@ -59,6 +59,7 @@ dnl *** required versions of GStreamer stuff ***
GST_REQ=1.3.0.1
GSTPB_REQ=1.3.0.1
GSTPG_REQ=1.3.0.1
GSTPD_REQ=1.3.0.1
dnl *** autotools stuff ****
@ -176,6 +177,11 @@ GSTPG_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-good-$GST_API_VERSION --variabl
AC_SUBST(GSTPG_PLUGINS_DIR)
AC_MSG_NOTICE(Using GStreamer Good Plugins in $GSTPG_PLUGINS_DIR)
AG_GST_CHECK_GST_PLUGINS_BAD($GST_API_VERSION, [$GSTPD_REQ], [yes])
GSTPD_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-bad-$GST_API_VERSION --variable pluginsdir`
AC_SUBST(GSTPD_PLUGINS_DIR)
AC_MSG_NOTICE(Using GStreamer Bad Plugins in $GSTPD_PLUGINS_DIR)
AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)
AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_GST_CHECK" = "xyes")

View file

@ -136,6 +136,7 @@ main (int argc, char *argv[])
gst_rtsp_media_factory_set_permissions (factory, permissions);
gst_rtsp_permissions_unref (permissions);
#endif
gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_SAVP);
/* attach the test factory to the /test url */
gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

View file

@ -26,6 +26,8 @@
#include <string.h>
#include <gst/sdp/gstmikey.h>
#include "rtsp-sdp.h"
static gboolean
@ -171,6 +173,93 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media,
gst_sdp_media_add_attribute (smedia, "control", tmp);
g_free (tmp);
/* check for srtp */
do {
GstBuffer *srtpkey;
const GValue *val;
const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth;
GstMIKEYMessage *msg;
GstMIKEYPayload *payload;
GBytes *bytes;
GstMapInfo info;
const guint8 *data;
gsize size;
gchar *base64;
guint8 byte;
guint32 ssrc;
val = gst_structure_get_value (s, "srtp-key");
if (val == NULL)
break;
srtpkey = gst_value_get_buffer (val);
if (srtpkey == NULL)
break;
srtpcipher = gst_structure_get_string (s, "srtp-cipher");
srtpauth = gst_structure_get_string (s, "srtp-auth");
srtcpcipher = gst_structure_get_string (s, "srtcp-cipher");
srtcpauth = gst_structure_get_string (s, "srtcp-auth");
if (srtpcipher == NULL || srtpauth == NULL || srtcpcipher == NULL ||
srtcpauth == NULL)
break;
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_rtsp_stream_get_ssrc (stream, &ssrc);
gst_mikey_message_add_cs_srtp (msg, 0, 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 with the above discovered algorithms */
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_buffer_map (srtpkey, &info, GST_MAP_READ);
gst_mikey_message_add_kemac (msg, GST_MIKEY_ENC_NULL, info.size, info.data,
GST_MIKEY_MAC_NULL, NULL);
gst_buffer_unmap (srtpkey, &info);
/* 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);
tmp = g_strdup_printf ("mikey %s", base64);
g_free (base64);
gst_sdp_media_add_attribute (smedia, "key-mgmt", tmp);
g_free (tmp);
} while (FALSE);
/* collect all other properties and add them to fmtp or attributes */
fmtp = g_string_new ("");
g_string_append_printf (fmtp, "%d ", caps_pt);
@ -198,6 +287,10 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPMedia * media,
continue;
if (!strcmp (fname, "seqnum-base"))
continue;
if (g_str_has_prefix (fname, "srtp-"))
continue;
if (g_str_has_prefix (fname, "srtcp-"))
continue;
if (g_str_has_prefix (fname, "a-")) {
/* attribute */

View file

@ -79,6 +79,10 @@ struct _GstRTSPStreamPrivate
/* the RTPSession object */
GObject *session;
/* SRTP encoder/decoder */
GstElement *srtpenc;
GstElement *srtpdec;
/* sinks used for sending and receiving RTP and RTCP over ipv4, they share
* sockets */
GstElement *udpsrc_v4[2];
@ -1503,6 +1507,87 @@ static GstAppSinkCallbacks sink_cb = {
handle_new_sample,
};
static GstElement *
get_rtp_encoder (GstRTSPStream * stream, guint session)
{
GstRTSPStreamPrivate *priv = stream->priv;
if (priv->srtpenc == NULL) {
gchar *name;
name = g_strdup_printf ("srtpenc_%u", session);
priv->srtpenc = gst_element_factory_make ("srtpenc", name);
g_free (name);
g_object_set (priv->srtpenc, "random-key", TRUE, NULL);
}
return gst_object_ref (priv->srtpenc);
}
static GstElement *
request_rtp_encoder (GstElement * rtpbin, guint session, GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv = stream->priv;
GstElement *enc;
GstPad *pad;
gchar *name;
if (priv->idx != session)
return NULL;
GST_DEBUG_OBJECT (stream, "make RTP encoder for session %u", session);
enc = get_rtp_encoder (stream, session);
name = g_strdup_printf ("rtp_sink_%d", session);
pad = gst_element_get_request_pad (enc, name);
g_free (name);
gst_object_unref (pad);
return enc;
}
static GstElement *
request_rtcp_encoder (GstElement * rtpbin, guint session,
GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv = stream->priv;
GstElement *enc;
GstPad *pad;
gchar *name;
if (priv->idx != session)
return NULL;
GST_DEBUG_OBJECT (stream, "make RTCP encoder for session %u", session);
enc = get_rtp_encoder (stream, session);
name = g_strdup_printf ("rtcp_sink_%d", session);
pad = gst_element_get_request_pad (enc, name);
g_free (name);
gst_object_unref (pad);
return enc;
}
static GstElement *
request_rtcp_decoder (GstElement * rtpbin, guint session,
GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv = stream->priv;
if (priv->idx != session)
return NULL;
if (priv->srtpdec == NULL) {
gchar *name;
name = g_strdup_printf ("srtpdec_%u", session);
priv->srtpdec = gst_element_factory_make ("srtpdec", name);
g_free (name);
}
return gst_object_ref (priv->srtpdec);
}
/**
* gst_rtsp_stream_join_bin:
* @stream: a #GstRTSPStream
@ -1549,6 +1634,21 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
/* update the dscp qos field in the sinks */
update_dscp_qos (stream);
if (priv->profiles & GST_RTSP_PROFILE_SAVP
|| priv->profiles & GST_RTSP_PROFILE_SAVPF) {
/* For SRTP */
g_signal_connect (rtpbin, "request-rtp-encoder",
(GCallback) request_rtp_encoder, stream);
g_signal_connect (rtpbin, "request-rtcp-encoder",
(GCallback) request_rtcp_encoder, stream);
#if 0
g_signal_connect (rtpbin, "request-rtp-decoder",
(GCallback) request_rtp_decoder, stream);
#endif
g_signal_connect (rtpbin, "request-rtcp-decoder",
(GCallback) request_rtcp_decoder, stream);
}
/* get a pad for sending RTP */
name = g_strdup_printf ("send_rtp_sink_%u", idx);
priv->send_rtp_sink = gst_element_get_request_pad (rtpbin, name);
@ -1873,6 +1973,9 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
gst_caps_unref (priv->caps);
priv->caps = NULL;
if (priv->srtpenc)
gst_object_unref (priv->srtpenc);
priv->is_joined = FALSE;
g_mutex_unlock (&priv->lock);

View file

@ -11,8 +11,8 @@ TESTS_ENVIRONMENT = \
GST_STATE_IGNORE_ELEMENTS="$(STATE_IGNORE_ELEMENTS)" \
$(REGISTRY_ENVIRONMENT) \
GST_PLUGIN_SYSTEM_PATH_1_0= \
GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR) \
GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good"
GST_PLUGIN_PATH_1_0=$(GST_PLUGINS_DIR):$(GSTPB_PLUGINS_DIR):$(GSTPG_PLUGINS_DIR):$(GSTPD_PLUGINS_DIR) \
GST_PLUGIN_LOADING_WHITELIST="gstreamer:gst-plugins-base:gst-plugins-good:gst-plugins-bad"
# ths core dumps of some machines have PIDs appended