1 /*
2  * GStreamer - GStreamer SRTP encoder
3  *
4  * Copyright 2009-2011 Collabora Ltd.
5  *  @author: Gabriel Millaire <gabriel.millaire@collabora.com>
6  *  @author: Olivier Crete <olivier.crete@collabora.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
44  * Boston, MA 02111-1307, USA.
45  */
46 
47 /**
48  * SECTION:element-srtpenc
49  * @title: srtpenc
50  * @see_also: srtpdec
51  *
52  * gstrtpenc acts as an encoder that adds security to RTP and RTCP
53  * packets in the form of encryption and authentication. It outs SRTP
54  * and SRTCP.
55  *
56  * An application can request multiple RTP and RTCP pads to protect,
57  * but every sink pad requested must receive packets from the same
58  * source (identical SSRC). If a packet received contains a different
59  * SSRC, a warning is emited and the valid SSRC is forced on the packet.
60  *
61  * This element uses libsrtp library. When receiving the first packet,
62  * the library is initialized with a new stream (based on the SSRC). It
63  * uses the default RTP and RTCP encryption and authentication mechanisms,
64  * unless the user has set the relevant properties first. It also uses
65  * a master key that MUST be set by property (key) at the beginning. The
66  * master key must be of a maximum length of 46 characters (14 characters
67  * for the salt plus the key). The encryption and authentication mechanisms
68  * available are :
69  *
70  * Encryption (properties rtp-cipher and rtcp-cipher)
71  * - AES_ICM 256 bits (maximum security)
72  * - AES_ICM 128 bits (default)
73  * - NULL
74  *
75  * Authentication (properties rtp-auth and rtcp-auth)
76  * - HMAC_SHA1 80 bits (default, maximum protection)
77  * - HMAC_SHA1 32 bits
78  * - NULL
79  *
80  * Note that for SRTP protection, authentication is mandatory (non-null)
81  * if encryption is used (non-null).
82  *
83  * When requested to create a sink pad, a linked source pad is created.
84  * Each packet received is first analysed (checked for valid SSRC) then
85  * its buffer is protected with libsrtp, then pushed on the source pad.
86  * If protection failed or the stream could not be created, the buffer
87  * is dropped and a warning is emitted. The packets pushed on the source
88  * pad are of type 'application/x-srtp' or 'application/x-srtcp'.
89  *
90  * When the maximum usage of the master key is reached, a soft-limit
91  * signal is sent to the user. The user must then set a new master key
92  * by property. If the hard limit is reached, a flag is set and every
93  * subsequent packet is dropped, until a new key is set and the stream
94  * has been updated.
95  *
96  * If a stream is to be shared between multiple clients it is also
97  * possible to request the internal SRTP rollover counter for a given
98  * SSRC. The rollover counter should be then transmitted and used by the
99  * clients to authenticate and decrypt the packets. Failing to do that
100  * the clients will start with a rollover counter of 0 which will
101  * probably be incorrect if the stream has been transmitted for a
102  * while to other clients.
103  *
104  * This element supports sending with a single Master Key, it is possible to set the
105  * Master Key Identifier (MKI) using the "mki" property. If this property is set, the MKI
106  * will be added to every buffer.
107  */
108 
109 #include "gstsrtpenc.h"
110 
111 #include <gst/rtp/gstrtpbuffer.h>
112 #include <gst/rtp/gstrtcpbuffer.h>
113 #include <string.h>
114 #include <stdio.h>
115 
116 GST_DEBUG_CATEGORY_STATIC (gst_srtp_enc_debug);
117 #define GST_CAT_DEFAULT gst_srtp_enc_debug
118 
119 /* 128 bit key size: 14 (salt) + 16 */
120 #define MASTER_128_KEY_SIZE 30
121 
122 /* 256 bit key size: 14 (salt) + 16 + 16 */
123 #define MASTER_256_KEY_SIZE 46
124 
125 /* Properties default values */
126 #define DEFAULT_MASTER_KEY      NULL
127 #define DEFAULT_RTP_CIPHER      GST_SRTP_CIPHER_AES_128_ICM
128 #define DEFAULT_RTP_AUTH        GST_SRTP_AUTH_HMAC_SHA1_80
129 #define DEFAULT_RTCP_CIPHER     DEFAULT_RTP_CIPHER
130 #define DEFAULT_RTCP_AUTH       DEFAULT_RTP_AUTH
131 #define DEFAULT_RANDOM_KEY      FALSE
132 #define DEFAULT_REPLAY_WINDOW_SIZE 128
133 #define DEFAULT_ALLOW_REPEAT_TX FALSE
134 
135 #define HAS_CRYPTO(filter) (filter->rtp_cipher != GST_SRTP_CIPHER_NULL || \
136       filter->rtcp_cipher != GST_SRTP_CIPHER_NULL ||                      \
137       filter->rtp_auth != GST_SRTP_AUTH_NULL ||                           \
138       filter->rtcp_auth != GST_SRTP_AUTH_NULL)
139 
140 /* Filter signals and args */
141 enum
142 {
143   SIGNAL_SOFT_LIMIT,
144   SIGNAL_GET_ROLLOVER_COUNTER,
145   LAST_SIGNAL
146 };
147 
148 enum
149 {
150   PROP_0,
151   PROP_MKEY,
152   PROP_RTP_CIPHER,
153   PROP_RTP_AUTH,
154   PROP_RTCP_CIPHER,
155   PROP_RTCP_AUTH,
156   PROP_RANDOM_KEY,
157   PROP_REPLAY_WINDOW_SIZE,
158   PROP_ALLOW_REPEAT_TX,
159   PROP_STATS,
160   PROP_MKI
161 };
162 
163 typedef struct ProcessBufferItData
164 {
165   GstSrtpEnc *filter;
166   GstPad *pad;
167   GstBufferList *out_list;
168   GstFlowReturn flowret;
169   gboolean is_rtcp;
170 } ProcessBufferItData;
171 
172 /* the capabilities of the inputs and outputs.
173  *
174  * describe the real formats here.
175  */
176 static GstStaticPadTemplate rtp_sink_template =
177 GST_STATIC_PAD_TEMPLATE ("rtp_sink_%u",
178     GST_PAD_SINK,
179     GST_PAD_REQUEST,
180     GST_STATIC_CAPS ("application/x-rtp")
181     );
182 
183 static GstStaticPadTemplate rtp_src_template =
184 GST_STATIC_PAD_TEMPLATE ("rtp_src_%u",
185     GST_PAD_SRC,
186     GST_PAD_SOMETIMES,
187     GST_STATIC_CAPS ("application/x-srtp")
188     );
189 
190 static GstStaticPadTemplate rtcp_sink_template =
191 GST_STATIC_PAD_TEMPLATE ("rtcp_sink_%u",
192     GST_PAD_SINK,
193     GST_PAD_REQUEST,
194     GST_STATIC_CAPS ("application/x-rtcp")
195     );
196 
197 static GstStaticPadTemplate rtcp_src_template =
198 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
199     GST_PAD_SRC,
200     GST_PAD_SOMETIMES,
201     GST_STATIC_CAPS ("application/x-srtcp")
202     );
203 
204 G_DEFINE_TYPE (GstSrtpEnc, gst_srtp_enc, GST_TYPE_ELEMENT);
205 
206 static guint gst_srtp_enc_signals[LAST_SIGNAL] = { 0 };
207 
208 static void gst_srtp_enc_dispose (GObject * object);
209 
210 static void gst_srtp_enc_set_property (GObject * object, guint prop_id,
211     const GValue * value, GParamSpec * pspec);
212 static void gst_srtp_enc_get_property (GObject * object, guint prop_id,
213     GValue * value, GParamSpec * pspec);
214 
215 static gboolean gst_srtp_enc_sink_query_rtp (GstPad * pad, GstObject * parent,
216     GstQuery * query);
217 static gboolean gst_srtp_enc_sink_query_rtcp (GstPad * pad, GstObject * parent,
218     GstQuery * query);
219 
220 static GstIterator *gst_srtp_enc_iterate_internal_links_rtp (GstPad * pad,
221     GstObject * parent);
222 static GstIterator *gst_srtp_enc_iterate_internal_links_rtcp (GstPad * pad,
223     GstObject * parent);
224 
225 static GstFlowReturn gst_srtp_enc_chain_rtp (GstPad * pad, GstObject * parent,
226     GstBuffer * buf);
227 static GstFlowReturn gst_srtp_enc_chain_rtcp (GstPad * pad, GstObject * parent,
228     GstBuffer * buf);
229 static GstFlowReturn gst_srtp_enc_chain_list_rtp (GstPad * pad,
230     GstObject * parent, GstBufferList * buf);
231 static GstFlowReturn gst_srtp_enc_chain_list_rtcp (GstPad * pad,
232     GstObject * parent, GstBufferList * buf);
233 
234 static gboolean gst_srtp_enc_sink_event_rtp (GstPad * pad, GstObject * parent,
235     GstEvent * event);
236 static gboolean gst_srtp_enc_sink_event_rtcp (GstPad * pad, GstObject * parent,
237     GstEvent * event);
238 
239 static GstStateChangeReturn gst_srtp_enc_change_state (GstElement * element,
240     GstStateChange transition);
241 
242 static GstPad *gst_srtp_enc_request_new_pad (GstElement * element,
243     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
244 
245 static void gst_srtp_enc_release_pad (GstElement * element, GstPad * pad);
246 
247 
248 /* initialize the srtpenc's class
249  */
250 static void
gst_srtp_enc_class_init(GstSrtpEncClass * klass)251 gst_srtp_enc_class_init (GstSrtpEncClass * klass)
252 {
253   GObjectClass *gobject_class;
254   GstElementClass *gstelement_class;
255 
256   gobject_class = (GObjectClass *) klass;
257   gstelement_class = (GstElementClass *) klass;
258 
259   gst_element_class_add_static_pad_template (gstelement_class,
260       &rtp_src_template);
261   gst_element_class_add_static_pad_template (gstelement_class,
262       &rtp_sink_template);
263   gst_element_class_add_static_pad_template (gstelement_class,
264       &rtcp_src_template);
265   gst_element_class_add_static_pad_template (gstelement_class,
266       &rtcp_sink_template);
267 
268   gst_element_class_set_static_metadata (gstelement_class, "SRTP encoder",
269       "Filter/Network/SRTP",
270       "A SRTP and SRTCP encoder",
271       "Gabriel Millaire <millaire.gabriel@collabora.com>");
272 
273 
274   /* Install callbacks */
275   gobject_class->set_property = gst_srtp_enc_set_property;
276   gobject_class->get_property = gst_srtp_enc_get_property;
277   gobject_class->dispose = gst_srtp_enc_dispose;
278   gstelement_class->request_new_pad =
279       GST_DEBUG_FUNCPTR (gst_srtp_enc_request_new_pad);
280   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_srtp_enc_release_pad);
281   gstelement_class->change_state =
282       GST_DEBUG_FUNCPTR (gst_srtp_enc_change_state);
283 
284   /* Install properties */
285   g_object_class_install_property (gobject_class, PROP_MKEY,
286       g_param_spec_boxed ("key", "Key", "Master key (minimum of "
287           G_STRINGIFY (MASTER_128_KEY_SIZE) " and maximum of "
288           G_STRINGIFY (MASTER_256_KEY_SIZE) " bytes)",
289           GST_TYPE_BUFFER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
290           GST_PARAM_MUTABLE_PLAYING));
291   g_object_class_install_property (gobject_class, PROP_RTP_CIPHER,
292       g_param_spec_enum ("rtp-cipher", "RTP Cipher", "RTP Cipher",
293           GST_TYPE_SRTP_CIPHER_TYPE, DEFAULT_RTP_CIPHER,
294           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295   g_object_class_install_property (gobject_class, PROP_RTP_AUTH,
296       g_param_spec_enum ("rtp-auth", "RTP Authentication",
297           "RTP Authentication", GST_TYPE_SRTP_AUTH_TYPE, DEFAULT_RTP_AUTH,
298           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299   g_object_class_install_property (gobject_class, PROP_RTCP_CIPHER,
300       g_param_spec_enum ("rtcp-cipher", "RTCP Cipher",
301           "RTCP Cipher", GST_TYPE_SRTP_CIPHER_TYPE, DEFAULT_RTCP_CIPHER,
302           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
303   g_object_class_install_property (gobject_class, PROP_RTCP_AUTH,
304       g_param_spec_enum ("rtcp-auth", "RTCP Authentication",
305           "RTCP Authentication", GST_TYPE_SRTP_AUTH_TYPE, DEFAULT_RTCP_AUTH,
306           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
307   g_object_class_install_property (gobject_class, PROP_RANDOM_KEY,
308       g_param_spec_boolean ("random-key", "Generate random key",
309           "Generate a random key if TRUE",
310           DEFAULT_RANDOM_KEY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
311   g_object_class_install_property (gobject_class, PROP_REPLAY_WINDOW_SIZE,
312       g_param_spec_uint ("replay-window-size", "Replay window size",
313           "Size of the replay protection window",
314           64, 0x8000, DEFAULT_REPLAY_WINDOW_SIZE,
315           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
316   g_object_class_install_property (gobject_class, PROP_ALLOW_REPEAT_TX,
317       g_param_spec_boolean ("allow-repeat-tx",
318           "Allow repeat packets transmission",
319           "Whether retransmissions of packets with the same sequence number are allowed"
320           "(Note that such repeated transmissions must have the same RTP payload, "
321           "or a severe security weakness is introduced!)",
322           DEFAULT_ALLOW_REPEAT_TX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
323   g_object_class_install_property (gobject_class, PROP_STATS,
324       g_param_spec_boxed ("stats", "Statistics", "Various statistics",
325           GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
326 #ifdef HAVE_SRTP2
327   g_object_class_install_property (gobject_class, PROP_MKI,
328       g_param_spec_boxed ("mki", "MKI",
329           "Master key Identifier (NULL means no MKI)", GST_TYPE_BUFFER,
330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
331           GST_PARAM_MUTABLE_PLAYING));
332 #endif
333 
334   /**
335    * GstSrtpEnc::soft-limit:
336    * @gstsrtpenc: the element on which the signal is emitted
337    *
338    * Signal emited when the stream with @ssrc has reached the soft
339    * limit of utilisation of it's master encryption key. User should
340    * provide a new key by setting the #GstSrtpEnc:key property.
341    */
342   gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT] =
343       g_signal_new ("soft-limit", G_TYPE_FROM_CLASS (klass),
344       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
345 }
346 
347 
348 /* initialize the new element
349  */
350 static void
gst_srtp_enc_init(GstSrtpEnc * filter)351 gst_srtp_enc_init (GstSrtpEnc * filter)
352 {
353   filter->key_changed = TRUE;
354   filter->first_session = TRUE;
355   filter->key = DEFAULT_MASTER_KEY;
356   filter->rtp_cipher = DEFAULT_RTP_CIPHER;
357   filter->rtp_auth = DEFAULT_RTP_AUTH;
358   filter->rtcp_cipher = DEFAULT_RTCP_CIPHER;
359   filter->rtcp_auth = DEFAULT_RTCP_AUTH;
360   filter->replay_window_size = DEFAULT_REPLAY_WINDOW_SIZE;
361   filter->allow_repeat_tx = DEFAULT_ALLOW_REPEAT_TX;
362   filter->ssrcs_set = g_hash_table_new (g_direct_hash, g_direct_equal);
363 }
364 
365 static guint
max_cipher_key_size(GstSrtpEnc * filter)366 max_cipher_key_size (GstSrtpEnc * filter)
367 {
368   guint rtp_size, rtcp_size;
369 
370   rtp_size = cipher_key_size (filter->rtp_cipher);
371   rtcp_size = cipher_key_size (filter->rtcp_cipher);
372 
373   return (rtp_size > rtcp_size) ? rtp_size : rtcp_size;
374 }
375 
376 /* Create stream
377  *
378  * Should be called with the filter locked
379  */
380 static srtp_err_status_t
gst_srtp_enc_create_session(GstSrtpEnc * filter)381 gst_srtp_enc_create_session (GstSrtpEnc * filter)
382 {
383   srtp_err_status_t ret;
384   srtp_policy_t policy;
385   GstMapInfo map;
386   guchar tmp[1];
387 #ifdef HAVE_SRTP2
388   srtp_master_key_t mkey;
389   srtp_master_key_t *mkey_ptr = &mkey;
390   gboolean has_mki = FALSE;
391   GstMapInfo mki_map;
392 #endif
393 
394   memset (&policy, 0, sizeof (srtp_policy_t));
395 
396   if (HAS_CRYPTO (filter)) {
397     guint expected;
398     gsize keysize;
399 
400     if (filter->key == NULL) {
401       GST_OBJECT_UNLOCK (filter);
402       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS,
403           ("Cipher is not NULL, key must be set"),
404           ("Cipher is not NULL, key must be set"));
405       GST_OBJECT_LOCK (filter);
406       return srtp_err_status_fail;
407     }
408 
409     expected = max_cipher_key_size (filter);
410     keysize = gst_buffer_get_size (filter->key);
411 
412     if (expected != keysize) {
413       GST_OBJECT_UNLOCK (filter);
414       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS,
415           ("Master key size is wrong"),
416           ("Expected master key of %d bytes, but received %" G_GSIZE_FORMAT
417               " bytes", expected, keysize));
418       GST_OBJECT_LOCK (filter);
419       return srtp_err_status_fail;
420     }
421   }
422 
423   GST_DEBUG_OBJECT (filter, "Setting RTP/RTCP policy to %d / %d",
424       filter->rtp_cipher, filter->rtcp_cipher);
425   set_crypto_policy_cipher_auth (filter->rtp_cipher, filter->rtp_auth,
426       &policy.rtp);
427   set_crypto_policy_cipher_auth (filter->rtcp_cipher, filter->rtcp_auth,
428       &policy.rtcp);
429 
430   if (HAS_CRYPTO (filter)) {
431     gst_buffer_map (filter->key, &map, GST_MAP_READ);
432     policy.key = (guchar *) map.data;
433   } else {
434     policy.key = tmp;
435   }
436 
437 #ifdef HAVE_SRTP2
438   if (filter->mki) {
439     if (!gst_buffer_map (filter->mki, &mki_map, GST_MAP_READ)) {
440       GST_OBJECT_UNLOCK (filter);
441       GST_ELEMENT_ERROR (filter, LIBRARY, SETTINGS, ("Could not map MKI"),
442           (NULL));
443       GST_OBJECT_LOCK (filter);
444 
445       ret = srtp_err_status_fail;
446       goto done;
447     }
448     has_mki = TRUE;
449 
450     policy.num_master_keys = 1;
451     policy.keys = &mkey_ptr;
452     mkey.key = policy.key;
453     policy.key = NULL;
454 
455     mkey.mki_id = (guchar *) mki_map.data;
456     mkey.mki_size = mki_map.size;
457   }
458 #endif
459 
460   policy.ssrc.value = 0;
461   policy.ssrc.type = ssrc_any_outbound;
462   policy.next = NULL;
463 
464   policy.window_size = filter->replay_window_size;
465   policy.allow_repeat_tx = filter->allow_repeat_tx;
466 
467   /* If it is the first stream, create the session
468    * If not, add the stream to the session
469    */
470   ret = srtp_create (&filter->session, &policy);
471   filter->first_session = FALSE;
472 
473 #ifdef HAVE_SRTP2
474 done:
475 
476   if (has_mki)
477     gst_buffer_unmap (filter->mki, &mki_map);
478 #endif
479 
480   if (HAS_CRYPTO (filter))
481     gst_buffer_unmap (filter->key, &map);
482 
483 
484   return ret;
485 }
486 
487 /* Release ressources and set default values
488  */
489 static void
gst_srtp_enc_reset_no_lock(GstSrtpEnc * filter)490 gst_srtp_enc_reset_no_lock (GstSrtpEnc * filter)
491 {
492   if (!filter->first_session) {
493     if (filter->session) {
494       srtp_dealloc (filter->session);
495       filter->session = NULL;
496     }
497 
498     g_hash_table_remove_all (filter->ssrcs_set);
499   }
500 
501   filter->first_session = TRUE;
502   filter->key_changed = FALSE;
503 }
504 
505 static void
gst_srtp_enc_reset(GstSrtpEnc * filter)506 gst_srtp_enc_reset (GstSrtpEnc * filter)
507 {
508   GST_OBJECT_LOCK (filter);
509   gst_srtp_enc_reset_no_lock (filter);
510   GST_OBJECT_UNLOCK (filter);
511 }
512 
513 /* Create sinkpad to receive RTP packets from encers
514  * and a srcpad for the RTP packets
515  */
516 static GstPad *
create_rtp_sink(GstSrtpEnc * filter,const gchar * name)517 create_rtp_sink (GstSrtpEnc * filter, const gchar * name)
518 {
519   GstPad *sinkpad, *srcpad;
520   gchar *sinkpadname, *srcpadname;
521   guint nb = 0;
522 
523   GST_DEBUG_OBJECT (filter, "creating RTP sink pad");
524   sinkpad = gst_pad_new_from_static_template (&rtp_sink_template, name);
525 
526   sinkpadname = gst_pad_get_name (sinkpad);
527   sscanf (sinkpadname, "rtp_sink_%u", &nb);
528   srcpadname = g_strdup_printf ("rtp_src_%u", nb);
529 
530   GST_DEBUG_OBJECT (filter, "creating RTP source pad");
531   srcpad = gst_pad_new_from_static_template (&rtp_src_template, srcpadname);
532   g_free (srcpadname);
533   g_free (sinkpadname);
534 
535   gst_pad_set_element_private (sinkpad, srcpad);
536   gst_pad_set_element_private (srcpad, sinkpad);
537 
538   gst_pad_set_query_function (sinkpad,
539       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_query_rtp));
540   gst_pad_set_iterate_internal_links_function (sinkpad,
541       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtp));
542   gst_pad_set_chain_function (sinkpad,
543       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_rtp));
544   gst_pad_set_chain_list_function (sinkpad,
545       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_list_rtp));
546   gst_pad_set_event_function (sinkpad,
547       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_event_rtp));
548   gst_pad_set_active (sinkpad, TRUE);
549   gst_element_add_pad (GST_ELEMENT_CAST (filter), sinkpad);
550 
551   gst_pad_set_iterate_internal_links_function (srcpad,
552       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtp));
553   gst_pad_set_active (srcpad, TRUE);
554   gst_element_add_pad (GST_ELEMENT_CAST (filter), srcpad);
555 
556   return sinkpad;
557 }
558 
559 /* Create sinkpad to receive RTCP packets from encers
560  * and a srcpad for the RTCP packets
561  */
562 static GstPad *
create_rtcp_sink(GstSrtpEnc * filter,const gchar * name)563 create_rtcp_sink (GstSrtpEnc * filter, const gchar * name)
564 {
565   GstPad *srcpad, *sinkpad;
566   gchar *sinkpadname, *srcpadname;
567   guint nb = 0;
568 
569   GST_DEBUG_OBJECT (filter, "creating RTCP sink pad");
570   sinkpad = gst_pad_new_from_static_template (&rtcp_sink_template, name);
571 
572   sinkpadname = gst_pad_get_name (sinkpad);
573   sscanf (sinkpadname, "rtcp_sink_%u", &nb);
574   srcpadname = g_strdup_printf ("rtcp_src_%u", nb);
575 
576   GST_DEBUG_OBJECT (filter, "creating RTCP source pad");
577   srcpad = gst_pad_new_from_static_template (&rtcp_src_template, srcpadname);
578   g_free (srcpadname);
579   g_free (sinkpadname);
580 
581   gst_pad_set_element_private (sinkpad, srcpad);
582   gst_pad_set_element_private (srcpad, sinkpad);
583 
584   gst_pad_set_query_function (sinkpad,
585       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_query_rtcp));
586   gst_pad_set_iterate_internal_links_function (sinkpad,
587       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtcp));
588   gst_pad_set_chain_function (sinkpad,
589       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_rtcp));
590   gst_pad_set_chain_list_function (sinkpad,
591       GST_DEBUG_FUNCPTR (gst_srtp_enc_chain_list_rtcp));
592   gst_pad_set_event_function (sinkpad,
593       GST_DEBUG_FUNCPTR (gst_srtp_enc_sink_event_rtcp));
594   gst_pad_set_active (sinkpad, TRUE);
595   gst_element_add_pad (GST_ELEMENT_CAST (filter), sinkpad);
596 
597   gst_pad_set_iterate_internal_links_function (srcpad,
598       GST_DEBUG_FUNCPTR (gst_srtp_enc_iterate_internal_links_rtcp));
599   gst_pad_set_active (srcpad, TRUE);
600   gst_element_add_pad (GST_ELEMENT_CAST (filter), srcpad);
601 
602   return sinkpad;
603 }
604 
605 /* Handling new pad request
606  */
607 static GstPad *
gst_srtp_enc_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * name,const GstCaps * caps)608 gst_srtp_enc_request_new_pad (GstElement * element,
609     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
610 {
611   GstElementClass *klass;
612   GstSrtpEnc *filter;
613 
614   filter = GST_SRTP_ENC (element);
615   klass = GST_ELEMENT_GET_CLASS (element);
616 
617   GST_INFO_OBJECT (element, "New pad requested");
618 
619   if (templ == gst_element_class_get_pad_template (klass, "rtp_sink_%u"))
620     return create_rtp_sink (filter, name);
621 
622   if (templ == gst_element_class_get_pad_template (klass, "rtcp_sink_%u"))
623     return create_rtcp_sink (filter, name);
624 
625   GST_ERROR_OBJECT (element, "Could not find specified template");
626   return NULL;
627 }
628 
629 /* Dispose
630  */
631 static void
gst_srtp_enc_dispose(GObject * object)632 gst_srtp_enc_dispose (GObject * object)
633 {
634   GstSrtpEnc *filter = GST_SRTP_ENC (object);
635   GstIterator *it;
636   GValue val = { 0 };
637 
638   GST_DEBUG_OBJECT (object, "Dispose...");
639 
640   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (object));
641   while (gst_iterator_next (it, &val) == GST_ITERATOR_OK) {
642     gst_srtp_enc_release_pad (GST_ELEMENT_CAST (object),
643         g_value_get_object (&val));
644     g_value_unset (&val);
645     gst_iterator_resync (it);
646   }
647   gst_iterator_free (it);
648 
649   gst_buffer_replace (&filter->key, NULL);
650   gst_buffer_replace (&filter->mki, NULL);
651 
652   if (filter->ssrcs_set)
653     g_hash_table_unref (filter->ssrcs_set);
654   filter->ssrcs_set = NULL;
655 
656   G_OBJECT_CLASS (gst_srtp_enc_parent_class)->dispose (object);
657 }
658 
659 static GstStructure *
gst_srtp_enc_create_stats(GstSrtpEnc * filter)660 gst_srtp_enc_create_stats (GstSrtpEnc * filter)
661 {
662   GstStructure *s;
663   GValue va = G_VALUE_INIT;
664   GValue v = G_VALUE_INIT;
665 
666   s = gst_structure_new_empty ("application/x-srtp-encoder-stats");
667 
668   g_value_init (&va, GST_TYPE_ARRAY);
669   g_value_init (&v, GST_TYPE_STRUCTURE);
670 
671   if (filter->session) {
672     GHashTableIter iter;
673     gpointer key;
674 
675     g_hash_table_iter_init (&iter, filter->ssrcs_set);
676     while (g_hash_table_iter_next (&iter, &key, NULL)) {
677       GstStructure *ss;
678       guint32 ssrc = GPOINTER_TO_UINT (key);
679       srtp_err_status_t status;
680       guint32 roc;
681 
682       status = srtp_get_stream_roc (filter->session, ssrc, &roc);
683       if (status != srtp_err_status_ok) {
684         continue;
685       }
686 
687       ss = gst_structure_new ("application/x-srtp-stream",
688           "ssrc", G_TYPE_UINT, ssrc, "roc", G_TYPE_UINT, roc, NULL);
689 
690       g_value_take_boxed (&v, ss);
691       gst_value_array_append_value (&va, &v);
692     }
693   }
694 
695   gst_structure_take_value (s, "streams", &va);
696   g_value_unset (&v);
697 
698   return s;
699 }
700 
701 static void
gst_srtp_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)702 gst_srtp_enc_set_property (GObject * object, guint prop_id,
703     const GValue * value, GParamSpec * pspec)
704 {
705   GstSrtpEnc *filter = GST_SRTP_ENC (object);
706 
707   GST_OBJECT_LOCK (filter);
708 
709   switch (prop_id) {
710     case PROP_MKEY:
711       gst_clear_buffer (&filter->key);
712       filter->key = g_value_dup_boxed (value);
713       filter->key_changed = TRUE;
714       GST_INFO_OBJECT (object, "Set property: key=[%p]", filter->key);
715       break;
716 
717     case PROP_RTP_CIPHER:
718       filter->rtp_cipher = g_value_get_enum (value);
719       GST_INFO_OBJECT (object, "Set property: rtp cipher=%d",
720           filter->rtp_cipher);
721       break;
722     case PROP_RTP_AUTH:
723       filter->rtp_auth = g_value_get_enum (value);
724       GST_INFO_OBJECT (object, "Set property: rtp auth=%d", filter->rtp_auth);
725       break;
726 
727     case PROP_RTCP_CIPHER:
728       filter->rtcp_cipher = g_value_get_enum (value);
729       GST_INFO_OBJECT (object, "Set property: rtcp cipher=%d",
730           filter->rtcp_cipher);
731       break;
732 
733     case PROP_RTCP_AUTH:
734       filter->rtcp_auth = g_value_get_enum (value);
735       GST_INFO_OBJECT (object, "Set property: rtcp auth=%d", filter->rtcp_auth);
736       break;
737 
738     case PROP_RANDOM_KEY:
739       filter->random_key = g_value_get_boolean (value);
740       break;
741 
742     case PROP_REPLAY_WINDOW_SIZE:
743       filter->replay_window_size = g_value_get_uint (value);
744       break;
745 
746     case PROP_ALLOW_REPEAT_TX:
747       filter->allow_repeat_tx = g_value_get_boolean (value);
748       break;
749 #ifdef HAVE_SRTP2
750     case PROP_MKI:
751       gst_clear_buffer (&filter->mki);
752       filter->mki = g_value_dup_boxed (value);
753       filter->key_changed = TRUE;
754       GST_INFO_OBJECT (object, "Set property: mki=[%p]", filter->mki);
755       break;
756 #endif
757     default:
758       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
759       break;
760   }
761 
762   GST_OBJECT_UNLOCK (filter);
763 }
764 
765 static void
gst_srtp_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)766 gst_srtp_enc_get_property (GObject * object, guint prop_id,
767     GValue * value, GParamSpec * pspec)
768 {
769   GstSrtpEnc *filter = GST_SRTP_ENC (object);
770   GST_OBJECT_LOCK (filter);
771 
772   switch (prop_id) {
773     case PROP_MKEY:
774       if (filter->key)
775         g_value_set_boxed (value, filter->key);
776       break;
777     case PROP_RTP_CIPHER:
778       g_value_set_enum (value, filter->rtp_cipher);
779       break;
780     case PROP_RTCP_CIPHER:
781       g_value_set_enum (value, filter->rtcp_cipher);
782       break;
783     case PROP_RTP_AUTH:
784       g_value_set_enum (value, filter->rtp_auth);
785       break;
786     case PROP_RTCP_AUTH:
787       g_value_set_enum (value, filter->rtcp_auth);
788       break;
789     case PROP_RANDOM_KEY:
790       g_value_set_boolean (value, filter->random_key);
791       break;
792     case PROP_REPLAY_WINDOW_SIZE:
793       g_value_set_uint (value, filter->replay_window_size);
794       break;
795     case PROP_ALLOW_REPEAT_TX:
796       g_value_set_boolean (value, filter->allow_repeat_tx);
797       break;
798     case PROP_STATS:
799       g_value_take_boxed (value, gst_srtp_enc_create_stats (filter));
800       break;
801 #ifdef HAVE_SRTP2
802     case PROP_MKI:
803       if (filter->mki)
804         g_value_set_boxed (value, filter->mki);
805       break;
806 #endif
807     default:
808       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
809       break;
810   }
811 
812   GST_OBJECT_UNLOCK (filter);
813 }
814 
815 /* Returns the source pad linked with the sink pad
816  */
817 static GstPad *
get_rtp_other_pad(GstPad * pad)818 get_rtp_other_pad (GstPad * pad)
819 {
820   return GST_PAD (gst_pad_get_element_private (pad));
821 }
822 
823 /* Release a sink pad and it's linked source pad
824  */
825 static void
gst_srtp_enc_release_pad(GstElement * element,GstPad * sinkpad)826 gst_srtp_enc_release_pad (GstElement * element, GstPad * sinkpad)
827 {
828   GstPad *srcpad;
829 
830   GST_INFO_OBJECT (element, "Releasing pad %s:%s",
831       GST_DEBUG_PAD_NAME (sinkpad));
832 
833   srcpad = GST_PAD (gst_pad_get_element_private (sinkpad));
834   gst_pad_set_element_private (sinkpad, NULL);
835   gst_pad_set_element_private (srcpad, NULL);
836 
837   /* deactivate from source to sink */
838   gst_pad_set_active (srcpad, FALSE);
839   gst_pad_set_active (sinkpad, FALSE);
840 
841   /* remove pads */
842   gst_element_remove_pad (element, srcpad);
843   gst_element_remove_pad (element, sinkpad);
844 }
845 
846 /* Common setcaps function
847  * Handles the link with other elements
848  */
849 static gboolean
gst_srtp_enc_sink_setcaps(GstPad * pad,GstSrtpEnc * filter,GstCaps * caps,gboolean is_rtcp)850 gst_srtp_enc_sink_setcaps (GstPad * pad, GstSrtpEnc * filter,
851     GstCaps * caps, gboolean is_rtcp)
852 {
853   GstPad *otherpad = NULL;
854   GstStructure *ps = NULL;
855   gboolean ret = FALSE;
856 
857   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
858 
859   caps = gst_caps_copy (caps);
860 
861   ps = gst_caps_get_structure (caps, 0);
862 
863   GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
864 
865   if (is_rtcp)
866     gst_structure_set_name (ps, "application/x-srtcp");
867   else
868     gst_structure_set_name (ps, "application/x-srtp");
869 
870   GST_OBJECT_LOCK (filter);
871 
872   if (gst_structure_has_field_typed (ps, "ssrc", G_TYPE_UINT)) {
873     guint ssrc;
874     gst_structure_get_uint (ps, "ssrc", &ssrc);
875     g_hash_table_add (filter->ssrcs_set, GUINT_TO_POINTER (ssrc));
876   }
877 
878   if (HAS_CRYPTO (filter))
879     gst_structure_set (ps, "srtp-key", GST_TYPE_BUFFER, filter->key, NULL);
880 
881 #ifdef HAVE_SRTP2
882   if (filter->mki)
883     gst_structure_set (ps, "mki", GST_TYPE_BUFFER, filter->mki, NULL);
884 #endif
885 
886   /* Add srtp-specific params to source caps */
887   gst_structure_set (ps,
888       "srtp-cipher", G_TYPE_STRING,
889       enum_nick_from_value (GST_TYPE_SRTP_CIPHER_TYPE, filter->rtp_cipher),
890       "srtp-auth", G_TYPE_STRING,
891       enum_nick_from_value (GST_TYPE_SRTP_AUTH_TYPE, filter->rtp_auth),
892       "srtcp-cipher", G_TYPE_STRING,
893       enum_nick_from_value (GST_TYPE_SRTP_CIPHER_TYPE, filter->rtcp_cipher),
894       "srtcp-auth", G_TYPE_STRING,
895       enum_nick_from_value (GST_TYPE_SRTP_AUTH_TYPE, filter->rtcp_auth), NULL);
896 
897   GST_OBJECT_UNLOCK (filter);
898 
899   GST_DEBUG_OBJECT (pad, "Source caps: %" GST_PTR_FORMAT, caps);
900 
901   /* Set caps on source pad */
902   otherpad = get_rtp_other_pad (pad);
903 
904   ret = gst_pad_set_caps (otherpad, caps);
905 
906   gst_caps_unref (caps);
907 
908   return ret;
909 }
910 
911 static gboolean
gst_srtp_enc_sink_query(GstPad * pad,GstObject * parent,GstQuery * query,gboolean is_rtcp)912 gst_srtp_enc_sink_query (GstPad * pad, GstObject * parent, GstQuery * query,
913     gboolean is_rtcp)
914 {
915   switch (GST_QUERY_TYPE (query)) {
916     case GST_QUERY_CAPS:
917     {
918       GstCaps *filter = NULL;
919       GstCaps *other_filter = NULL;
920       GstPad *otherpad;
921       GstCaps *other_caps;
922       GstCaps *ret;
923       GstCaps *template_caps;
924       int i;
925 
926       otherpad = get_rtp_other_pad (pad);
927 
928       gst_query_parse_caps (query, &filter);
929       if (filter) {
930         other_filter = gst_caps_copy (filter);
931 
932         for (i = 0; i < gst_caps_get_size (other_filter); i++) {
933           GstStructure *ps = gst_caps_get_structure (other_filter, i);
934           if (is_rtcp)
935             gst_structure_set_name (ps, "application/x-srtcp");
936           else
937             gst_structure_set_name (ps, "application/x-srtp");
938         }
939       }
940 
941       other_caps = gst_pad_peer_query_caps (otherpad, other_filter);
942 
943       if (other_filter)
944         gst_caps_unref (other_filter);
945 
946       if (!other_caps)
947         goto return_template;
948 
949       template_caps = gst_pad_get_pad_template_caps (otherpad);
950       ret = gst_caps_intersect_full (other_caps, template_caps,
951           GST_CAPS_INTERSECT_FIRST);
952       gst_caps_unref (other_caps);
953       gst_caps_unref (template_caps);
954 
955       ret = gst_caps_make_writable (ret);
956 
957       for (i = 0; i < gst_caps_get_size (ret); i++) {
958         GstStructure *ps = gst_caps_get_structure (ret, i);
959         if (is_rtcp)
960           gst_structure_set_name (ps, "application/x-rtcp");
961         else
962           gst_structure_set_name (ps, "application/x-rtp");
963         gst_structure_remove_fields (ps, "srtp-key", "srtp-cipher", "srtp-auth",
964             "srtcp-cipher", "srtcp-auth", "mki", NULL);
965       }
966 
967       gst_query_set_caps_result (query, ret);
968       gst_caps_unref (ret);
969       return TRUE;
970     return_template:
971 
972       ret = gst_pad_get_pad_template_caps (pad);
973       gst_query_set_caps_result (query, ret);
974       gst_caps_unref (ret);
975 
976       return TRUE;
977     }
978     default:
979       return gst_pad_query_default (pad, parent, query);
980   }
981 }
982 
983 static gboolean
gst_srtp_enc_sink_query_rtp(GstPad * pad,GstObject * parent,GstQuery * query)984 gst_srtp_enc_sink_query_rtp (GstPad * pad, GstObject * parent, GstQuery * query)
985 {
986   return gst_srtp_enc_sink_query (pad, parent, query, FALSE);
987 }
988 
989 static gboolean
gst_srtp_enc_sink_query_rtcp(GstPad * pad,GstObject * parent,GstQuery * query)990 gst_srtp_enc_sink_query_rtcp (GstPad * pad, GstObject * parent,
991     GstQuery * query)
992 {
993   return gst_srtp_enc_sink_query (pad, parent, query, TRUE);
994 }
995 
996 static GstIterator *
gst_srtp_enc_iterate_internal_links(GstPad * pad,GstObject * parent,gboolean is_rtcp)997 gst_srtp_enc_iterate_internal_links (GstPad * pad, GstObject * parent,
998     gboolean is_rtcp)
999 {
1000   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1001   GstPad *otherpad = NULL;
1002   GstIterator *it = NULL;
1003 
1004   otherpad = get_rtp_other_pad (pad);
1005 
1006   if (otherpad) {
1007     GValue val = { 0 };
1008 
1009     g_value_init (&val, GST_TYPE_PAD);
1010     g_value_set_object (&val, otherpad);
1011     it = gst_iterator_new_single (GST_TYPE_PAD, &val);
1012     g_value_unset (&val);
1013   } else {
1014     GST_ELEMENT_ERROR (GST_ELEMENT_CAST (filter), CORE, PAD, (NULL),
1015         ("Unable to get linked pad"));
1016   }
1017 
1018   return it;
1019 }
1020 
1021 static GstIterator *
gst_srtp_enc_iterate_internal_links_rtp(GstPad * pad,GstObject * parent)1022 gst_srtp_enc_iterate_internal_links_rtp (GstPad * pad, GstObject * parent)
1023 {
1024   return gst_srtp_enc_iterate_internal_links (pad, parent, FALSE);
1025 }
1026 
1027 static GstIterator *
gst_srtp_enc_iterate_internal_links_rtcp(GstPad * pad,GstObject * parent)1028 gst_srtp_enc_iterate_internal_links_rtcp (GstPad * pad, GstObject * parent)
1029 {
1030   return gst_srtp_enc_iterate_internal_links (pad, parent, TRUE);
1031 }
1032 
1033 
1034 static void
gst_srtp_enc_replace_random_key(GstSrtpEnc * filter)1035 gst_srtp_enc_replace_random_key (GstSrtpEnc * filter)
1036 {
1037   guint i;
1038   guint key_size;
1039   GstMapInfo map;
1040 
1041   GST_DEBUG_OBJECT (filter, "Generating random key");
1042 
1043   if (filter->key)
1044     gst_buffer_unref (filter->key);
1045 
1046   key_size = max_cipher_key_size (filter);
1047 
1048   filter->key = gst_buffer_new_allocate (NULL, key_size, NULL);
1049 
1050   gst_buffer_map (filter->key, &map, GST_MAP_WRITE);
1051   for (i = 0; i < map.size; i += 4)
1052     GST_WRITE_UINT32_BE (map.data + i, g_random_int ());
1053   gst_buffer_unmap (filter->key, &map);
1054 
1055   filter->key_changed = TRUE;
1056 }
1057 
1058 static GstFlowReturn
gst_srtp_enc_check_set_caps(GstSrtpEnc * filter,GstPad * pad,gboolean is_rtcp)1059 gst_srtp_enc_check_set_caps (GstSrtpEnc * filter, GstPad * pad,
1060     gboolean is_rtcp)
1061 {
1062   gboolean do_setcaps = FALSE;
1063 
1064   GST_OBJECT_LOCK (filter);
1065 
1066   if (filter->key_changed) {
1067     gst_srtp_enc_reset_no_lock (filter);
1068     do_setcaps = TRUE;
1069   }
1070 
1071   if (filter->first_session) {
1072     srtp_err_status_t status = gst_srtp_enc_create_session (filter);
1073 
1074     if (status != srtp_err_status_ok) {
1075       GST_OBJECT_UNLOCK (filter);
1076       GST_ELEMENT_ERROR (filter, LIBRARY, INIT,
1077           ("Could not initialize SRTP encoder"),
1078           ("Failed to add stream to SRTP encoder (err: %d)", status));
1079       return GST_FLOW_ERROR;
1080     }
1081   }
1082 
1083   GST_OBJECT_UNLOCK (filter);
1084 
1085   /* Update source caps if asked */
1086   if (do_setcaps) {
1087     GstCaps *caps;
1088 
1089     caps = gst_pad_get_current_caps (pad);
1090     if (!gst_srtp_enc_sink_setcaps (pad, filter, caps, is_rtcp)) {
1091       gst_caps_unref (caps);
1092       return GST_FLOW_NOT_NEGOTIATED;
1093     }
1094     gst_caps_unref (caps);
1095   }
1096 
1097   return GST_FLOW_OK;
1098 }
1099 
1100 static GstFlowReturn
gst_srtp_enc_process_buffer(GstSrtpEnc * filter,GstPad * pad,GstBuffer * buf,gboolean is_rtcp,GstBuffer ** outbuf_ptr)1101 gst_srtp_enc_process_buffer (GstSrtpEnc * filter, GstPad * pad,
1102     GstBuffer * buf, gboolean is_rtcp, GstBuffer ** outbuf_ptr)
1103 {
1104   GstFlowReturn ret = GST_FLOW_OK;
1105   gint size_max, size;
1106   GstBuffer *bufout = NULL;
1107   GstMapInfo mapout;
1108   srtp_err_status_t err;
1109 
1110   /* Create a bigger buffer to add protection */
1111   size = gst_buffer_get_size (buf);
1112   size_max = size + SRTP_MAX_TRAILER_LEN + 10;
1113   bufout = gst_buffer_new_allocate (NULL, size_max, NULL);
1114 
1115   gst_buffer_map (bufout, &mapout, GST_MAP_READWRITE);
1116 
1117   gst_buffer_extract (buf, 0, mapout.data, size);
1118 
1119   GST_OBJECT_LOCK (filter);
1120 
1121   gst_srtp_init_event_reporter ();
1122 
1123   if (filter->session == NULL) {
1124     /* The rtcp session disappeared (element shutting down) */
1125     GST_OBJECT_UNLOCK (filter);
1126     ret = GST_FLOW_FLUSHING;
1127     goto fail;
1128   }
1129 #ifdef HAVE_SRTP2
1130   if (is_rtcp)
1131     err = srtp_protect_rtcp_mki (filter->session, mapout.data, &size,
1132         (filter->mki != NULL), 0);
1133   else
1134     err = srtp_protect_mki (filter->session, mapout.data, &size,
1135         (filter->mki != NULL), 0);
1136 #else
1137   if (is_rtcp)
1138     err = srtp_protect_rtcp (filter->session, mapout.data, &size);
1139   else
1140     err = srtp_protect (filter->session, mapout.data, &size);
1141 #endif
1142 
1143   GST_OBJECT_UNLOCK (filter);
1144 
1145   gst_buffer_unmap (bufout, &mapout);
1146 
1147   if (err == srtp_err_status_ok) {
1148     /* Buffer protected */
1149     gst_buffer_set_size (bufout, size);
1150     gst_buffer_copy_into (bufout, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1151 
1152     GST_LOG_OBJECT (pad, "Encoding %s buffer of size %d",
1153         is_rtcp ? "RTCP" : "RTP", size);
1154 
1155   } else if (err == srtp_err_status_key_expired) {
1156 
1157     GST_ELEMENT_ERROR (GST_ELEMENT_CAST (filter), STREAM, ENCODE,
1158         ("Key usage limit has been reached"),
1159         ("Unable to protect buffer (hard key usage limit reached)"));
1160     ret = GST_FLOW_ERROR;
1161     goto fail;
1162 
1163   } else {
1164     /* srtp_protect failed */
1165     GST_ELEMENT_ERROR (filter, LIBRARY, FAILED, (NULL),
1166         ("Unable to protect buffer (protect failed) code %d", err));
1167     ret = GST_FLOW_ERROR;
1168     goto fail;
1169   }
1170 
1171   *outbuf_ptr = bufout;
1172   return ret;
1173 
1174 fail:
1175   gst_buffer_unref (bufout);
1176   return ret;
1177 }
1178 
1179 static GstFlowReturn
gst_srtp_enc_chain(GstPad * pad,GstObject * parent,GstBuffer * buf,gboolean is_rtcp)1180 gst_srtp_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf,
1181     gboolean is_rtcp)
1182 {
1183   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1184   GstFlowReturn ret = GST_FLOW_OK;
1185   GstPad *otherpad;
1186   GstBuffer *bufout = NULL;
1187 
1188   if ((ret = gst_srtp_enc_check_set_caps (filter, pad, is_rtcp)) != GST_FLOW_OK) {
1189     goto out;
1190   }
1191 
1192   GST_OBJECT_LOCK (filter);
1193 
1194   if (!HAS_CRYPTO (filter)) {
1195     GST_OBJECT_UNLOCK (filter);
1196     otherpad = get_rtp_other_pad (pad);
1197     return gst_pad_push (otherpad, buf);
1198   }
1199 
1200   GST_OBJECT_UNLOCK (filter);
1201 
1202   ret = gst_srtp_enc_process_buffer (filter, pad, buf, is_rtcp, &bufout);
1203   if (ret != GST_FLOW_OK)
1204     goto out;
1205 
1206   /* Push buffer to source pad */
1207   otherpad = get_rtp_other_pad (pad);
1208   ret = gst_pad_push (otherpad, bufout);
1209   bufout = NULL;
1210 
1211   if (ret != GST_FLOW_OK)
1212     goto out;
1213 
1214   GST_OBJECT_LOCK (filter);
1215 
1216   if (gst_srtp_get_soft_limit_reached ()) {
1217     GST_OBJECT_UNLOCK (filter);
1218     g_signal_emit (filter, gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT], 0);
1219     GST_OBJECT_LOCK (filter);
1220     if (filter->random_key && !filter->key_changed)
1221       gst_srtp_enc_replace_random_key (filter);
1222   }
1223 
1224   GST_OBJECT_UNLOCK (filter);
1225 
1226 out:
1227   gst_buffer_unref (buf);
1228   return ret;
1229 }
1230 
1231 static gboolean
process_buffer_it(GstBuffer ** buffer,guint index,gpointer user_data)1232 process_buffer_it (GstBuffer ** buffer, guint index, gpointer user_data)
1233 {
1234   ProcessBufferItData *data = user_data;
1235   GstBuffer *bufout;
1236   GstFlowReturn ret;
1237 
1238   ret = gst_srtp_enc_process_buffer (data->filter, data->pad, *buffer,
1239       data->is_rtcp, &bufout);
1240   if (ret != GST_FLOW_OK) {
1241     data->flowret = ret;
1242     return FALSE;
1243   }
1244 
1245   gst_buffer_list_add (data->out_list, bufout);
1246 
1247   return TRUE;
1248 }
1249 
1250 static GstFlowReturn
gst_srtp_enc_chain_list(GstPad * pad,GstObject * parent,GstBufferList * buf_list,gboolean is_rtcp)1251 gst_srtp_enc_chain_list (GstPad * pad, GstObject * parent,
1252     GstBufferList * buf_list, gboolean is_rtcp)
1253 {
1254   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1255   GstFlowReturn ret = GST_FLOW_OK;
1256   GstPad *otherpad;
1257   GstBufferList *out_list = NULL;
1258   ProcessBufferItData process_data;
1259 
1260   GST_LOG_OBJECT (pad, "Buffer chain with list of %d",
1261       gst_buffer_list_length (buf_list));
1262 
1263   if (!gst_buffer_list_length (buf_list))
1264     goto out;
1265 
1266   if ((ret = gst_srtp_enc_check_set_caps (filter, pad, is_rtcp)) != GST_FLOW_OK)
1267     goto out;
1268 
1269   GST_OBJECT_LOCK (filter);
1270 
1271   if (!HAS_CRYPTO (filter)) {
1272     GST_OBJECT_UNLOCK (filter);
1273     otherpad = get_rtp_other_pad (pad);
1274     return gst_pad_push_list (otherpad, buf_list);
1275   }
1276 
1277   GST_OBJECT_UNLOCK (filter);
1278 
1279   out_list = gst_buffer_list_new ();
1280 
1281   process_data.filter = filter;
1282   process_data.pad = pad;
1283   process_data.is_rtcp = is_rtcp;
1284   process_data.out_list = out_list;
1285   process_data.flowret = GST_FLOW_OK;
1286 
1287   if (!gst_buffer_list_foreach (buf_list, process_buffer_it, &process_data)) {
1288     ret = process_data.flowret;
1289     goto out;
1290   }
1291 
1292   if (!gst_buffer_list_length (out_list)) {
1293     gst_buffer_list_unref (out_list);
1294     ret = GST_FLOW_OK;
1295     goto out;
1296   }
1297 
1298   /* Push buffer to source pad */
1299   otherpad = get_rtp_other_pad (pad);
1300   GST_LOG_OBJECT (pad, "Pushing buffer chain of %d",
1301       gst_buffer_list_length (buf_list));
1302   ret = gst_pad_push_list (otherpad, out_list);
1303 
1304   if (ret != GST_FLOW_OK) {
1305     goto out;
1306   }
1307 
1308   GST_OBJECT_LOCK (filter);
1309 
1310   if (gst_srtp_get_soft_limit_reached ()) {
1311     GST_OBJECT_UNLOCK (filter);
1312     g_signal_emit (filter, gst_srtp_enc_signals[SIGNAL_SOFT_LIMIT], 0);
1313     GST_OBJECT_LOCK (filter);
1314     if (filter->random_key && !filter->key_changed)
1315       gst_srtp_enc_replace_random_key (filter);
1316   }
1317 
1318   GST_OBJECT_UNLOCK (filter);
1319 
1320 out:
1321 
1322   gst_buffer_list_unref (buf_list);
1323 
1324   return ret;
1325 }
1326 
1327 static GstFlowReturn
gst_srtp_enc_chain_rtp(GstPad * pad,GstObject * parent,GstBuffer * buf)1328 gst_srtp_enc_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buf)
1329 {
1330   return gst_srtp_enc_chain (pad, parent, buf, FALSE);
1331 }
1332 
1333 static GstFlowReturn
gst_srtp_enc_chain_rtcp(GstPad * pad,GstObject * parent,GstBuffer * buf)1334 gst_srtp_enc_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buf)
1335 {
1336   return gst_srtp_enc_chain (pad, parent, buf, TRUE);
1337 }
1338 
1339 static GstFlowReturn
gst_srtp_enc_chain_list_rtp(GstPad * pad,GstObject * parent,GstBufferList * buf_list)1340 gst_srtp_enc_chain_list_rtp (GstPad * pad, GstObject * parent,
1341     GstBufferList * buf_list)
1342 {
1343   return gst_srtp_enc_chain_list (pad, parent, buf_list, FALSE);
1344 }
1345 
1346 static GstFlowReturn
gst_srtp_enc_chain_list_rtcp(GstPad * pad,GstObject * parent,GstBufferList * buf_list)1347 gst_srtp_enc_chain_list_rtcp (GstPad * pad, GstObject * parent,
1348     GstBufferList * buf_list)
1349 {
1350   return gst_srtp_enc_chain_list (pad, parent, buf_list, TRUE);
1351 }
1352 
1353 
1354 /* Change state
1355  */
1356 static GstStateChangeReturn
gst_srtp_enc_change_state(GstElement * element,GstStateChange transition)1357 gst_srtp_enc_change_state (GstElement * element, GstStateChange transition)
1358 {
1359   GstStateChangeReturn res;
1360   GstSrtpEnc *filter;
1361 
1362   filter = GST_SRTP_ENC (element);
1363 
1364   switch (transition) {
1365     case GST_STATE_CHANGE_NULL_TO_READY:
1366       if (filter->rtp_cipher != GST_SRTP_CIPHER_NULL ||
1367           filter->rtcp_cipher != GST_SRTP_CIPHER_NULL ||
1368           filter->rtp_auth != GST_SRTP_AUTH_NULL ||
1369           filter->rtcp_auth != GST_SRTP_AUTH_NULL) {
1370         if (!filter->key) {
1371           if (filter->random_key) {
1372             gst_srtp_enc_replace_random_key (filter);
1373           } else {
1374             GST_ERROR_OBJECT (element, "Need a key to get to READY");
1375             return GST_STATE_CHANGE_FAILURE;
1376           }
1377         }
1378       }
1379 
1380       /* RFC 3711 says in "3. SRTP Framework" that SRTCP message authentication
1381        * is MANDATORY. In case of GCM let the pipeline handle any errors.
1382        */
1383       if (filter->rtcp_cipher != GST_SRTP_CIPHER_AES_128_GCM
1384           && filter->rtcp_cipher != GST_SRTP_CIPHER_AES_256_GCM
1385           && filter->rtcp_cipher != GST_SRTP_CIPHER_NULL
1386           && filter->rtcp_auth == GST_SRTP_AUTH_NULL) {
1387         GST_ERROR_OBJECT (filter,
1388             "RTCP authentication can't be NULL if encryption is not NULL.");
1389         return GST_STATE_CHANGE_FAILURE;
1390       }
1391       GST_OBJECT_LOCK (filter);
1392       if (!filter->first_session)
1393         gst_srtp_enc_reset_no_lock (filter);
1394       GST_OBJECT_UNLOCK (filter);
1395       break;
1396     case GST_STATE_CHANGE_READY_TO_PAUSED:
1397       break;
1398     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1399       break;
1400     default:
1401       break;
1402   }
1403 
1404   res = GST_ELEMENT_CLASS (gst_srtp_enc_parent_class)->change_state (element,
1405       transition);
1406 
1407   switch (transition) {
1408     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1409       break;
1410     case GST_STATE_CHANGE_PAUSED_TO_READY:
1411       gst_srtp_enc_reset (filter);
1412       break;
1413     case GST_STATE_CHANGE_READY_TO_NULL:
1414       break;
1415     default:
1416       break;
1417   }
1418 
1419   return res;
1420 }
1421 
1422 static gboolean
gst_srtp_enc_sink_event(GstPad * pad,GstObject * parent,GstEvent * event,gboolean is_rtcp)1423 gst_srtp_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event,
1424     gboolean is_rtcp)
1425 {
1426   GstSrtpEnc *filter = GST_SRTP_ENC (parent);
1427   gboolean ret;
1428   GstPad *otherpad;
1429 
1430   otherpad = get_rtp_other_pad (pad);
1431 
1432   switch (GST_EVENT_TYPE (event)) {
1433     case GST_EVENT_FLUSH_STOP:
1434       GST_DEBUG_OBJECT (pad, "Encing event Flush stop (%d)",
1435           GST_EVENT_TYPE (event));
1436       gst_srtp_enc_reset (filter);
1437       ret = gst_pad_push_event (otherpad, event);
1438       break;
1439     case GST_EVENT_CAPS:
1440     {
1441       GstCaps *caps;
1442 
1443       gst_event_parse_caps (event, &caps);
1444       ret = gst_srtp_enc_sink_setcaps (pad, filter, caps, is_rtcp);
1445       gst_event_unref (event);
1446       break;
1447     }
1448     default:
1449       GST_DEBUG_OBJECT (pad, "Encing event default (%d)",
1450           GST_EVENT_TYPE (event));
1451       ret = gst_pad_event_default (pad, parent, event);
1452       break;
1453   }
1454 
1455   return ret;
1456 }
1457 
1458 static gboolean
gst_srtp_enc_sink_event_rtp(GstPad * pad,GstObject * parent,GstEvent * event)1459 gst_srtp_enc_sink_event_rtp (GstPad * pad, GstObject * parent, GstEvent * event)
1460 {
1461   return gst_srtp_enc_sink_event (pad, parent, event, FALSE);
1462 }
1463 
1464 static gboolean
gst_srtp_enc_sink_event_rtcp(GstPad * pad,GstObject * parent,GstEvent * event)1465 gst_srtp_enc_sink_event_rtcp (GstPad * pad, GstObject * parent,
1466     GstEvent * event)
1467 {
1468   return gst_srtp_enc_sink_event (pad, parent, event, TRUE);
1469 }
1470 
1471 /* entry point to initialize the plug-in
1472  * initialize the plug-in itself
1473  * register the element factories and other features
1474  */
1475 gboolean
gst_srtp_enc_plugin_init(GstPlugin * srtpenc)1476 gst_srtp_enc_plugin_init (GstPlugin * srtpenc)
1477 {
1478   GST_DEBUG_CATEGORY_INIT (gst_srtp_enc_debug, "srtpenc", 0, "SRTP Enc");
1479 
1480   return gst_element_register (srtpenc, "srtpenc", GST_RANK_NONE,
1481       GST_TYPE_SRTP_ENC);
1482 }
1483