1 /* GStreamer
2  * Copyright (C) <2014> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * gstmikey.h: various helper functions to manipulate mikey messages
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /**
23  * SECTION:gstmikey
24  * @title: GstMIKEYMessage
25  * @short_description: Helper methods for dealing with MIKEY messages
26  *
27  * The GstMIKEY helper functions makes it easy to parse and create MIKEY
28  * messages.
29  *
30  * Since: 1.4
31  */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <string.h>
37 
38 #include "gstmikey.h"
39 
40 GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYPayload, gst_mikey_payload);
41 GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYMessage, gst_mikey_message);
42 
43 static void
payload_destroy(GstMIKEYPayload ** payload)44 payload_destroy (GstMIKEYPayload ** payload)
45 {
46   gst_mikey_payload_unref (*payload);
47 }
48 
49 #define INIT_ARRAY(field, type, init_func)              \
50 G_STMT_START {                                          \
51   if (field)                                            \
52     g_array_set_size ((field), 0);                      \
53   else {                                                \
54     (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
55     g_array_set_clear_func ((field), (GDestroyNotify)init_func);        \
56   }                                                     \
57 } G_STMT_END
58 
59 #define FREE_ARRAY(field)         \
60 G_STMT_START {                    \
61   if (field)                      \
62     g_array_free ((field), TRUE); \
63   (field) = NULL;                 \
64 } G_STMT_END
65 
66 #define INIT_MEMDUP(field, data, len)            \
67 G_STMT_START {                                   \
68   g_free ((field));                              \
69   (field) = g_memdup (data, len);                \
70 } G_STMT_END
71 #define FREE_MEMDUP(field)                       \
72 G_STMT_START {                                   \
73   g_free ((field));                              \
74   (field) = NULL;                                \
75 } G_STMT_END
76 
77 
78 /* Key data transport payload (KEMAC) */
79 static guint
get_mac_len(GstMIKEYMacAlg mac_alg)80 get_mac_len (GstMIKEYMacAlg mac_alg)
81 {
82   guint len;
83 
84   switch (mac_alg) {
85     case GST_MIKEY_MAC_NULL:
86       len = 0;                  /* no MAC key */
87       break;
88     case GST_MIKEY_MAC_HMAC_SHA_1_160:
89       len = 20;                 /* 160 bits key */
90       break;
91     default:
92       len = -1;
93       break;
94   }
95   return len;
96 }
97 
98 /**
99  * gst_mikey_payload_kemac_set:
100  * @payload: a #GstMIKEYPayload
101  * @enc_alg: the #GstMIKEYEncAlg
102  * @mac_alg: a #GstMIKEYMacAlg
103  *
104  * Set the KEMAC parameters. @payload should point to a %GST_MIKEY_PT_KEMAC
105  * payload.
106  *
107  * Returns: %TRUE on success
108  *
109  * Since: 1.4
110  */
111 gboolean
gst_mikey_payload_kemac_set(GstMIKEYPayload * payload,GstMIKEYEncAlg enc_alg,GstMIKEYMacAlg mac_alg)112 gst_mikey_payload_kemac_set (GstMIKEYPayload * payload,
113     GstMIKEYEncAlg enc_alg, GstMIKEYMacAlg mac_alg)
114 {
115   GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
116 
117   g_return_val_if_fail (payload != NULL, FALSE);
118   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, FALSE);
119 
120   p->enc_alg = enc_alg;
121   p->mac_alg = mac_alg;
122   INIT_ARRAY (p->subpayloads, GstMIKEYPayload *, payload_destroy);
123 
124   return TRUE;
125 }
126 
127 static gboolean
gst_mikey_payload_kemac_dispose(GstMIKEYPayloadKEMAC * payload)128 gst_mikey_payload_kemac_dispose (GstMIKEYPayloadKEMAC * payload)
129 {
130   FREE_ARRAY (payload->subpayloads);
131 
132   return TRUE;
133 }
134 
135 static GstMIKEYPayloadKEMAC *
gst_mikey_payload_kemac_copy(const GstMIKEYPayloadKEMAC * payload)136 gst_mikey_payload_kemac_copy (const GstMIKEYPayloadKEMAC * payload)
137 {
138   guint i, len;
139   GstMIKEYPayloadKEMAC *copy = g_slice_dup (GstMIKEYPayloadKEMAC, payload);
140   gst_mikey_payload_kemac_set (&copy->pt, payload->enc_alg, payload->mac_alg);
141   len = payload->subpayloads->len;
142   for (i = 0; i < len; i++) {
143     GstMIKEYPayload *pay =
144         g_array_index (payload->subpayloads, GstMIKEYPayload *, i);
145     gst_mikey_payload_kemac_add_sub (&copy->pt, gst_mikey_payload_copy (pay));
146   }
147   return copy;
148 }
149 
150 /**
151  * gst_mikey_payload_kemac_get_n_sub:
152  * @payload: a #GstMIKEYPayload
153  *
154  * Get the number of sub payloads of @payload. @payload should be of type
155  * %GST_MIKEY_PT_KEMAC.
156  *
157  * Returns: the number of sub payloads in @payload
158  *
159  * Since: 1.4
160  */
161 guint
gst_mikey_payload_kemac_get_n_sub(const GstMIKEYPayload * payload)162 gst_mikey_payload_kemac_get_n_sub (const GstMIKEYPayload * payload)
163 {
164   GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
165 
166   g_return_val_if_fail (payload != NULL, 0);
167   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
168 
169   return p->subpayloads->len;
170 }
171 
172 /**
173  * gst_mikey_payload_kemac_get_sub:
174  * @payload: a #GstMIKEYPayload
175  * @idx: an index
176  *
177  * Get the sub payload of @payload at @idx. @payload should be of type
178  * %GST_MIKEY_PT_KEMAC.
179  *
180  * Returns: (transfer none): the #GstMIKEYPayload at @idx.
181  *
182  * Since: 1.4
183  */
184 const GstMIKEYPayload *
gst_mikey_payload_kemac_get_sub(const GstMIKEYPayload * payload,guint idx)185 gst_mikey_payload_kemac_get_sub (const GstMIKEYPayload * payload, guint idx)
186 {
187   GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
188 
189   g_return_val_if_fail (payload != NULL, 0);
190   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
191 
192   if (p->subpayloads->len <= idx)
193     return NULL;
194 
195   return g_array_index (p->subpayloads, GstMIKEYPayload *, idx);
196 }
197 
198 /**
199  * gst_mikey_payload_kemac_remove_sub:
200  * @payload: a #GstMIKEYPayload
201  * @idx: the index to remove
202  *
203  * Remove the sub payload at @idx in @payload.
204  *
205  * Returns: %TRUE on success.
206  *
207  * Since: 1.4
208  */
209 gboolean
gst_mikey_payload_kemac_remove_sub(GstMIKEYPayload * payload,guint idx)210 gst_mikey_payload_kemac_remove_sub (GstMIKEYPayload * payload, guint idx)
211 {
212   GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
213 
214   g_return_val_if_fail (payload != NULL, 0);
215   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
216   g_return_val_if_fail (p->subpayloads->len > idx, FALSE);
217 
218   g_array_remove_index (p->subpayloads, idx);
219 
220   return TRUE;
221 }
222 
223 /**
224  * gst_mikey_payload_kemac_add_sub:
225  * @payload: a #GstMIKEYPayload
226  * @newpay: (transfer full): a #GstMIKEYPayload to add
227  *
228  * Add a new sub payload to @payload.
229  *
230  * Returns: %TRUE on success.
231  *
232  * Since: 1.4
233  */
234 gboolean
gst_mikey_payload_kemac_add_sub(GstMIKEYPayload * payload,GstMIKEYPayload * newpay)235 gst_mikey_payload_kemac_add_sub (GstMIKEYPayload * payload,
236     GstMIKEYPayload * newpay)
237 {
238   GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
239 
240   g_return_val_if_fail (payload != NULL, 0);
241   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
242 
243   g_array_append_val (p->subpayloads, newpay);
244 
245   return TRUE;
246 }
247 
248 /* Envelope data payload (PKE) */
249 /**
250  * gst_mikey_payload_pke_set:
251  * @payload: a #GstMIKEYPayload
252  * @C: envelope key cache indicator
253  * @data_len: the length of @data
254  * @data: (array length=data_len): the encrypted envelope key
255  *
256  * Set the PKE values in @payload. @payload must be of type
257  * %GST_MIKEY_PT_PKE.
258  *
259  * Returns: %TRUE on success
260  *
261  * Since: 1.4
262  */
263 gboolean
gst_mikey_payload_pke_set(GstMIKEYPayload * payload,GstMIKEYCacheType C,guint16 data_len,const guint8 * data)264 gst_mikey_payload_pke_set (GstMIKEYPayload * payload, GstMIKEYCacheType C,
265     guint16 data_len, const guint8 * data)
266 {
267   GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload;
268 
269   g_return_val_if_fail (payload != NULL, FALSE);
270   g_return_val_if_fail (payload->type == GST_MIKEY_PT_PKE, FALSE);
271 
272   p->C = C;
273   p->data_len = data_len;
274   INIT_MEMDUP (p->data, data, data_len);
275 
276   return TRUE;
277 }
278 
279 static gboolean
gst_mikey_payload_pke_dispose(GstMIKEYPayloadPKE * payload)280 gst_mikey_payload_pke_dispose (GstMIKEYPayloadPKE * payload)
281 {
282   FREE_MEMDUP (payload->data);
283 
284   return TRUE;
285 }
286 
287 static GstMIKEYPayloadPKE *
gst_mikey_payload_pke_copy(const GstMIKEYPayloadPKE * payload)288 gst_mikey_payload_pke_copy (const GstMIKEYPayloadPKE * payload)
289 {
290   GstMIKEYPayloadPKE *copy = g_slice_dup (GstMIKEYPayloadPKE, payload);
291   gst_mikey_payload_pke_set (&copy->pt, payload->C, payload->data_len,
292       payload->data);
293   return copy;
294 }
295 
296 /* DH data payload (DH) */
297 /* Signature payload (SIGN) */
298 
299 /* Timestamp payload (T) */
300 static guint
get_ts_len(GstMIKEYTSType type)301 get_ts_len (GstMIKEYTSType type)
302 {
303   guint len;
304 
305   switch (type) {
306     case GST_MIKEY_TS_TYPE_NTP_UTC:
307     case GST_MIKEY_TS_TYPE_NTP:
308       len = 8;
309       break;
310     case GST_MIKEY_TS_TYPE_COUNTER:
311       len = 4;
312       break;
313     default:
314       len = -1;
315       break;
316   }
317   return len;
318 }
319 
320 /**
321  * gst_mikey_payload_t_set:
322  * @payload: a #GstMIKEYPayload
323  * @type: the #GstMIKEYTSType
324  * @ts_value: (array): the timestamp value
325  *
326  * Set the timestamp in a %GST_MIKEY_PT_T @payload.
327  *
328  * Returns: %TRUE on success
329  *
330  * Since: 1.4
331  */
332 gboolean
gst_mikey_payload_t_set(GstMIKEYPayload * payload,GstMIKEYTSType type,const guint8 * ts_value)333 gst_mikey_payload_t_set (GstMIKEYPayload * payload,
334     GstMIKEYTSType type, const guint8 * ts_value)
335 {
336   GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload;
337   guint ts_len;
338 
339   g_return_val_if_fail (payload != NULL, FALSE);
340   g_return_val_if_fail (payload->type == GST_MIKEY_PT_T, FALSE);
341 
342   if ((ts_len = get_ts_len (type)) == -1)
343     return FALSE;
344 
345   p->type = type;
346   INIT_MEMDUP (p->ts_value, ts_value, ts_len);
347 
348   return TRUE;
349 }
350 
351 static gboolean
gst_mikey_payload_t_dispose(GstMIKEYPayloadT * payload)352 gst_mikey_payload_t_dispose (GstMIKEYPayloadT * payload)
353 {
354   FREE_MEMDUP (payload->ts_value);
355 
356   return TRUE;
357 }
358 
359 static GstMIKEYPayloadT *
gst_mikey_payload_t_copy(const GstMIKEYPayloadT * payload)360 gst_mikey_payload_t_copy (const GstMIKEYPayloadT * payload)
361 {
362   GstMIKEYPayloadT *copy = g_slice_dup (GstMIKEYPayloadT, payload);
363   gst_mikey_payload_t_set (&copy->pt, payload->type, payload->ts_value);
364   return copy;
365 }
366 
367 /* ID payload (ID) */
368 /* Certificate Payload (CERT) */
369 /* Cert hash payload (CHASH)*/
370 /* Ver msg payload (V) */
371 /* Security Policy payload (SP)*/
372 static void
param_clear(GstMIKEYPayloadSPParam * param)373 param_clear (GstMIKEYPayloadSPParam * param)
374 {
375   FREE_MEMDUP (param->val);
376 }
377 
378 /**
379  * gst_mikey_payload_sp_set:
380  * @payload: a #GstMIKEYPayload
381  * @policy: the policy number
382  * @proto: a #GstMIKEYSecProto
383  *
384  * Set the Security Policy parameters for @payload.
385  *
386  * Returns: %TRUE on success
387  *
388  * Since: 1.4
389  */
390 gboolean
gst_mikey_payload_sp_set(GstMIKEYPayload * payload,guint policy,GstMIKEYSecProto proto)391 gst_mikey_payload_sp_set (GstMIKEYPayload * payload,
392     guint policy, GstMIKEYSecProto proto)
393 {
394   GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
395 
396   g_return_val_if_fail (payload != NULL, FALSE);
397   g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE);
398 
399   p->policy = policy;
400   p->proto = proto;
401   INIT_ARRAY (p->params, GstMIKEYPayloadSPParam, param_clear);
402 
403   return TRUE;
404 }
405 
406 static gboolean
gst_mikey_payload_sp_dispose(GstMIKEYPayloadSP * payload)407 gst_mikey_payload_sp_dispose (GstMIKEYPayloadSP * payload)
408 {
409   FREE_ARRAY (payload->params);
410 
411   return TRUE;
412 }
413 
414 static GstMIKEYPayloadSP *
gst_mikey_payload_sp_copy(const GstMIKEYPayloadSP * payload)415 gst_mikey_payload_sp_copy (const GstMIKEYPayloadSP * payload)
416 {
417   guint i, len;
418   GstMIKEYPayloadSP *copy = g_slice_dup (GstMIKEYPayloadSP, payload);
419   gst_mikey_payload_sp_set (&copy->pt, payload->policy, payload->proto);
420   len = payload->params->len;
421   for (i = 0; i < len; i++) {
422     GstMIKEYPayloadSPParam *param = &g_array_index (payload->params,
423         GstMIKEYPayloadSPParam, i);
424     gst_mikey_payload_sp_add_param (&copy->pt, param->type, param->len,
425         param->val);
426   }
427   return copy;
428 }
429 
430 /**
431  * gst_mikey_payload_sp_get_n_params:
432  * @payload: a #GstMIKEYPayload
433  *
434  * Get the number of security policy parameters in a %GST_MIKEY_PT_SP
435  * @payload.
436  *
437  * Returns: the number of parameters in @payload
438  *
439  * Since: 1.4
440  */
441 guint
gst_mikey_payload_sp_get_n_params(const GstMIKEYPayload * payload)442 gst_mikey_payload_sp_get_n_params (const GstMIKEYPayload * payload)
443 {
444   GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
445 
446   g_return_val_if_fail (payload != NULL, 0);
447   g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, 0);
448 
449   return p->params->len;
450 
451 }
452 
453 /**
454  * gst_mikey_payload_sp_get_param:
455  * @payload: a #GstMIKEYPayload
456  * @idx: an index
457  *
458  * Get the Security Policy parameter in a %GST_MIKEY_PT_SP @payload
459  * at @idx.
460  *
461  * Returns: the #GstMIKEYPayloadSPParam at @idx in @payload
462  *
463  * Since: 1.4
464  */
465 const GstMIKEYPayloadSPParam *
gst_mikey_payload_sp_get_param(const GstMIKEYPayload * payload,guint idx)466 gst_mikey_payload_sp_get_param (const GstMIKEYPayload * payload, guint idx)
467 {
468   GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
469 
470   g_return_val_if_fail (payload != NULL, NULL);
471   g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, NULL);
472 
473   if (p->params->len <= idx)
474     return NULL;
475 
476   return &g_array_index (p->params, GstMIKEYPayloadSPParam, idx);
477 }
478 
479 /**
480  * gst_mikey_payload_sp_remove_param:
481  * @payload: a #GstMIKEYPayload
482  * @idx: an index
483  *
484  * Remove the Security Policy parameters from a %GST_MIKEY_PT_SP
485  * @payload at @idx.
486  *
487  * Returns: %TRUE on success
488  *
489  * Since: 1.4
490  */
491 gboolean
gst_mikey_payload_sp_remove_param(GstMIKEYPayload * payload,guint idx)492 gst_mikey_payload_sp_remove_param (GstMIKEYPayload * payload, guint idx)
493 {
494   GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
495 
496   g_return_val_if_fail (payload != NULL, FALSE);
497   g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE);
498   g_return_val_if_fail (p->params->len > idx, FALSE);
499 
500   g_array_remove_index (p->params, idx);
501 
502   return TRUE;
503 }
504 
505 /**
506  * gst_mikey_payload_sp_add_param:
507  * @payload: a #GstMIKEYPayload
508  * @type: a type
509  * @len: a length
510  * @val: (array length=len): @len bytes of data
511  *
512  * Add a new parameter to the %GST_MIKEY_PT_SP @payload with @type, @len
513  * and @val.
514  *
515  * Returns: %TRUE on success
516  *
517  * Since: 1.4
518  */
519 gboolean
gst_mikey_payload_sp_add_param(GstMIKEYPayload * payload,guint8 type,guint8 len,const guint8 * val)520 gst_mikey_payload_sp_add_param (GstMIKEYPayload * payload,
521     guint8 type, guint8 len, const guint8 * val)
522 {
523   GstMIKEYPayloadSPParam param = { 0 };
524   GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
525 
526   g_return_val_if_fail (payload != NULL, FALSE);
527   g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE);
528 
529   param.type = type;
530   param.len = len;
531   INIT_MEMDUP (param.val, val, len);
532 
533   g_array_append_val (p->params, param);
534 
535   return TRUE;
536 }
537 
538 /* RAND payload (RAND) */
539 /**
540  * gst_mikey_payload_rand_set:
541  * @payload: a #GstMIKEYPayload
542  * @len: the length of @rand
543  * @rand: (array length=len): random values
544  *
545  * Set the random values in a %GST_MIKEY_PT_RAND @payload.
546  *
547  * Returns: %TRUE on success
548  *
549  * Since: 1.4
550  */
551 gboolean
gst_mikey_payload_rand_set(GstMIKEYPayload * payload,guint8 len,const guint8 * rand)552 gst_mikey_payload_rand_set (GstMIKEYPayload * payload, guint8 len,
553     const guint8 * rand)
554 {
555   GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload;
556 
557   g_return_val_if_fail (payload != NULL, FALSE);
558   g_return_val_if_fail (payload->type == GST_MIKEY_PT_RAND, FALSE);
559 
560   p->len = len;
561   INIT_MEMDUP (p->rand, rand, len);
562 
563   return TRUE;
564 }
565 
566 static gboolean
gst_mikey_payload_rand_dispose(GstMIKEYPayloadRAND * payload)567 gst_mikey_payload_rand_dispose (GstMIKEYPayloadRAND * payload)
568 {
569   FREE_MEMDUP (payload->rand);
570 
571   return TRUE;
572 }
573 
574 static GstMIKEYPayloadRAND *
gst_mikey_payload_rand_copy(const GstMIKEYPayloadRAND * payload)575 gst_mikey_payload_rand_copy (const GstMIKEYPayloadRAND * payload)
576 {
577   GstMIKEYPayloadRAND *copy = g_slice_dup (GstMIKEYPayloadRAND, payload);
578   gst_mikey_payload_rand_set (&copy->pt, payload->len, payload->rand);
579   return copy;
580 }
581 
582 
583 
584 /* Error payload (ERR) */
585 /* Key data sub-payload */
586 
587 /**
588  * gst_mikey_payload_key_data_set_key:
589  * @payload: a #GstMIKEYPayload
590  * @key_type: a #GstMIKEYKeyDataType
591  * @key_len: the length of @key_data
592  * @key_data: (array length=key_len): the key of type @key_type
593  *
594  * Set @key_len bytes of @key_data of type @key_type as the key for the
595  * %GST_MIKEY_PT_KEY_DATA @payload.
596  *
597  * Returns: %TRUE on success
598  *
599  * Since: 1.4
600  */
601 gboolean
gst_mikey_payload_key_data_set_key(GstMIKEYPayload * payload,GstMIKEYKeyDataType key_type,guint16 key_len,const guint8 * key_data)602 gst_mikey_payload_key_data_set_key (GstMIKEYPayload * payload,
603     GstMIKEYKeyDataType key_type, guint16 key_len, const guint8 * key_data)
604 {
605   GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
606 
607   g_return_val_if_fail (payload != NULL, FALSE);
608   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE);
609   g_return_val_if_fail (key_len > 0 && key_data != NULL, FALSE);
610 
611   p->key_type = key_type;
612   p->key_len = key_len;
613   INIT_MEMDUP (p->key_data, key_data, key_len);
614 
615   return TRUE;
616 }
617 
618 /**
619  * gst_mikey_payload_key_data_set_salt:
620  * @payload: a #GstMIKEYPayload
621  * @salt_len: the length of @salt_data
622  * @salt_data: (array length=salt_len) (allow-none): the salt
623  *
624  * Set the salt key data. If @salt_len is 0 and @salt_data is %NULL, the
625  * salt data will be removed.
626  *
627  * Returns: %TRUE on success
628  *
629  * Since: 1.4
630  */
631 gboolean
gst_mikey_payload_key_data_set_salt(GstMIKEYPayload * payload,guint16 salt_len,const guint8 * salt_data)632 gst_mikey_payload_key_data_set_salt (GstMIKEYPayload * payload,
633     guint16 salt_len, const guint8 * salt_data)
634 {
635   GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
636 
637   g_return_val_if_fail (payload != NULL, FALSE);
638   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE);
639   g_return_val_if_fail ((salt_len == 0 && salt_data == NULL) ||
640       (salt_len > 0 && salt_data != NULL), FALSE);
641 
642   p->salt_len = salt_len;
643   INIT_MEMDUP (p->salt_data, salt_data, salt_len);
644 
645   return TRUE;
646 }
647 
648 /* Key validity data */
649 
650 /**
651  * gst_mikey_payload_key_data_set_spi:
652  * @payload: a #GstMIKEYPayload
653  * @spi_len: the length of @spi_data
654  * @spi_data: (array length=spi_len): the SPI/MKI data
655  *
656  * Set the SPI/MKI validity in the %GST_MIKEY_PT_KEY_DATA @payload.
657  *
658  * Returns: %TRUE on success
659  *
660  * Since: 1.4
661  */
662 gboolean
gst_mikey_payload_key_data_set_spi(GstMIKEYPayload * payload,guint8 spi_len,const guint8 * spi_data)663 gst_mikey_payload_key_data_set_spi (GstMIKEYPayload * payload,
664     guint8 spi_len, const guint8 * spi_data)
665 {
666   GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
667 
668   g_return_val_if_fail (payload != NULL, FALSE);
669   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE);
670   g_return_val_if_fail ((spi_len == 0 && spi_data == NULL) ||
671       (spi_len > 0 && spi_data != NULL), FALSE);
672 
673   p->kv_type = GST_MIKEY_KV_SPI;
674   p->kv_len[0] = spi_len;
675   INIT_MEMDUP (p->kv_data[0], spi_data, spi_len);
676   p->kv_len[1] = 0;
677   FREE_MEMDUP (p->kv_data[1]);
678 
679   return TRUE;
680 }
681 
682 /**
683  * gst_mikey_payload_key_data_set_interval:
684  * @payload: a #GstMIKEYPayload
685  * @vf_len: the length of @vf_data
686  * @vf_data: (array length=vf_data): the Valid From data
687  * @vt_len: the length of @vt_data
688  * @vt_data: (array length=vt_len): the Valid To data
689  *
690  * Set the key validity period in the %GST_MIKEY_PT_KEY_DATA @payload.
691  *
692  * Returns: %TRUE on success
693  *
694  * Since: 1.4
695  */
696 gboolean
gst_mikey_payload_key_data_set_interval(GstMIKEYPayload * payload,guint8 vf_len,const guint8 * vf_data,guint8 vt_len,const guint8 * vt_data)697 gst_mikey_payload_key_data_set_interval (GstMIKEYPayload * payload,
698     guint8 vf_len, const guint8 * vf_data, guint8 vt_len,
699     const guint8 * vt_data)
700 {
701   GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
702 
703   g_return_val_if_fail (payload != NULL, FALSE);
704   g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE);
705   g_return_val_if_fail ((vf_len == 0 && vf_data == NULL) ||
706       (vf_len > 0 && vf_data != NULL), FALSE);
707   g_return_val_if_fail ((vt_len == 0 && vt_data == NULL) ||
708       (vt_len > 0 && vt_data != NULL), FALSE);
709 
710   p->kv_type = GST_MIKEY_KV_INTERVAL;
711   p->kv_len[0] = vf_len;
712   INIT_MEMDUP (p->kv_data[0], vf_data, vf_len);
713   p->kv_len[1] = vt_len;
714   INIT_MEMDUP (p->kv_data[1], vt_data, vt_len);
715 
716   return TRUE;
717 }
718 
719 static gboolean
gst_mikey_payload_key_data_dispose(GstMIKEYPayloadKeyData * payload)720 gst_mikey_payload_key_data_dispose (GstMIKEYPayloadKeyData * payload)
721 {
722   FREE_MEMDUP (payload->key_data);
723   FREE_MEMDUP (payload->salt_data);
724   FREE_MEMDUP (payload->kv_data[0]);
725   FREE_MEMDUP (payload->kv_data[1]);
726 
727   return TRUE;
728 }
729 
730 static GstMIKEYPayloadKeyData *
gst_mikey_payload_key_data_copy(const GstMIKEYPayloadKeyData * payload)731 gst_mikey_payload_key_data_copy (const GstMIKEYPayloadKeyData * payload)
732 {
733   GstMIKEYPayloadKeyData *copy = g_slice_dup (GstMIKEYPayloadKeyData, payload);
734   gst_mikey_payload_key_data_set_key (&copy->pt, payload->key_type,
735       payload->key_len, payload->key_data);
736   gst_mikey_payload_key_data_set_salt (&copy->pt, payload->salt_len,
737       payload->salt_data);
738   if (payload->kv_type == GST_MIKEY_KV_SPI)
739     gst_mikey_payload_key_data_set_spi (&copy->pt, payload->kv_len[0],
740         payload->kv_data[0]);
741   else if (payload->kv_type == GST_MIKEY_KV_INTERVAL)
742     gst_mikey_payload_key_data_set_interval (&copy->pt, payload->kv_len[0],
743         payload->kv_data[0], payload->kv_len[1], payload->kv_data[1]);
744   else {
745     FREE_MEMDUP (copy->kv_data[0]);
746     FREE_MEMDUP (copy->kv_data[1]);
747   }
748   return copy;
749 }
750 
751 /* General Extension Payload */
752 
753 static void
mikey_payload_free(GstMIKEYPayload * payload)754 mikey_payload_free (GstMIKEYPayload * payload)
755 {
756   g_slice_free1 (payload->len, payload);
757 }
758 
759 
760 /**
761  * gst_mikey_payload_new:
762  * @type: a #GstMIKEYPayloadType
763  *
764  * Make a new #GstMIKEYPayload with @type.
765  *
766  * Returns: (nullable): a new #GstMIKEYPayload or %NULL on failure.
767  *
768  * Since: 1.4
769  */
770 GstMIKEYPayload *
gst_mikey_payload_new(GstMIKEYPayloadType type)771 gst_mikey_payload_new (GstMIKEYPayloadType type)
772 {
773   guint len = 0;
774   GstMIKEYPayload *result;
775   GstMiniObjectCopyFunction copy;
776   GstMiniObjectDisposeFunction clear;
777 
778   switch (type) {
779     case GST_MIKEY_PT_KEMAC:
780       len = sizeof (GstMIKEYPayloadKEMAC);
781       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_kemac_dispose;
782       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_kemac_copy;
783       break;
784     case GST_MIKEY_PT_T:
785       len = sizeof (GstMIKEYPayloadT);
786       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_t_dispose;
787       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_t_copy;
788       break;
789     case GST_MIKEY_PT_PKE:
790       len = sizeof (GstMIKEYPayloadPKE);
791       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_pke_dispose;
792       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_pke_copy;
793       break;
794     case GST_MIKEY_PT_DH:
795     case GST_MIKEY_PT_SIGN:
796     case GST_MIKEY_PT_ID:
797     case GST_MIKEY_PT_CERT:
798     case GST_MIKEY_PT_CHASH:
799     case GST_MIKEY_PT_V:
800     case GST_MIKEY_PT_SP:
801       len = sizeof (GstMIKEYPayloadSP);
802       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_sp_dispose;
803       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_sp_copy;
804       break;
805     case GST_MIKEY_PT_RAND:
806       len = sizeof (GstMIKEYPayloadRAND);
807       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_rand_dispose;
808       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_rand_copy;
809       break;
810     case GST_MIKEY_PT_ERR:
811       break;
812     case GST_MIKEY_PT_KEY_DATA:
813       len = sizeof (GstMIKEYPayloadKeyData);
814       clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_key_data_dispose;
815       copy = (GstMiniObjectCopyFunction) gst_mikey_payload_key_data_copy;
816       break;
817     case GST_MIKEY_PT_GEN_EXT:
818     case GST_MIKEY_PT_LAST:
819       break;
820   }
821   if (len == 0)
822     return NULL;
823 
824   result = g_slice_alloc0 (len);
825   gst_mini_object_init (GST_MINI_OBJECT_CAST (result),
826       0, GST_TYPE_MIKEY_PAYLOAD, copy, clear,
827       (GstMiniObjectFreeFunction) mikey_payload_free);
828   result->type = type;
829   result->len = len;
830 
831   return result;
832 }
833 
834 static GstMIKEYMessage *
mikey_message_copy(GstMIKEYMessage * msg)835 mikey_message_copy (GstMIKEYMessage * msg)
836 {
837   GstMIKEYMessage *copy;
838   guint i, len;
839 
840   copy = gst_mikey_message_new ();
841 
842   gst_mikey_message_set_info (copy, msg->version, msg->type, msg->V,
843       msg->prf_func, msg->CSB_id, msg->map_type);
844 
845   len = msg->map_info->len;
846   for (i = 0; i < len; i++) {
847     const GstMIKEYMapSRTP *srtp = gst_mikey_message_get_cs_srtp (msg, i);
848     gst_mikey_message_add_cs_srtp (copy, srtp->policy, srtp->ssrc, srtp->roc);
849   }
850 
851   len = msg->payloads->len;
852   for (i = 0; i < len; i++) {
853     const GstMIKEYPayload *pay = gst_mikey_message_get_payload (msg, i);
854     gst_mikey_message_add_payload (copy, gst_mikey_payload_copy (pay));
855   }
856   return copy;
857 }
858 
859 static void
mikey_message_free(GstMIKEYMessage * msg)860 mikey_message_free (GstMIKEYMessage * msg)
861 {
862   FREE_ARRAY (msg->map_info);
863   FREE_ARRAY (msg->payloads);
864 
865   g_slice_free (GstMIKEYMessage, msg);
866 }
867 
868 /**
869  * gst_mikey_message_new:
870  *
871  * Make a new MIKEY message.
872  *
873  * Returns: a new #GstMIKEYMessage on success
874  *
875  * Since: 1.4
876  */
877 GstMIKEYMessage *
gst_mikey_message_new(void)878 gst_mikey_message_new (void)
879 {
880   GstMIKEYMessage *result;
881 
882   result = g_slice_new0 (GstMIKEYMessage);
883   gst_mini_object_init (GST_MINI_OBJECT_CAST (result),
884       0, GST_TYPE_MIKEY_MESSAGE,
885       (GstMiniObjectCopyFunction) mikey_message_copy, NULL,
886       (GstMiniObjectFreeFunction) mikey_message_free);
887 
888   INIT_ARRAY (result->map_info, GstMIKEYMapSRTP, NULL);
889   INIT_ARRAY (result->payloads, GstMIKEYPayload *, payload_destroy);
890 
891   return result;
892 }
893 
894 /**
895  * gst_mikey_message_new_from_bytes:
896  * @bytes: a #GBytes
897  * @info: a #GstMIKEYDecryptInfo
898  * @error: a #GError
899  *
900  * Make a new #GstMIKEYMessage from @bytes.
901  *
902  * Returns: a new #GstMIKEYMessage
903  *
904  * Since: 1.4
905  */
906 GstMIKEYMessage *
gst_mikey_message_new_from_bytes(GBytes * bytes,GstMIKEYDecryptInfo * info,GError ** error)907 gst_mikey_message_new_from_bytes (GBytes * bytes, GstMIKEYDecryptInfo * info,
908     GError ** error)
909 {
910   gconstpointer data;
911   gsize size;
912 
913   g_return_val_if_fail (bytes != NULL, NULL);
914 
915   data = g_bytes_get_data (bytes, &size);
916   return gst_mikey_message_new_from_data (data, size, info, error);
917 }
918 
919 /**
920  * gst_mikey_message_set_info:
921  * @msg: a #GstMIKEYMessage
922  * @version: a version
923  * @type: a #GstMIKEYType
924  * @V: verify flag
925  * @prf_func: the #GstMIKEYPRFFunc function to use
926  * @CSB_id: the Crypto Session Bundle id
927  * @map_type: the #GstMIKEYMapType
928  *
929  * Set the information in @msg.
930  *
931  * Returns: %TRUE on success
932  *
933  * Since: 1.4
934  */
935 gboolean
gst_mikey_message_set_info(GstMIKEYMessage * msg,guint8 version,GstMIKEYType type,gboolean V,GstMIKEYPRFFunc prf_func,guint32 CSB_id,GstMIKEYMapType map_type)936 gst_mikey_message_set_info (GstMIKEYMessage * msg, guint8 version,
937     GstMIKEYType type, gboolean V, GstMIKEYPRFFunc prf_func, guint32 CSB_id,
938     GstMIKEYMapType map_type)
939 {
940   g_return_val_if_fail (msg != NULL, FALSE);
941 
942   msg->version = version;
943   msg->type = type;
944   msg->V = V;
945   msg->prf_func = prf_func;
946   msg->CSB_id = CSB_id;
947   msg->map_type = map_type;
948 
949   return TRUE;
950 }
951 
952 /**
953  * gst_mikey_message_get_n_cs:
954  * @msg: a #GstMIKEYMessage
955  *
956  * Get the number of crypto sessions in @msg.
957  *
958  * Returns: the number of crypto sessions
959  *
960  * Since: 1.4
961  */
962 guint
gst_mikey_message_get_n_cs(const GstMIKEYMessage * msg)963 gst_mikey_message_get_n_cs (const GstMIKEYMessage * msg)
964 {
965   g_return_val_if_fail (msg != NULL, 0);
966 
967   return msg->map_info->len;
968 }
969 
970 /**
971  * gst_mikey_message_get_cs_srtp:
972  * @msg: a #GstMIKEYMessage
973  * @idx: an index
974  *
975  * Get the policy information of @msg at @idx.
976  *
977  * Returns: a #GstMIKEYMapSRTP
978  *
979  * Since: 1.4
980  */
981 const GstMIKEYMapSRTP *
gst_mikey_message_get_cs_srtp(const GstMIKEYMessage * msg,guint idx)982 gst_mikey_message_get_cs_srtp (const GstMIKEYMessage * msg, guint idx)
983 {
984   g_return_val_if_fail (msg != NULL, NULL);
985   g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, NULL);
986 
987   if (msg->map_info->len <= idx)
988     return NULL;
989 
990   return &g_array_index (msg->map_info, GstMIKEYMapSRTP, idx);
991 }
992 
993 /**
994  * gst_mikey_message_insert_cs_srtp:
995  * @msg: a #GstMIKEYMessage
996  * @idx: the index to insert at
997  * @map: the map info
998  *
999  * Insert a Crypto Session map for SRTP in @msg at @idx
1000  *
1001  * When @idx is -1, the policy will be appended.
1002  *
1003  * Returns: %TRUE on success
1004  *
1005  * Since: 1.4
1006  */
1007 gboolean
gst_mikey_message_insert_cs_srtp(GstMIKEYMessage * msg,gint idx,const GstMIKEYMapSRTP * map)1008 gst_mikey_message_insert_cs_srtp (GstMIKEYMessage * msg, gint idx,
1009     const GstMIKEYMapSRTP * map)
1010 {
1011   g_return_val_if_fail (msg != NULL, FALSE);
1012   g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE);
1013   g_return_val_if_fail (map != NULL, FALSE);
1014   g_return_val_if_fail (idx == -1 || msg->map_info->len > idx, FALSE);
1015 
1016   if (idx == -1)
1017     g_array_append_val (msg->map_info, *map);
1018   else
1019     g_array_insert_val (msg->map_info, idx, *map);
1020 
1021   return TRUE;
1022 }
1023 
1024 /**
1025  * gst_mikey_message_replace_cs_srtp:
1026  * @msg: a #GstMIKEYMessage
1027  * @idx: the index to insert at
1028  * @map: the map info
1029  *
1030  * Replace a Crypto Session map for SRTP in @msg at @idx with @map.
1031  *
1032  * Returns: %TRUE on success
1033  *
1034  * Since: 1.4
1035  */
1036 gboolean
gst_mikey_message_replace_cs_srtp(GstMIKEYMessage * msg,gint idx,const GstMIKEYMapSRTP * map)1037 gst_mikey_message_replace_cs_srtp (GstMIKEYMessage * msg, gint idx,
1038     const GstMIKEYMapSRTP * map)
1039 {
1040   g_return_val_if_fail (msg != NULL, FALSE);
1041   g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE);
1042   g_return_val_if_fail (map != NULL, FALSE);
1043   g_return_val_if_fail (msg->map_info->len > idx, FALSE);
1044 
1045   g_array_index (msg->map_info, GstMIKEYMapSRTP, idx) = *map;
1046 
1047   return TRUE;
1048 }
1049 
1050 /**
1051  * gst_mikey_message_remove_cs_srtp:
1052  * @msg: a #GstMIKEYMessage
1053  * @idx: the index to remove
1054  *
1055  * Remove the SRTP policy at @idx.
1056  *
1057  * Returns: %TRUE on success
1058  *
1059  * Since: 1.4
1060  */
1061 gboolean
gst_mikey_message_remove_cs_srtp(GstMIKEYMessage * msg,gint idx)1062 gst_mikey_message_remove_cs_srtp (GstMIKEYMessage * msg, gint idx)
1063 {
1064   g_return_val_if_fail (msg != NULL, FALSE);
1065   g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE);
1066   g_return_val_if_fail (msg->map_info->len > idx, FALSE);
1067 
1068   g_array_remove_index (msg->map_info, idx);
1069 
1070   return TRUE;
1071 }
1072 
1073 /**
1074  * gst_mikey_message_add_cs_srtp:
1075  * @msg: a #GstMIKEYMessage
1076  * @policy: The security policy applied for the stream with @ssrc
1077  * @ssrc: the SSRC that must be used for the stream
1078  * @roc: current rollover counter
1079  *
1080  * Add a Crypto policy for SRTP to @msg.
1081  *
1082  * Returns: %TRUE on success
1083  *
1084  * Since: 1.4
1085  */
1086 gboolean
gst_mikey_message_add_cs_srtp(GstMIKEYMessage * msg,guint8 policy,guint32 ssrc,guint32 roc)1087 gst_mikey_message_add_cs_srtp (GstMIKEYMessage * msg, guint8 policy,
1088     guint32 ssrc, guint32 roc)
1089 {
1090   GstMIKEYMapSRTP val;
1091 
1092   g_return_val_if_fail (msg != NULL, FALSE);
1093   g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE);
1094 
1095   val.policy = policy;
1096   val.ssrc = ssrc;
1097   val.roc = roc;
1098 
1099   return gst_mikey_message_insert_cs_srtp (msg, -1, &val);
1100 }
1101 
1102 /* adding/retrieving payloads */
1103 /**
1104  * gst_mikey_message_get_n_payloads:
1105  * @msg: a #GstMIKEYMessage
1106  *
1107  * Get the number of payloads in @msg.
1108  *
1109  * Returns: the number of payloads in @msg
1110  *
1111  * Since: 1.4
1112  */
1113 guint
gst_mikey_message_get_n_payloads(const GstMIKEYMessage * msg)1114 gst_mikey_message_get_n_payloads (const GstMIKEYMessage * msg)
1115 {
1116   g_return_val_if_fail (msg != NULL, 0);
1117 
1118   return msg->payloads->len;
1119 }
1120 
1121 /**
1122  * gst_mikey_message_get_payload:
1123  * @msg: a #GstMIKEYMessage
1124  * @idx: an index
1125  *
1126  * Get the #GstMIKEYPayload at @idx in @msg
1127  *
1128  * Returns: (transfer none): the #GstMIKEYPayload at @idx. The payload
1129  * remains valid for as long as it is part of @msg.
1130  *
1131  * Since: 1.4
1132  */
1133 const GstMIKEYPayload *
gst_mikey_message_get_payload(const GstMIKEYMessage * msg,guint idx)1134 gst_mikey_message_get_payload (const GstMIKEYMessage * msg, guint idx)
1135 {
1136   g_return_val_if_fail (msg != NULL, NULL);
1137 
1138   if (idx >= msg->payloads->len)
1139     return NULL;
1140 
1141   return g_array_index (msg->payloads, GstMIKEYPayload *, idx);
1142 }
1143 
1144 /**
1145  * gst_mikey_message_find_payload:
1146  * @msg: a #GstMIKEYMessage
1147  * @type: a #GstMIKEYPayloadType
1148  * @nth: payload to find
1149  *
1150  * Find the @nth occurence of the payload with @type in @msg.
1151  *
1152  * Returns: the @nth #GstMIKEYPayload of @type.
1153  *
1154  * Since: 1.4
1155  */
1156 const GstMIKEYPayload *
gst_mikey_message_find_payload(const GstMIKEYMessage * msg,GstMIKEYPayloadType type,guint idx)1157 gst_mikey_message_find_payload (const GstMIKEYMessage * msg,
1158     GstMIKEYPayloadType type, guint idx)
1159 {
1160   guint i, len, count;
1161 
1162   count = 0;
1163   len = msg->payloads->len;
1164   for (i = 0; i < len; i++) {
1165     GstMIKEYPayload *payload =
1166         g_array_index (msg->payloads, GstMIKEYPayload *, i);
1167 
1168     if (payload->type == type) {
1169       if (count == idx)
1170         return payload;
1171 
1172       count++;
1173     }
1174   }
1175   return NULL;
1176 }
1177 
1178 /**
1179  * gst_mikey_message_remove_payload:
1180  * @msg: a #GstMIKEYMessage
1181  * @idx: an index
1182  *
1183  * Remove the payload in @msg at @idx
1184  *
1185  * Returns: %TRUE on success
1186  *
1187  * Since: 1.4
1188  */
1189 gboolean
gst_mikey_message_remove_payload(GstMIKEYMessage * msg,guint idx)1190 gst_mikey_message_remove_payload (GstMIKEYMessage * msg, guint idx)
1191 {
1192   g_return_val_if_fail (msg != NULL, FALSE);
1193   g_return_val_if_fail (msg->payloads->len > idx, FALSE);
1194 
1195   g_array_remove_index (msg->payloads, idx);
1196 
1197   return TRUE;
1198 }
1199 
1200 /**
1201  * gst_mikey_message_insert_payload:
1202  * @msg: a #GstMIKEYMessage
1203  * @idx: an index
1204  * @payload: (transfer full): a #GstMIKEYPayload
1205  *
1206  * Insert the @payload at index @idx in @msg. If @idx is -1, the payload
1207  * will be appended to @msg.
1208  *
1209  * Returns: %TRUE on success
1210  *
1211  * Since: 1.4
1212  */
1213 gboolean
gst_mikey_message_insert_payload(GstMIKEYMessage * msg,guint idx,GstMIKEYPayload * payload)1214 gst_mikey_message_insert_payload (GstMIKEYMessage * msg, guint idx,
1215     GstMIKEYPayload * payload)
1216 {
1217   g_return_val_if_fail (msg != NULL, FALSE);
1218   g_return_val_if_fail (payload != NULL, FALSE);
1219   g_return_val_if_fail (idx == -1 || msg->payloads->len > idx, FALSE);
1220 
1221   if (idx == -1)
1222     g_array_append_val (msg->payloads, payload);
1223   else
1224     g_array_insert_val (msg->payloads, idx, payload);
1225 
1226   return TRUE;
1227 }
1228 
1229 /**
1230  * gst_mikey_message_add_payload:
1231  * @msg: a #GstMIKEYMessage
1232  * @payload: (transfer full): a #GstMIKEYPayload
1233  *
1234  * Add a new payload to @msg.
1235  *
1236  * Returns: %TRUE on success
1237  *
1238  * Since: 1.4
1239  */
1240 gboolean
gst_mikey_message_add_payload(GstMIKEYMessage * msg,GstMIKEYPayload * payload)1241 gst_mikey_message_add_payload (GstMIKEYMessage * msg, GstMIKEYPayload * payload)
1242 {
1243   return gst_mikey_message_insert_payload (msg, -1, payload);
1244 }
1245 
1246 /**
1247  * gst_mikey_message_replace_payload:
1248  * @msg: a #GstMIKEYMessage
1249  * @idx: an index
1250  * @payload: (transfer full): a #GstMIKEYPayload
1251  *
1252  * Replace the payload at @idx in @msg with @payload.
1253  *
1254  * Returns: %TRUE on success
1255  *
1256  * Since: 1.4
1257  */
1258 gboolean
gst_mikey_message_replace_payload(GstMIKEYMessage * msg,guint idx,GstMIKEYPayload * payload)1259 gst_mikey_message_replace_payload (GstMIKEYMessage * msg, guint idx,
1260     GstMIKEYPayload * payload)
1261 {
1262   GstMIKEYPayload *p;
1263 
1264   g_return_val_if_fail (msg != NULL, FALSE);
1265   g_return_val_if_fail (payload != NULL, FALSE);
1266   g_return_val_if_fail (msg->payloads->len > idx, FALSE);
1267 
1268   p = g_array_index (msg->payloads, GstMIKEYPayload *, idx);
1269   gst_mikey_payload_unref (p);
1270   g_array_index (msg->payloads, GstMIKEYPayload *, idx) = payload;
1271 
1272   return TRUE;
1273 }
1274 
1275 /**
1276  * gst_mikey_message_add_pke:
1277  * @msg: a #GstMIKEYMessage
1278  * @C: envelope key cache indicator
1279  * @data_len: the length of @data
1280  * @data: (array length=data_len): the encrypted envelope key
1281  *
1282  * Add a new PKE payload to @msg with the given parameters.
1283  *
1284  * Returns: %TRUE on success
1285  *
1286  * Since: 1.4
1287  */
1288 gboolean
gst_mikey_message_add_pke(GstMIKEYMessage * msg,GstMIKEYCacheType C,guint16 data_len,const guint8 * data)1289 gst_mikey_message_add_pke (GstMIKEYMessage * msg, GstMIKEYCacheType C,
1290     guint16 data_len, const guint8 * data)
1291 {
1292   GstMIKEYPayload *p;
1293 
1294   g_return_val_if_fail (msg != NULL, FALSE);
1295 
1296   p = gst_mikey_payload_new (GST_MIKEY_PT_PKE);
1297   if (!gst_mikey_payload_pke_set (p, C, data_len, data)) {
1298     gst_mikey_payload_unref (p);
1299     return FALSE;
1300   }
1301 
1302   return gst_mikey_message_insert_payload (msg, -1, p);
1303 }
1304 
1305 /**
1306  * gst_mikey_message_add_t:
1307  * @msg: a #GstMIKEYMessage
1308  * @type: specifies the timestamp type used
1309  * @ts_value: (array): The timestamp value of the specified @type
1310  *
1311  * Add a new T payload to @msg with the given parameters.
1312  *
1313  * Returns: %TRUE on success
1314  *
1315  * Since: 1.4
1316  */
1317 gboolean
gst_mikey_message_add_t(GstMIKEYMessage * msg,GstMIKEYTSType type,const guint8 * ts_value)1318 gst_mikey_message_add_t (GstMIKEYMessage * msg, GstMIKEYTSType type,
1319     const guint8 * ts_value)
1320 {
1321   GstMIKEYPayload *p;
1322 
1323   g_return_val_if_fail (msg != NULL, FALSE);
1324 
1325   p = gst_mikey_payload_new (GST_MIKEY_PT_T);
1326   if (!gst_mikey_payload_t_set (p, type, ts_value)) {
1327     gst_mikey_payload_unref (p);
1328     return FALSE;
1329   }
1330 
1331   return gst_mikey_message_insert_payload (msg, -1, p);
1332 }
1333 
1334 /**
1335  * gst_mikey_message_add_t_now_ntp_utc:
1336  * @msg: a #GstMIKEYMessage
1337  *
1338  * Add a new T payload to @msg that contains the current time
1339  * in NTP-UTC format.
1340  *
1341  * Returns: %TRUE on success
1342  *
1343  * Since: 1.4
1344  */
1345 gboolean
gst_mikey_message_add_t_now_ntp_utc(GstMIKEYMessage * msg)1346 gst_mikey_message_add_t_now_ntp_utc (GstMIKEYMessage * msg)
1347 {
1348   gint64 now;
1349   guint64 ntptime;
1350   guint8 bytes[8];
1351 
1352   now = g_get_real_time ();
1353 
1354   /* convert clock time to NTP time. upper 32 bits should contain the seconds
1355    * and the lower 32 bits, the fractions of a second. */
1356   ntptime = gst_util_uint64_scale (now, (G_GINT64_CONSTANT (1) << 32), 1000000);
1357   /* conversion from UNIX timestamp (seconds since 1970) to NTP (seconds
1358    * since 1900). */
1359   ntptime += (G_GUINT64_CONSTANT (2208988800) << 32);
1360   GST_WRITE_UINT64_BE (bytes, ntptime);
1361 
1362   return gst_mikey_message_add_t (msg, GST_MIKEY_TS_TYPE_NTP_UTC, bytes);
1363 }
1364 
1365 /**
1366  * gst_mikey_message_add_rand:
1367  * @msg: a #GstMIKEYMessage
1368  * @len: the length of @rand
1369  * @rand: (array length=len): random data
1370  *
1371  * Add a new RAND payload to @msg with the given parameters.
1372  *
1373  * Returns: %TRUE on success
1374  *
1375  * Since: 1.4
1376  */
1377 gboolean
gst_mikey_message_add_rand(GstMIKEYMessage * msg,guint8 len,const guint8 * rand)1378 gst_mikey_message_add_rand (GstMIKEYMessage * msg, guint8 len,
1379     const guint8 * rand)
1380 {
1381   GstMIKEYPayload *p;
1382 
1383   g_return_val_if_fail (msg != NULL, FALSE);
1384   g_return_val_if_fail (len != 0 && rand != NULL, FALSE);
1385 
1386   p = gst_mikey_payload_new (GST_MIKEY_PT_RAND);
1387   if (!gst_mikey_payload_rand_set (p, len, rand)) {
1388     gst_mikey_payload_unref (p);
1389     return FALSE;
1390   }
1391 
1392   return gst_mikey_message_insert_payload (msg, -1, p);
1393 }
1394 
1395 /**
1396  * gst_mikey_message_add_rand_len:
1397  * @msg: a #GstMIKEYMessage
1398  * @len: length
1399  *
1400  * Add a new RAND payload to @msg with @len random bytes.
1401  *
1402  * Returns: %TRUE on success
1403  *
1404  * Since: 1.4
1405  */
1406 gboolean
gst_mikey_message_add_rand_len(GstMIKEYMessage * msg,guint8 len)1407 gst_mikey_message_add_rand_len (GstMIKEYMessage * msg, guint8 len)
1408 {
1409   GstMIKEYPayloadRAND *p;
1410   guint i;
1411 
1412   p = (GstMIKEYPayloadRAND *) gst_mikey_payload_new (GST_MIKEY_PT_RAND);
1413   p->len = len;
1414   p->rand = g_malloc (len);
1415   for (i = 0; i < len; i++)
1416     p->rand[i] = g_random_int_range (0, 256);
1417 
1418   return gst_mikey_message_add_payload (msg, &p->pt);
1419 }
1420 
1421 #define ENSURE_SIZE(n)                          \
1422 G_STMT_START {                                  \
1423   guint offset = data - arr->data;              \
1424   g_byte_array_set_size (arr, offset + n);      \
1425   data = arr->data + offset;                    \
1426 } G_STMT_END
1427 static guint
payloads_to_bytes(GArray * payloads,GByteArray * arr,guint8 ** ptr,guint offset,GstMIKEYEncryptInfo * info,GError ** error)1428 payloads_to_bytes (GArray * payloads, GByteArray * arr, guint8 ** ptr,
1429     guint offset, GstMIKEYEncryptInfo * info, GError ** error)
1430 {
1431   guint i, n_payloads, len, start, size;
1432   guint8 *data;
1433   GstMIKEYPayload *next_payload;
1434 
1435   len = arr->len;
1436   start = *ptr - arr->data;
1437   data = *ptr + offset;
1438 
1439   n_payloads = payloads->len;
1440 
1441   for (i = 0; i < n_payloads; i++) {
1442     GstMIKEYPayload *payload = g_array_index (payloads, GstMIKEYPayload *, i);
1443 
1444     if (i + 1 < n_payloads)
1445       next_payload = g_array_index (payloads, GstMIKEYPayload *, i + 1);
1446     else
1447       next_payload = NULL;
1448 
1449     switch (payload->type) {
1450       case GST_MIKEY_PT_KEMAC:
1451       {
1452         GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
1453         guint enc_len;
1454         guint mac_len;
1455 
1456         if ((mac_len = get_mac_len (p->mac_alg)) == -1)
1457           break;
1458 
1459         /*                  1                   2                   3
1460          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1461          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1462          * ! Next payload  ! Encr alg      ! Encr data len                 !
1463          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1464          * !                        Encr data                              ~
1465          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1466          * ! Mac alg       !        MAC                                    ~
1467          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1468          */
1469         ENSURE_SIZE (4);
1470         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1471         data[1] = p->enc_alg;
1472         enc_len =
1473             payloads_to_bytes (p->subpayloads, arr, &data, 4, info, error);
1474         /* FIXME, encrypt data here */
1475         GST_WRITE_UINT16_BE (&data[2], enc_len);
1476         data += enc_len;
1477         ENSURE_SIZE (5 + mac_len);
1478         data[4] = p->mac_alg;
1479         /* FIXME, do mac here */
1480         data += 5 + mac_len;
1481         break;
1482       }
1483       case GST_MIKEY_PT_T:
1484       {
1485         GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload;
1486         guint ts_len;
1487 
1488         if ((ts_len = get_ts_len (p->type)) == -1)
1489           break;
1490 
1491         /*                      1                   2                   3
1492          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1493          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1494          * ! Next Payload  !   TS type     ! TS value                      ~
1495          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1496          */
1497         ENSURE_SIZE (2 + ts_len);
1498         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1499         data[1] = p->type;
1500         memcpy (&data[2], p->ts_value, ts_len);
1501         data += 2 + ts_len;
1502         break;
1503       }
1504       case GST_MIKEY_PT_PKE:
1505       {
1506         guint16 clen;
1507         GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload;
1508         /*                      1                   2                   3
1509          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1510          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1511          * ! Next Payload  ! C ! Data len                  ! Data          ~
1512          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1513          */
1514         ENSURE_SIZE (3 + p->data_len);
1515         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1516         clen = (p->C << 14) || (p->data_len & 0x3fff);
1517         GST_WRITE_UINT16_BE (&data[1], clen);
1518         memcpy (&data[3], p->data, p->data_len);
1519         data += 3 + p->data_len;
1520         break;
1521       }
1522       case GST_MIKEY_PT_DH:
1523       case GST_MIKEY_PT_SIGN:
1524       case GST_MIKEY_PT_ID:
1525       case GST_MIKEY_PT_CERT:
1526       case GST_MIKEY_PT_CHASH:
1527       case GST_MIKEY_PT_V:
1528         break;
1529       case GST_MIKEY_PT_SP:
1530       {
1531         GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
1532         guint len, plen, i;
1533 
1534         plen = 0;
1535         len = p->params->len;
1536         for (i = 0; i < len; i++) {
1537           GstMIKEYPayloadSPParam *param = &g_array_index (p->params,
1538               GstMIKEYPayloadSPParam, i);
1539           plen += 2 + param->len;
1540         }
1541         /*                      1                   2                   3
1542          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1543          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1544          * ! Next payload  ! Policy no     ! Prot type     ! Policy param  ~
1545          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1546          * ~ length (cont) ! Policy param                                  ~
1547          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1548          */
1549         ENSURE_SIZE (5 + plen);
1550         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1551         data[1] = p->policy;
1552         data[2] = p->proto;
1553         GST_WRITE_UINT16_BE (&data[3], plen);
1554         data += 5;
1555         for (i = 0; i < len; i++) {
1556           GstMIKEYPayloadSPParam *param = &g_array_index (p->params,
1557               GstMIKEYPayloadSPParam, i);
1558           /*                     1                   2                   3
1559            * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1560            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1561            * ! Type          ! Length        ! Value                         ~
1562            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1563            */
1564           data[0] = param->type;
1565           data[1] = param->len;
1566           memcpy (&data[2], param->val, param->len);
1567           data += 2 + param->len;
1568         }
1569         break;
1570       }
1571       case GST_MIKEY_PT_RAND:
1572       {
1573         GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload;
1574         /*                      1                   2                   3
1575          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1576          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1577          * ! Next payload  ! RAND len      ! RAND                          ~
1578          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1579          */
1580         ENSURE_SIZE (2 + p->len);
1581         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1582         data[1] = p->len;
1583         memcpy (&data[2], p->rand, p->len);
1584         data += 2 + p->len;
1585         break;
1586       }
1587       case GST_MIKEY_PT_ERR:
1588         break;
1589       case GST_MIKEY_PT_KEY_DATA:
1590       {
1591         GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
1592         /*                        1                   2                   3
1593          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1594          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1595          * !  Next Payload ! Type  ! KV    ! Key data len                  !
1596          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1597          * !                         Key data                              ~
1598          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1599          * ! Salt len (optional)           ! Salt data (optional)          ~
1600          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1601          * !                        KV data (optional)                     ~
1602          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1603          */
1604         ENSURE_SIZE (4 + p->key_len);
1605         data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1606         data[1] =
1607             ((p->key_type | (p->salt_len ? 1 : 0)) << 4) | (p->kv_type & 0xf);
1608         GST_WRITE_UINT16_BE (&data[2], p->key_len);
1609         memcpy (&data[4], p->key_data, p->key_len);
1610         data += 4 + p->key_len;
1611 
1612         if (p->salt_len > 0) {
1613           ENSURE_SIZE (2 + p->salt_len);
1614           GST_WRITE_UINT16_BE (&data[0], p->salt_len);
1615           memcpy (&data[2], p->salt_data, p->salt_len);
1616           data += 2 + p->salt_len;
1617         }
1618         if (p->kv_type == GST_MIKEY_KV_SPI) {
1619           /*
1620            *                      1                   2                   3
1621            *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1622            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1623            * ! SPI Length    ! SPI                                           ~
1624            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1625            */
1626           ENSURE_SIZE (1 + p->kv_len[0]);
1627           data[0] = p->kv_len[0];
1628           memcpy (&data[1], p->kv_data[0], p->kv_len[0]);
1629           data += 1 + p->kv_len[0];
1630         } else if (p->kv_type == GST_MIKEY_KV_INTERVAL) {
1631           /*
1632            *                      1                   2                   3
1633            *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1634            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1635            * ! VF Length     ! Valid From                                    ~
1636            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1637            * ! VT Length     ! Valid To (expires)                            ~
1638            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1639            */
1640           ENSURE_SIZE (1 + p->kv_len[0]);
1641           data[0] = p->kv_len[0];
1642           memcpy (&data[1], p->kv_data[0], p->kv_len[0]);
1643           data += 1 + p->kv_len[0];
1644           ENSURE_SIZE (1 + p->kv_len[1]);
1645           data[0] = p->kv_len[1];
1646           memcpy (&data[1], p->kv_data[1], p->kv_len[1]);
1647           data += 1 + p->kv_len[1];
1648         }
1649         break;
1650       }
1651       case GST_MIKEY_PT_GEN_EXT:
1652       case GST_MIKEY_PT_LAST:
1653         break;
1654     }
1655   }
1656   *ptr = arr->data + start;
1657   size = arr->len - len;
1658 
1659   return size;
1660 }
1661 
1662 /**
1663  * gst_mikey_message_to_bytes:
1664  * @msg: a #GstMIKEYMessage
1665  * @info: a #GstMIKEYEncryptInfo
1666  * @error: a #GError
1667  *
1668  * Convert @msg to a #GBytes.
1669  *
1670  * Returns: a new #GBytes for @msg.
1671  *
1672  * Since: 1.4
1673  */
1674 GBytes *
gst_mikey_message_to_bytes(GstMIKEYMessage * msg,GstMIKEYEncryptInfo * info,GError ** error)1675 gst_mikey_message_to_bytes (GstMIKEYMessage * msg, GstMIKEYEncryptInfo * info,
1676     GError ** error)
1677 {
1678   GByteArray *arr = NULL;
1679   guint8 *data;
1680   GstMIKEYPayload *next_payload;
1681   guint i, n_cs;
1682   arr = g_byte_array_new ();
1683   data = arr->data;
1684 
1685   if (msg->payloads->len == 0)
1686     next_payload = NULL;
1687   else
1688     next_payload = g_array_index (msg->payloads, GstMIKEYPayload *, 0);
1689 
1690   n_cs = msg->map_info->len;
1691   /*                      1                   2                   3
1692    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1693    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1694    * !  version      !  data type    ! next payload  !V! PRF func    !
1695    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1696    * !                         CSB ID                                !
1697    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1698    * ! #CS           ! CS ID map type! CS ID map info                ~
1699    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1700    */
1701   ENSURE_SIZE (10 + 9 * n_cs);
1702   data[0] = msg->version;
1703   data[1] = msg->type;
1704   data[2] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1705   data[3] = (msg->V ? 0x80 : 0x00) | (msg->prf_func & 0x7f);
1706   GST_WRITE_UINT32_BE (&data[4], msg->CSB_id);
1707   data[8] = n_cs;
1708   data[9] = msg->map_type;
1709   data += 10;
1710 
1711   for (i = 0; i < n_cs; i++) {
1712     GstMIKEYMapSRTP *info = &g_array_index (msg->map_info, GstMIKEYMapSRTP, i);
1713     /*                      1                   2                   3
1714      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1715      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1716      * ! Policy_no_1   ! SSRC_1                                        !
1717      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1718      * ! SSRC_1 (cont) ! ROC_1                                         !
1719      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1720      * ! ROC_1 (cont)  ! Policy_no_2   ! SSRC_2                        !
1721      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1722      * ! SSRC_2 (cont)                 ! ROC_2                         !
1723      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1724      * ! ROC_2 (cont)                  !                               :
1725      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ...
1726      */
1727     data[0] = info->policy;
1728     GST_WRITE_UINT32_BE (&data[1], info->ssrc);
1729     GST_WRITE_UINT32_BE (&data[5], info->roc);
1730     data += 9;
1731   }
1732 
1733   payloads_to_bytes (msg->payloads, arr, &data, 0, info, error);
1734 
1735   return g_byte_array_free_to_bytes (arr);
1736 }
1737 
1738 #undef ENSURE_SIZE
1739 
1740 typedef enum
1741 {
1742   STATE_PSK,
1743   STATE_PK,
1744   STATE_KEMAC,
1745   STATE_OTHER
1746 } ParseState;
1747 
1748 #define CHECK_SIZE(n) if (size < (n)) goto short_data;
1749 #define ADVANCE(n) (d += (n), size -= (n));
1750 static gboolean
payloads_from_bytes(ParseState state,GArray * payloads,const guint8 * d,gsize size,guint8 next_payload,GstMIKEYDecryptInfo * info,GError ** error)1751 payloads_from_bytes (ParseState state, GArray * payloads, const guint8 * d,
1752     gsize size, guint8 next_payload, GstMIKEYDecryptInfo * info,
1753     GError ** error)
1754 {
1755   GstMIKEYPayload *p;
1756 
1757   while (next_payload != GST_MIKEY_PT_LAST) {
1758     p = NULL;
1759     switch (next_payload) {
1760       case GST_MIKEY_PT_KEMAC:
1761       {
1762         guint mac_len;
1763         GstMIKEYEncAlg enc_alg;
1764         guint16 enc_len;
1765         const guint8 *enc_data;
1766         GstMIKEYMacAlg mac_alg;
1767         guint8 np;
1768         /*                  1                   2                   3
1769          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1770          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1771          * ! Next payload  ! Encr alg      ! Encr data len                 !
1772          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1773          * !                        Encr data                              ~
1774          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1775          * ! Mac alg       !        MAC                                    ~
1776          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1777          */
1778         CHECK_SIZE (5);
1779         next_payload = d[0];
1780         enc_alg = d[1];
1781         enc_len = GST_READ_UINT16_BE (&d[2]);
1782         CHECK_SIZE (5 + enc_len);
1783         enc_data = &d[4];
1784         /* FIXME, decrypt data */
1785         ADVANCE (enc_len);
1786         mac_alg = d[4];
1787         if ((mac_len = get_mac_len (mac_alg)) == -1)
1788           goto invalid_data;
1789         CHECK_SIZE (5 + mac_len);
1790         /* FIXME, check MAC */
1791         ADVANCE (5 + mac_len);
1792 
1793         p = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC);
1794         gst_mikey_payload_kemac_set (p, enc_alg, mac_alg);
1795 
1796         if (state == STATE_PSK)
1797           /* we expect Key data for Preshared key */
1798           np = GST_MIKEY_PT_KEY_DATA;
1799         else if (state == STATE_PK)
1800           /* we expect ID for Public key */
1801           np = GST_MIKEY_PT_ID;
1802         else
1803           goto invalid_data;
1804 
1805         payloads_from_bytes (STATE_KEMAC,
1806             ((GstMIKEYPayloadKEMAC *) p)->subpayloads, enc_data, enc_len, np,
1807             info, error);
1808         g_array_append_val (payloads, p);
1809         break;
1810       }
1811       case GST_MIKEY_PT_T:
1812       {
1813         GstMIKEYTSType type;
1814         guint ts_len;
1815         const guint8 *ts_value;
1816         /*                      1                   2                   3
1817          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1818          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1819          * ! Next Payload  !   TS type     ! TS value                      ~
1820          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1821          */
1822         CHECK_SIZE (2);
1823         next_payload = d[0];
1824         type = d[1];
1825         if ((ts_len = get_ts_len (type)) == -1)
1826           goto invalid_data;
1827         CHECK_SIZE (2 + ts_len);
1828         ts_value = &d[2];
1829         ADVANCE (2 + ts_len);
1830 
1831         p = gst_mikey_payload_new (GST_MIKEY_PT_T);
1832         gst_mikey_payload_t_set (p, type, ts_value);
1833         g_array_append_val (payloads, p);
1834         break;
1835       }
1836       case GST_MIKEY_PT_PKE:
1837       {
1838         guint8 C;
1839         guint16 clen, data_len;
1840         const guint8 *data;
1841         /*                      1                   2                   3
1842          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1843          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1844          * ! Next Payload  ! C ! Data len                  ! Data          ~
1845          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1846          */
1847         CHECK_SIZE (3);
1848         next_payload = d[0];
1849         clen = GST_READ_UINT16_BE (&d[1]);
1850         C = clen >> 14;
1851         data_len = clen & 0x3fff;
1852         CHECK_SIZE (3 + data_len);
1853         data = &d[3];
1854         ADVANCE (3 + data_len);
1855 
1856         p = gst_mikey_payload_new (GST_MIKEY_PT_PKE);
1857         gst_mikey_payload_pke_set (p, C, data_len, data);
1858         g_array_append_val (payloads, p);
1859         break;
1860       }
1861       case GST_MIKEY_PT_DH:
1862       case GST_MIKEY_PT_SIGN:
1863       case GST_MIKEY_PT_ID:
1864       case GST_MIKEY_PT_CERT:
1865       case GST_MIKEY_PT_CHASH:
1866       case GST_MIKEY_PT_V:
1867         break;
1868       case GST_MIKEY_PT_SP:
1869       {
1870         guint8 policy;
1871         GstMIKEYSecProto proto;
1872         guint16 plen;
1873         /*                      1                   2                   3
1874          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1875          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1876          * ! Next payload  ! Policy no     ! Prot type     ! Policy param  ~
1877          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1878          * ~ length (cont) ! Policy param                                  ~
1879          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1880          */
1881         CHECK_SIZE (5);
1882         next_payload = d[0];
1883         policy = d[1];
1884         proto = d[2];
1885         plen = GST_READ_UINT16_BE (&d[3]);
1886         ADVANCE (5);
1887 
1888         p = gst_mikey_payload_new (GST_MIKEY_PT_SP);
1889         gst_mikey_payload_sp_set (p, policy, proto);
1890 
1891         CHECK_SIZE (plen);
1892         while (plen) {
1893           guint8 type, len;
1894 
1895           CHECK_SIZE (2);
1896           /*                     1                   2                   3
1897            * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1898            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1899            * ! Type          ! Length        ! Value                         ~
1900            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1901            */
1902           type = d[0];
1903           len = d[1];
1904           CHECK_SIZE (2 + len);
1905           gst_mikey_payload_sp_add_param (p, type, len, &d[2]);
1906           ADVANCE (2 + len);
1907           plen -= 2 + len;
1908         }
1909         g_array_append_val (payloads, p);
1910         break;
1911       }
1912       case GST_MIKEY_PT_RAND:
1913       {
1914         guint8 len;
1915         const guint8 *rand;
1916         /*                      1                   2                   3
1917          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1918          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1919          * ! Next payload  ! RAND len      ! RAND                          ~
1920          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1921          */
1922         CHECK_SIZE (2);
1923         next_payload = d[0];
1924         len = d[1];
1925         CHECK_SIZE (2 + len);
1926         rand = &d[2];
1927         ADVANCE (2 + len);
1928 
1929         p = gst_mikey_payload_new (GST_MIKEY_PT_RAND);
1930         gst_mikey_payload_rand_set (p, len, rand);
1931         g_array_append_val (payloads, p);
1932         break;
1933       }
1934       case GST_MIKEY_PT_ERR:
1935         break;
1936       case GST_MIKEY_PT_KEY_DATA:
1937       {
1938         GstMIKEYKeyDataType key_type;
1939         GstMIKEYKVType kv_type;
1940         guint16 key_len, salt_len = 0;
1941         const guint8 *key_data, *salt_data;
1942         /*                        1                   2                   3
1943          *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1944          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1945          * !  Next Payload ! Type  ! KV    ! Key data len                  !
1946          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1947          * !                         Key data                              ~
1948          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1949          * ! Salt len (optional)           ! Salt data (optional)          ~
1950          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1951          * !                        KV data (optional)                     ~
1952          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1953          */
1954         CHECK_SIZE (4);
1955         next_payload = d[0];
1956         key_type = d[1] >> 4;
1957         kv_type = d[1] & 0xf;
1958         key_len = GST_READ_UINT16_BE (&d[2]);
1959         CHECK_SIZE (4 + key_len);
1960         key_data = &d[4];
1961         ADVANCE (4 + key_len);
1962         if (key_type & 1) {
1963           CHECK_SIZE (2);
1964           salt_len = GST_READ_UINT16_BE (&d[0]);
1965           CHECK_SIZE (2 + salt_len);
1966           salt_data = &d[2];
1967           ADVANCE (2 + salt_len);
1968         }
1969         p = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA);
1970         gst_mikey_payload_key_data_set_key (p, key_type & 2, key_len, key_data);
1971         if (salt_len > 0)
1972           gst_mikey_payload_key_data_set_salt (p, salt_len, salt_data);
1973 
1974         if (kv_type == GST_MIKEY_KV_SPI) {
1975           guint8 spi_len;
1976           const guint8 *spi_data;
1977           /*
1978            *                      1                   2                   3
1979            *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1980            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1981            * ! SPI Length    ! SPI                                           ~
1982            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1983            */
1984           CHECK_SIZE (1);
1985           spi_len = d[0];
1986           CHECK_SIZE (1 + spi_len);
1987           spi_data = &d[1];
1988           ADVANCE (1 + spi_len);
1989 
1990           gst_mikey_payload_key_data_set_spi (p, spi_len, spi_data);
1991         } else if (kv_type == GST_MIKEY_KV_INTERVAL) {
1992           guint8 vf_len, vt_len;
1993           const guint8 *vf_data, *vt_data;
1994           /*
1995            *                      1                   2                   3
1996            *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1997            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1998            * ! VF Length     ! Valid From                                    ~
1999            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2000            * ! VT Length     ! Valid To (expires)                            ~
2001            * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2002            */
2003           CHECK_SIZE (1);
2004           vf_len = d[0];
2005           CHECK_SIZE (1 + vf_len);
2006           vf_data = &d[1];
2007           ADVANCE (1 + vf_len);
2008           CHECK_SIZE (1);
2009           vt_len = d[0];
2010           CHECK_SIZE (1 + vt_len);
2011           vt_data = &d[1];
2012           ADVANCE (1 + vt_len);
2013 
2014           gst_mikey_payload_key_data_set_interval (p, vf_len, vf_data, vt_len,
2015               vt_data);
2016         } else if (kv_type != GST_MIKEY_KV_NULL)
2017           goto invalid_data;
2018 
2019         g_array_append_val (payloads, p);
2020         break;
2021       }
2022       case GST_MIKEY_PT_GEN_EXT:
2023       case GST_MIKEY_PT_LAST:
2024         break;
2025     }
2026   }
2027   return TRUE;
2028 
2029   /* ERRORS */
2030 short_data:
2031   {
2032     GST_DEBUG ("not enough data");
2033     if (p)
2034       gst_mikey_payload_unref (p);
2035     return FALSE;
2036   }
2037 invalid_data:
2038   {
2039     GST_DEBUG ("invalid data");
2040     if (p)
2041       gst_mikey_payload_unref (p);
2042     return FALSE;
2043   }
2044 }
2045 
2046 /**
2047  * gst_mikey_message_new_from_data:
2048  * @data: (array length=size) (element-type guint8): bytes to read
2049  * @size: length of @data
2050  * @info: #GstMIKEYDecryptInfo
2051  * @error: a #GError
2052  *
2053  * Parse @size bytes from @data into a #GstMIKEYMessage. @info contains the
2054  * parameters to decrypt and verify the data.
2055  *
2056  * Returns: a #GstMIKEYMessage on success or %NULL when parsing failed and
2057  * @error will be set.
2058  *
2059  * Since: 1.4
2060  */
2061 GstMIKEYMessage *
gst_mikey_message_new_from_data(gconstpointer data,gsize size,GstMIKEYDecryptInfo * info,GError ** error)2062 gst_mikey_message_new_from_data (gconstpointer data, gsize size,
2063     GstMIKEYDecryptInfo * info, GError ** error)
2064 {
2065   GstMIKEYMessage *msg;
2066   guint n_cs, i;
2067   const guint8 *d = data;
2068   guint8 next_payload;
2069   ParseState state;
2070 
2071   g_return_val_if_fail (data != NULL, NULL);
2072 
2073   msg = gst_mikey_message_new ();
2074   /*                      1                   2                   3
2075    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2076    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2077    * !  version      !  data type    ! next payload  !V! PRF func    !
2078    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2079    * !                         CSB ID                                !
2080    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2081    * ! #CS           ! CS ID map type! CS ID map info                ~
2082    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2083    */
2084   CHECK_SIZE (10);
2085   msg->version = d[0];
2086   if (msg->version != GST_MIKEY_VERSION)
2087     goto unknown_version;
2088 
2089   msg->type = d[1];
2090   next_payload = d[2];
2091   msg->V = d[3] & 0x80 ? TRUE : FALSE;
2092   msg->prf_func = d[3] & 0x7f;
2093   msg->CSB_id = GST_READ_UINT32_BE (&d[4]);
2094   n_cs = d[8];
2095   msg->map_type = d[9];
2096   ADVANCE (10);
2097 
2098   CHECK_SIZE (n_cs * 9);
2099   for (i = 0; i < n_cs; i++) {
2100     GstMIKEYMapSRTP map;
2101 
2102     /*                      1                   2                   3
2103      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2104      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2105      * ! Policy_no_1   ! SSRC_1                                        !
2106      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2107      * ! SSRC_1 (cont) ! ROC_1                                         !
2108      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2109      * ! ROC_1 (cont)  ! Policy_no_2   ! SSRC_2                        ~
2110      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2111      */
2112     map.policy = d[0];
2113     map.ssrc = GST_READ_UINT32_BE (&d[1]);
2114     map.roc = GST_READ_UINT32_BE (&d[5]);
2115     gst_mikey_message_insert_cs_srtp (msg, -1, &map);
2116     ADVANCE (9);
2117   }
2118   if (msg->type == GST_MIKEY_TYPE_PSK_INIT)
2119     state = STATE_PSK;
2120   else if (msg->type == GST_MIKEY_TYPE_PK_INIT)
2121     state = STATE_PK;
2122   else
2123     state = STATE_OTHER;
2124 
2125   if (!payloads_from_bytes (state, msg->payloads, d, size, next_payload, info,
2126           error))
2127     goto parse_error;
2128 
2129   return msg;
2130 
2131   /* ERRORS */
2132 short_data:
2133   {
2134     GST_DEBUG ("not enough data");
2135     gst_mikey_message_unref (msg);
2136     return NULL;
2137   }
2138 unknown_version:
2139   {
2140     GST_DEBUG ("unknown version");
2141     gst_mikey_message_unref (msg);
2142     return NULL;
2143   }
2144 parse_error:
2145   {
2146     GST_DEBUG ("failed to parse");
2147     gst_mikey_message_unref (msg);
2148     return NULL;
2149   }
2150 }
2151 
2152 #define AES_128_KEY_LEN 16
2153 #define AES_256_KEY_LEN 32
2154 #define HMAC_32_KEY_LEN 4
2155 #define HMAC_80_KEY_LEN 10
2156 
2157 static gboolean
auth_alg_from_cipher_name(const gchar * cipher,guint8 * auth_alg)2158 auth_alg_from_cipher_name (const gchar * cipher, guint8 * auth_alg)
2159 {
2160   if (g_strcmp0 (cipher, "aes-128-icm") == 0)
2161     *auth_alg = GST_MIKEY_MAC_HMAC_SHA_1_160;
2162   else if (g_strcmp0 (cipher, "aes-256-icm") == 0)
2163     *auth_alg = GST_MIKEY_MAC_HMAC_SHA_1_160;
2164   else if (g_strcmp0 (cipher, "aes-128-gcm") == 0)
2165     *auth_alg = GST_MIKEY_MAC_NULL;
2166   else if (g_strcmp0 (cipher, "aes-256-gcm") == 0)
2167     *auth_alg = GST_MIKEY_MAC_NULL;
2168   else {
2169     GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2170     return FALSE;
2171   }
2172   return TRUE;
2173 }
2174 
2175 static gboolean
enc_alg_from_cipher_name(const gchar * cipher,guint8 * enc_alg)2176 enc_alg_from_cipher_name (const gchar * cipher, guint8 * enc_alg)
2177 {
2178   if (g_strcmp0 (cipher, "aes-128-icm") == 0)
2179     *enc_alg = GST_MIKEY_ENC_AES_CM_128;
2180   else if (g_strcmp0 (cipher, "aes-256-icm") == 0)
2181     *enc_alg = GST_MIKEY_ENC_AES_CM_128;
2182   else if (g_strcmp0 (cipher, "aes-128-gcm") == 0)
2183     *enc_alg = GST_MIKEY_ENC_AES_GCM_128;
2184   else if (g_strcmp0 (cipher, "aes-256-gcm") == 0)
2185     *enc_alg = GST_MIKEY_ENC_AES_GCM_128;
2186   else {
2187     GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2188     return FALSE;
2189   }
2190   return TRUE;
2191 }
2192 
2193 
2194 static gboolean
enc_key_length_from_cipher_name(const gchar * cipher,guint8 * enc_key_length)2195 enc_key_length_from_cipher_name (const gchar * cipher, guint8 * enc_key_length)
2196 {
2197   if (g_strcmp0 (cipher, "aes-128-icm") == 0)
2198     *enc_key_length = AES_128_KEY_LEN;
2199   else if (g_strcmp0 (cipher, "aes-256-icm") == 0)
2200     *enc_key_length = AES_256_KEY_LEN;
2201   else if (g_strcmp0 (cipher, "aes-128-gcm") == 0)
2202     *enc_key_length = AES_128_KEY_LEN;
2203   else if (g_strcmp0 (cipher, "aes-256-gcm") == 0)
2204     *enc_key_length = AES_256_KEY_LEN;
2205   else {
2206     GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2207     return FALSE;
2208   }
2209   return TRUE;
2210 }
2211 
2212 static gboolean
auth_key_length_from_auth_cipher_name(const gchar * auth,const gchar * cipher,guint8 * length)2213 auth_key_length_from_auth_cipher_name (const gchar * auth, const gchar * cipher,
2214     guint8 * length)
2215 {
2216   if (g_strcmp0 (cipher, "aes-128-gcm") == 0
2217       || g_strcmp0 (cipher, "aes-256-gcm") == 0) {
2218     *length = 0;
2219   } else {
2220     if (g_strcmp0 (auth, "hmac-sha1-32") == 0) {
2221       *length = HMAC_32_KEY_LEN;
2222     } else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) {
2223       *length = HMAC_80_KEY_LEN;
2224     } else {
2225       GST_ERROR ("authentication algorithm '%s' not supported", auth);
2226       return FALSE;
2227     }
2228   }
2229   return TRUE;
2230 }
2231 
2232 /**
2233  * gst_mikey_message_new_from_caps:
2234  * @caps: a #GstCaps, including SRTP parameters (srtp/srtcp cipher, authorization, key data)
2235  *
2236  * Makes mikey message including:
2237  *  - Security Policy Payload
2238  *  - Key Data Transport Payload
2239  *  - Key Data Sub-Payload
2240  *
2241  * Returns: (transfer full): a #GstMIKEYMessage,
2242  * or %NULL if there is no srtp information in the caps.
2243  *
2244  * Since: 1.8
2245  */
2246 GstMIKEYMessage *
gst_mikey_message_new_from_caps(GstCaps * caps)2247 gst_mikey_message_new_from_caps (GstCaps * caps)
2248 {
2249   GstMIKEYMessage *msg;
2250   GstMIKEYPayload *payload, *pkd;
2251   guint8 byte;
2252   guint8 enc_alg;
2253   guint8 auth_alg;
2254   guint8 enc_key_length;
2255   guint8 auth_key_length;
2256   GstStructure *s;
2257   GstMapInfo info;
2258   GstBuffer *srtpkey;
2259   const GValue *val;
2260   const gchar *cipher, *auth;
2261   const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth;
2262 
2263   g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), NULL);
2264 
2265   s = gst_caps_get_structure (caps, 0);
2266   g_return_val_if_fail (s != NULL, NULL);
2267 
2268   val = gst_structure_get_value (s, "srtp-key");
2269   if (!val)
2270     goto no_key;
2271 
2272   srtpkey = gst_value_get_buffer (val);
2273   if (!srtpkey || !GST_IS_BUFFER (srtpkey))
2274     goto no_key;
2275 
2276   srtpcipher = gst_structure_get_string (s, "srtp-cipher");
2277   srtpauth = gst_structure_get_string (s, "srtp-auth");
2278   srtcpcipher = gst_structure_get_string (s, "srtcp-cipher");
2279   srtcpauth = gst_structure_get_string (s, "srtcp-auth");
2280 
2281   /* we need srtp cipher/auth or srtcp cipher/auth */
2282   if ((srtpcipher == NULL || srtpauth == NULL)
2283       && (srtcpcipher == NULL || srtcpauth == NULL)) {
2284     GST_WARNING ("could not find the right SRTP parameters in caps");
2285     return NULL;
2286   }
2287 
2288   /* prefer srtp cipher over srtcp */
2289   cipher = srtpcipher;
2290   if (cipher == NULL)
2291     cipher = srtcpcipher;
2292 
2293   /* prefer srtp auth over srtcp */
2294   auth = srtpauth;
2295   if (auth == NULL)
2296     auth = srtcpauth;
2297 
2298   /* get cipher and auth values */
2299   if (!enc_alg_from_cipher_name (cipher, &enc_alg) ||
2300       !auth_alg_from_cipher_name (cipher, &auth_alg) ||
2301       !enc_key_length_from_cipher_name (cipher, &enc_key_length) ||
2302       !auth_key_length_from_auth_cipher_name (auth, cipher, &auth_key_length)) {
2303     return NULL;
2304   }
2305 
2306   msg = gst_mikey_message_new ();
2307   /* unencrypted MIKEY message, we send this over TLS so this is allowed */
2308   gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT,
2309       FALSE, GST_MIKEY_PRF_MIKEY_1, g_random_int (), GST_MIKEY_MAP_TYPE_SRTP);
2310 
2311   /* timestamp is now */
2312   gst_mikey_message_add_t_now_ntp_utc (msg);
2313   /* add some random data */
2314   gst_mikey_message_add_rand_len (msg, 16);
2315 
2316   /* the policy '0' is SRTP */
2317   payload = gst_mikey_payload_new (GST_MIKEY_PT_SP);
2318   gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP);
2319 
2320   /* AES-CM or AES-GCM is supported */
2321   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1,
2322       &enc_alg);
2323   /* encryption key length */
2324   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1,
2325       &enc_key_length);
2326   /* HMAC-SHA1 or NULL in case of GCM */
2327   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1,
2328       &auth_alg);
2329   /* authentication key length */
2330   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1,
2331       &auth_key_length);
2332   /* we enable encryption on RTP and RTCP */
2333   byte = 1;
2334   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1,
2335       &byte);
2336   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1,
2337       &byte);
2338   /* we enable authentication on RTP and RTCP */
2339   gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1,
2340       &byte);
2341   gst_mikey_message_add_payload (msg, payload);
2342 
2343   /* make unencrypted KEMAC */
2344   payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC);
2345   gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL);
2346   /* add the key in KEMAC */
2347   pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA);
2348   gst_buffer_map (srtpkey, &info, GST_MAP_READ);
2349   gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size,
2350       info.data);
2351   gst_buffer_unmap (srtpkey, &info);
2352   gst_mikey_payload_kemac_add_sub (payload, pkd);
2353   gst_mikey_message_add_payload (msg, payload);
2354 
2355   return msg;
2356 
2357 no_key:
2358   GST_INFO ("No srtp key");
2359   return NULL;
2360 }
2361 
2362 #define AES_128_KEY_LEN 16
2363 #define AES_256_KEY_LEN 32
2364 #define HMAC_32_KEY_LEN 4
2365 #define HMAC_80_KEY_LEN 10
2366 
2367 /**
2368  * gst_mikey_message_to_caps:
2369  * @msg: a #GstMIKEYMessage
2370  * @caps: a #GstCaps to be filled with SRTP parameters (srtp/srtcp cipher, authorization, key data)
2371  *
2372  * Returns: %TRUE on success
2373  *
2374  * Since: 1.8.1
2375  */
2376 gboolean
gst_mikey_message_to_caps(const GstMIKEYMessage * msg,GstCaps * caps)2377 gst_mikey_message_to_caps (const GstMIKEYMessage * msg, GstCaps * caps)
2378 {
2379   gboolean res = FALSE;
2380   const GstMIKEYPayload *payload;
2381   const gchar *srtp_cipher;
2382   const gchar *srtp_auth;
2383 
2384   srtp_cipher = "aes-128-icm";
2385   srtp_auth = "hmac-sha1-80";
2386 
2387   /* check the Security policy if any */
2388   if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) {
2389     GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
2390     guint len, i;
2391     guint enc_alg = GST_MIKEY_ENC_NULL;
2392 
2393     if (p->proto != GST_MIKEY_SEC_PROTO_SRTP)
2394       goto done;
2395 
2396     len = gst_mikey_payload_sp_get_n_params (payload);
2397     for (i = 0; i < len; i++) {
2398       const GstMIKEYPayloadSPParam *param =
2399           gst_mikey_payload_sp_get_param (payload, i);
2400 
2401       switch (param->type) {
2402         case GST_MIKEY_SP_SRTP_ENC_ALG:
2403           enc_alg = param->val[0];
2404           switch (param->val[0]) {
2405             case GST_MIKEY_ENC_NULL:
2406               srtp_cipher = "null";
2407               break;
2408             case GST_MIKEY_ENC_AES_CM_128:
2409             case GST_MIKEY_ENC_AES_KW_128:
2410               srtp_cipher = "aes-128-icm";
2411               break;
2412             case GST_MIKEY_ENC_AES_GCM_128:
2413               srtp_cipher = "aes-128-gcm";
2414               break;
2415             default:
2416               break;
2417           }
2418           break;
2419         case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
2420           switch (param->val[0]) {
2421             case AES_128_KEY_LEN:
2422               if (enc_alg == GST_MIKEY_ENC_AES_CM_128 ||
2423                   enc_alg == GST_MIKEY_ENC_AES_KW_128) {
2424                 srtp_cipher = "aes-128-icm";
2425               } else if (enc_alg == GST_MIKEY_ENC_AES_GCM_128) {
2426                 srtp_cipher = "aes-128-gcm";
2427               }
2428               break;
2429             case AES_256_KEY_LEN:
2430               if (enc_alg == GST_MIKEY_ENC_AES_CM_128 ||
2431                   enc_alg == GST_MIKEY_ENC_AES_KW_128) {
2432                 srtp_cipher = "aes-256-icm";
2433               } else if (enc_alg == GST_MIKEY_ENC_AES_GCM_128) {
2434                 srtp_cipher = "aes-256-gcm";
2435               }
2436               break;
2437             default:
2438               break;
2439           }
2440           break;
2441         case GST_MIKEY_SP_SRTP_AUTH_ALG:
2442           switch (param->val[0]) {
2443             case GST_MIKEY_MAC_NULL:
2444               srtp_auth = "null";
2445               break;
2446             case GST_MIKEY_MAC_HMAC_SHA_1_160:
2447               srtp_auth = "hmac-sha1-80";
2448               break;
2449             default:
2450               break;
2451           }
2452           break;
2453         case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
2454           switch (param->val[0]) {
2455             case HMAC_32_KEY_LEN:
2456               srtp_auth = "hmac-sha1-32";
2457               break;
2458             case HMAC_80_KEY_LEN:
2459               srtp_auth = "hmac-sha1-80";
2460               break;
2461             default:
2462               break;
2463           }
2464           break;
2465         case GST_MIKEY_SP_SRTP_SRTP_ENC:
2466           break;
2467         case GST_MIKEY_SP_SRTP_SRTCP_ENC:
2468           break;
2469         default:
2470           break;
2471       }
2472     }
2473   }
2474 
2475   if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0)))
2476     goto done;
2477   else {
2478     GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
2479     const GstMIKEYPayload *sub;
2480     GstMIKEYPayloadKeyData *pkd;
2481     GstBuffer *buf;
2482 
2483     if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL)
2484       goto done;
2485 
2486     if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0)))
2487       goto done;
2488 
2489     if (sub->type != GST_MIKEY_PT_KEY_DATA)
2490       goto done;
2491 
2492     pkd = (GstMIKEYPayloadKeyData *) sub;
2493     buf =
2494         gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
2495         pkd->key_len);
2496     gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
2497     gst_buffer_unref (buf);
2498   }
2499 
2500   gst_caps_set_simple (caps,
2501       "srtp-cipher", G_TYPE_STRING, srtp_cipher,
2502       "srtp-auth", G_TYPE_STRING, srtp_auth,
2503       "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
2504       "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
2505 
2506   res = TRUE;
2507 
2508 done:
2509   return res;
2510 }
2511 
2512 /**
2513  * gst_mikey_message_base64_encode:
2514  * @msg: a #GstMIKEYMessage
2515  *
2516  * Returns: (transfer full): a #gchar, base64-encoded data
2517  *
2518  * Since: 1.8
2519  */
2520 gchar *
gst_mikey_message_base64_encode(GstMIKEYMessage * msg)2521 gst_mikey_message_base64_encode (GstMIKEYMessage * msg)
2522 {
2523   GBytes *bytes;
2524   gchar *base64;
2525   const guint8 *data;
2526   gsize size;
2527 
2528   g_return_val_if_fail (msg != NULL, NULL);
2529 
2530   /* serialize mikey message to bytes */
2531   bytes = gst_mikey_message_to_bytes (msg, NULL, NULL);
2532 
2533   /* and make it into base64 */
2534   data = g_bytes_get_data (bytes, &size);
2535   base64 = g_base64_encode (data, size);
2536   g_bytes_unref (bytes);
2537 
2538   return base64;
2539 }
2540