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_memdup2 (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 (©->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 (©->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 (©->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 (©->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 (©->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 (©->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 (©->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 (©->pt, payload->key_type,
735 payload->key_len, payload->key_data);
736 gst_mikey_payload_key_data_set_salt (©->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 (©->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 (©->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 occurrence 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 = gst_buffer_new_memdup (pkd->key_data, pkd->key_len);
2494 gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
2495 gst_buffer_unref (buf);
2496 }
2497
2498 gst_caps_set_simple (caps,
2499 "srtp-cipher", G_TYPE_STRING, srtp_cipher,
2500 "srtp-auth", G_TYPE_STRING, srtp_auth,
2501 "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
2502 "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
2503
2504 res = TRUE;
2505
2506 done:
2507 return res;
2508 }
2509
2510 /**
2511 * gst_mikey_message_base64_encode:
2512 * @msg: a #GstMIKEYMessage
2513 *
2514 * Returns: (transfer full): a #gchar, base64-encoded data
2515 *
2516 * Since: 1.8
2517 */
2518 gchar *
gst_mikey_message_base64_encode(GstMIKEYMessage * msg)2519 gst_mikey_message_base64_encode (GstMIKEYMessage * msg)
2520 {
2521 GBytes *bytes;
2522 gchar *base64;
2523 const guint8 *data;
2524 gsize size;
2525
2526 g_return_val_if_fail (msg != NULL, NULL);
2527
2528 /* serialize mikey message to bytes */
2529 bytes = gst_mikey_message_to_bytes (msg, NULL, NULL);
2530
2531 /* and make it into base64 */
2532 data = g_bytes_get_data (bytes, &size);
2533 base64 = g_base64_encode (data, size);
2534 g_bytes_unref (bytes);
2535
2536 return base64;
2537 }
2538