srtp: add support for rollover counters and replay protection window size
authorAleix Conchillo Flaqué <aleix@oblong.com>
Sat, 22 Mar 2014 05:16:41 +0000 (22:16 -0700)
committerOlivier Crête <olivier.crete@collabora.com>
Tue, 3 Jun 2014 20:18:25 +0000 (16:18 -0400)
We add a new signal, get-rollover-counter, to the SRTP encoder. Given a
ssrc the signal will return the currently internal SRTP rollover counter
for the given stream.

For the SRTP decoder we have a new SRTP caps parameter "roc" that needs
to be set when a new SRTP stream is created for a given SSRC.

https://bugzilla.gnome.org/show_bug.cgi?id=726861

ext/srtp/gstsrtpdec.c
ext/srtp/gstsrtpdec.h
ext/srtp/gstsrtpenc.c
ext/srtp/gstsrtpenc.h

index b82a0a6ca28eddc0e15a5c941350074c3c69d2ec..5d42f44859c19c6e8e1d7d4770c45b4b2e35fbbe 100644 (file)
  * subsequent packet is dropped, until a new key is set and the stream
  * has been updated.
  *
+ * If a stream is to be shared between multiple clients the SRTP
+ * rollover counter for a given SSRC must be set in the caps "roc" field
+ * when the request-key signal is emitted by the decoder. The rollover
+ * counters should have been transmitted by a signaling protocol by some
+ * other means. If no rollover counter is provided by the user, 0 is
+ * used by default.
+ *
  * <refsect2>
  * <title>Example pipelines</title>
  * |[
 
 #include "gstsrtpdec.h"
 
+#include <srtp/srtp_priv.h>
+
 GST_DEBUG_CATEGORY_STATIC (gst_srtp_dec_debug);
 #define GST_CAT_DEFAULT gst_srtp_dec_debug
 
@@ -203,6 +212,7 @@ struct _GstSrtpDecSsrcStream
 {
   guint32 ssrc;
 
+  guint32 roc;
   GstBuffer *key;
   GstSrtpCipherType rtp_cipher;
   GstSrtpAuthType rtp_auth;
@@ -216,6 +226,7 @@ struct _GstSrtpDecSsrcStream
       stream->rtp_auth != GST_SRTP_AUTH_NULL ||         \
       stream->rtcp_auth != GST_SRTP_AUTH_NULL)
 
+
 /* initialize the srtpdec's class */
 static void
 gst_srtp_dec_class_init (GstSrtpDecClass * klass)
@@ -238,11 +249,14 @@ gst_srtp_dec_class_init (GstSrtpDecClass * klass)
       "A SRTP and SRTCP decoder",
       "Gabriel Millaire <millaire.gabriel@collabora.com>");
 
+  /* Install callbacks */
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_srtp_dec_change_state);
+
   klass->clear_streams = GST_DEBUG_FUNCPTR (gst_srtp_dec_clear_streams);
   klass->remove_stream = GST_DEBUG_FUNCPTR (gst_srtp_dec_remove_stream);
 
+  /* Install signals */
   /**
    * GstSrtpDec::request-key:
    * @gstsrtpdec: the element on which the signal is emitted
@@ -369,6 +383,7 @@ gst_srtp_dec_init (GstSrtpDec * filter)
   gst_element_add_pad (GST_ELEMENT (filter), filter->rtcp_srcpad);
 
   filter->first_session = TRUE;
+  filter->roc_changed = FALSE;
 }
 
 static void
@@ -421,6 +436,7 @@ get_stream_from_caps (GstSrtpDec * filter, GstCaps * caps, guint32 ssrc)
   if (!rtp_cipher || !rtp_auth || !rtcp_cipher || !rtcp_auth)
     goto error;
 
+  gst_structure_get_uint (s, "roc", &stream->roc);
 
   stream->rtp_cipher = enum_value_from_nick (GST_TYPE_SRTP_CIPHER_TYPE,
       rtp_cipher);
@@ -518,6 +534,17 @@ init_session_stream (GstSrtpDec * filter, guint32 ssrc,
     gst_buffer_unmap (stream->key, &map);
 
   if (ret == err_status_ok) {
+    srtp_stream_t srtp_stream;
+
+    srtp_stream = srtp_get_stream (filter->session, htonl (ssrc));
+    if (srtp_stream) {
+      /* Here, we just set the ROC, but we also need to set the initial
+       * RTP sequence number later, otherwise libsrtp will not be able
+       * to get the right packet index. */
+      rdbx_set_roc (&srtp_stream->rtp_rdbx, stream->roc);
+      filter->roc_changed = TRUE;
+    }
+
     filter->first_session = FALSE;
     g_hash_table_insert (filter->streams, GUINT_TO_POINTER (stream->ssrc),
         stream);
@@ -672,9 +699,9 @@ request_key_with_signal (GstSrtpDec * filter, guint32 ssrc, gint signal)
   if (caps) {
     stream = update_session_stream_from_caps (filter, ssrc, caps);
     if (stream)
-      GST_DEBUG_OBJECT (filter, "New stream set with SSRC %d", ssrc);
+      GST_DEBUG_OBJECT (filter, "New stream set with SSRC %u", ssrc);
     else
-      GST_WARNING_OBJECT (filter, "Could not set stream with SSRC %d", ssrc);
+      GST_WARNING_OBJECT (filter, "Could not set stream with SSRC %u", ssrc);
     gst_caps_unref (caps);
   }
 
@@ -1016,8 +1043,32 @@ unprotect:
 
   if (is_rtcp)
     err = srtp_unprotect_rtcp (filter->session, map.data, &size);
-  else
+  else {
+    /* If ROC has changed, we know we need to set the initial RTP
+     * sequence number too. */
+    if (filter->roc_changed) {
+      srtp_stream_t stream;
+
+      stream = srtp_get_stream (filter->session, htonl (ssrc));
+
+      if (stream) {
+        guint16 seqnum = 0;
+        GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
+
+        gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuf);
+        seqnum = gst_rtp_buffer_get_seq (&rtpbuf);
+        gst_rtp_buffer_unmap (&rtpbuf);
+
+        /* We finally add the RTP sequence number to the current
+         * rollover counter. */
+        stream->rtp_rdbx.index &= ~0xFFFF;
+        stream->rtp_rdbx.index |= seqnum;
+      }
+
+      filter->roc_changed = FALSE;
+    }
     err = srtp_unprotect (filter->session, map.data, &size);
+  }
 
   gst_buffer_unmap (buf, &map);
 
index 8129dc08fc088d2c688ea4535f404eafb7b40492..41862e032a49be76c0ac48f057e4ae1a5cae6efc 100644 (file)
@@ -81,6 +81,8 @@ struct _GstSrtpDec
 
   gboolean rtp_has_segment;
   gboolean rtcp_has_segment;
+
+  gboolean roc_changed;
 };
 
 struct _GstSrtpDecClass
index adee36843beb64d749b6774014ade752df3415d3..ad637a6fe211df85ef63cb0fa6557ceff061a596 100644 (file)
  * subsequent packet is dropped, until a new key is set and the stream
  * has been updated.
  *
+ * If a stream is to be shared between multiple clients it is also
+ * possible to request the internal SRTP rollover counter for a given
+ * SSRC. The rollover counter should be then transmitted and used by the
+ * clients to authenticate and decrypt the packets. Failing to do that
+ * 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.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "gstsrtp.h"
 #include "gstsrtp-enumtypes.h"
 
+#include <srtp/srtp_priv.h>
+
 GST_DEBUG_CATEGORY_STATIC (gst_srtp_enc_debug);
 #define GST_CAT_DEFAULT gst_srtp_enc_debug
 
@@ -135,6 +144,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_srtp_enc_debug);
 enum
 {
   SIGNAL_SOFT_LIMIT,
+  SIGNAL_GET_ROLLOVER_COUNTER,
   LAST_SIGNAL
 };
 
@@ -221,6 +231,28 @@ static GstPad *gst_srtp_enc_request_new_pad (GstElement * element,
 
 static void gst_srtp_enc_release_pad (GstElement * element, GstPad * pad);
 
+
+static guint32
+gst_srtp_enc_get_rollover_counter (GstSrtpEnc * filter, guint32 ssrc)
+{
+  guint32 roc = 0;
+  srtp_stream_t stream;
+
+  GST_OBJECT_LOCK (filter);
+
+  GST_DEBUG_OBJECT (filter, "retrieving SRTP Rollover Counter, ssrc: %u", ssrc);
+
+  if (filter->session) {
+    stream = srtp_get_stream (filter->session, htonl (ssrc));
+    if (stream)
+      roc = stream->rtp_rdbx.index >> 16;
+  }
+
+  GST_OBJECT_UNLOCK (filter);
+
+  return roc;
+}
+
 /* initialize the srtpenc's class
  */
 static void
@@ -301,6 +333,22 @@ gst_srtp_enc_class_init (GstSrtpEncClass * klass)
   gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT] =
       g_signal_new ("soft-limit", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  /**
+   * GstSrtpEnc::get-rollover-counter:
+   * @gstsrtpenc: the element on which the signal is emitted
+   * @ssrc: The unique SSRC of the stream
+   *
+   * Request the SRTP rollover counter for the stream with @ssrc.
+   */
+  gst_srtp_enc_signals[SIGNAL_GET_ROLLOVER_COUNTER] =
+      g_signal_new ("get-rollover-counter", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstSrtpEncClass,
+          get_rollover_counter), NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_UINT, 1, G_TYPE_UINT);
+
+  klass->get_rollover_counter =
+      GST_DEBUG_FUNCPTR (gst_srtp_enc_get_rollover_counter);
 }
 
 
index c4bc75cef81d0165432f6423ed036af44844683d..36da4ffae739dae2465d426dd4e2f4ccf59c53be 100644 (file)
@@ -88,6 +88,9 @@ struct _GstSrtpEnc
 struct _GstSrtpEncClass
 {
   GstElementClass parent_class;
+
+  /* action signals */
+  guint32 (*get_rollover_counter) (GstSrtpEnc *encoder, guint32 ssrc);
 };
 
 GType gst_srtp_enc_get_type (void);