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