2 * Copyright (C) <2014> Wim Taymans <wim.taymans@gmail.com>
4 * gstmikey.h: various helper functions to manipulate mikey messages
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.
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.
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.
24 * @title: GstMIKEYMessage
25 * @short_description: Helper methods for dealing with MIKEY messages
27 * The GstMIKEY helper functions makes it easy to parse and create MIKEY
40 GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYPayload, gst_mikey_payload);
41 GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYMessage, gst_mikey_message);
44 payload_destroy (GstMIKEYPayload ** payload)
46 gst_mikey_payload_unref (*payload);
49 #define INIT_ARRAY(field, type, init_func) \
52 g_array_set_size ((field), 0); \
54 (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
55 g_array_set_clear_func ((field), (GDestroyNotify)init_func); \
59 #define FREE_ARRAY(field) \
62 g_array_free ((field), TRUE); \
66 #define INIT_MEMDUP(field, data, len) \
69 (field) = g_memdup2 (data, len); \
71 #define FREE_MEMDUP(field) \
78 /* Key data transport payload (KEMAC) */
80 get_mac_len (GstMIKEYMacAlg mac_alg)
85 case GST_MIKEY_MAC_NULL:
86 len = 0; /* no MAC key */
88 case GST_MIKEY_MAC_HMAC_SHA_1_160:
89 len = 20; /* 160 bits key */
99 * gst_mikey_payload_kemac_set:
100 * @payload: a #GstMIKEYPayload
101 * @enc_alg: the #GstMIKEYEncAlg
102 * @mac_alg: a #GstMIKEYMacAlg
104 * Set the KEMAC parameters. @payload should point to a %GST_MIKEY_PT_KEMAC
107 * Returns: %TRUE on success
112 gst_mikey_payload_kemac_set (GstMIKEYPayload * payload,
113 GstMIKEYEncAlg enc_alg, GstMIKEYMacAlg mac_alg)
115 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
117 g_return_val_if_fail (payload != NULL, FALSE);
118 g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, FALSE);
120 p->enc_alg = enc_alg;
121 p->mac_alg = mac_alg;
122 INIT_ARRAY (p->subpayloads, GstMIKEYPayload *, payload_destroy);
128 gst_mikey_payload_kemac_dispose (GstMIKEYPayloadKEMAC * payload)
130 FREE_ARRAY (payload->subpayloads);
135 static GstMIKEYPayloadKEMAC *
136 gst_mikey_payload_kemac_copy (const GstMIKEYPayloadKEMAC * payload)
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));
151 * gst_mikey_payload_kemac_get_n_sub:
152 * @payload: a #GstMIKEYPayload
154 * Get the number of sub payloads of @payload. @payload should be of type
155 * %GST_MIKEY_PT_KEMAC.
157 * Returns: the number of sub payloads in @payload
162 gst_mikey_payload_kemac_get_n_sub (const GstMIKEYPayload * payload)
164 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
166 g_return_val_if_fail (payload != NULL, 0);
167 g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
169 return p->subpayloads->len;
173 * gst_mikey_payload_kemac_get_sub:
174 * @payload: a #GstMIKEYPayload
177 * Get the sub payload of @payload at @idx. @payload should be of type
178 * %GST_MIKEY_PT_KEMAC.
180 * Returns: (transfer none): the #GstMIKEYPayload at @idx.
184 const GstMIKEYPayload *
185 gst_mikey_payload_kemac_get_sub (const GstMIKEYPayload * payload, guint idx)
187 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
189 g_return_val_if_fail (payload != NULL, 0);
190 g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
192 if (p->subpayloads->len <= idx)
195 return g_array_index (p->subpayloads, GstMIKEYPayload *, idx);
199 * gst_mikey_payload_kemac_remove_sub:
200 * @payload: a #GstMIKEYPayload
201 * @idx: the index to remove
203 * Remove the sub payload at @idx in @payload.
205 * Returns: %TRUE on success.
210 gst_mikey_payload_kemac_remove_sub (GstMIKEYPayload * payload, guint idx)
212 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
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);
218 g_array_remove_index (p->subpayloads, idx);
224 * gst_mikey_payload_kemac_add_sub:
225 * @payload: a #GstMIKEYPayload
226 * @newpay: (transfer full): a #GstMIKEYPayload to add
228 * Add a new sub payload to @payload.
230 * Returns: %TRUE on success.
235 gst_mikey_payload_kemac_add_sub (GstMIKEYPayload * payload,
236 GstMIKEYPayload * newpay)
238 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
240 g_return_val_if_fail (payload != NULL, 0);
241 g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0);
243 g_array_append_val (p->subpayloads, newpay);
248 /* Envelope data payload (PKE) */
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
256 * Set the PKE values in @payload. @payload must be of type
259 * Returns: %TRUE on success
264 gst_mikey_payload_pke_set (GstMIKEYPayload * payload, GstMIKEYCacheType C,
265 guint16 data_len, const guint8 * data)
267 GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload;
269 g_return_val_if_fail (payload != NULL, FALSE);
270 g_return_val_if_fail (payload->type == GST_MIKEY_PT_PKE, FALSE);
273 p->data_len = data_len;
274 INIT_MEMDUP (p->data, data, data_len);
280 gst_mikey_payload_pke_dispose (GstMIKEYPayloadPKE * payload)
282 FREE_MEMDUP (payload->data);
287 static GstMIKEYPayloadPKE *
288 gst_mikey_payload_pke_copy (const GstMIKEYPayloadPKE * payload)
290 GstMIKEYPayloadPKE *copy = g_slice_dup (GstMIKEYPayloadPKE, payload);
291 gst_mikey_payload_pke_set (©->pt, payload->C, payload->data_len,
296 /* DH data payload (DH) */
297 /* Signature payload (SIGN) */
299 /* Timestamp payload (T) */
301 get_ts_len (GstMIKEYTSType type)
306 case GST_MIKEY_TS_TYPE_NTP_UTC:
307 case GST_MIKEY_TS_TYPE_NTP:
310 case GST_MIKEY_TS_TYPE_COUNTER:
321 * gst_mikey_payload_t_set:
322 * @payload: a #GstMIKEYPayload
323 * @type: the #GstMIKEYTSType
324 * @ts_value: (array): the timestamp value
326 * Set the timestamp in a %GST_MIKEY_PT_T @payload.
328 * Returns: %TRUE on success
333 gst_mikey_payload_t_set (GstMIKEYPayload * payload,
334 GstMIKEYTSType type, const guint8 * ts_value)
336 GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload;
339 g_return_val_if_fail (payload != NULL, FALSE);
340 g_return_val_if_fail (payload->type == GST_MIKEY_PT_T, FALSE);
342 if ((ts_len = get_ts_len (type)) == -1)
346 INIT_MEMDUP (p->ts_value, ts_value, ts_len);
352 gst_mikey_payload_t_dispose (GstMIKEYPayloadT * payload)
354 FREE_MEMDUP (payload->ts_value);
359 static GstMIKEYPayloadT *
360 gst_mikey_payload_t_copy (const GstMIKEYPayloadT * payload)
362 GstMIKEYPayloadT *copy = g_slice_dup (GstMIKEYPayloadT, payload);
363 gst_mikey_payload_t_set (©->pt, payload->type, payload->ts_value);
367 /* ID payload (ID) */
368 /* Certificate Payload (CERT) */
369 /* Cert hash payload (CHASH)*/
370 /* Ver msg payload (V) */
371 /* Security Policy payload (SP)*/
373 param_clear (GstMIKEYPayloadSPParam * param)
375 FREE_MEMDUP (param->val);
379 * gst_mikey_payload_sp_set:
380 * @payload: a #GstMIKEYPayload
381 * @policy: the policy number
382 * @proto: a #GstMIKEYSecProto
384 * Set the Security Policy parameters for @payload.
386 * Returns: %TRUE on success
391 gst_mikey_payload_sp_set (GstMIKEYPayload * payload,
392 guint policy, GstMIKEYSecProto proto)
394 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
396 g_return_val_if_fail (payload != NULL, FALSE);
397 g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE);
401 INIT_ARRAY (p->params, GstMIKEYPayloadSPParam, param_clear);
407 gst_mikey_payload_sp_dispose (GstMIKEYPayloadSP * payload)
409 FREE_ARRAY (payload->params);
414 static GstMIKEYPayloadSP *
415 gst_mikey_payload_sp_copy (const GstMIKEYPayloadSP * payload)
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,
431 * gst_mikey_payload_sp_get_n_params:
432 * @payload: a #GstMIKEYPayload
434 * Get the number of security policy parameters in a %GST_MIKEY_PT_SP
437 * Returns: the number of parameters in @payload
442 gst_mikey_payload_sp_get_n_params (const GstMIKEYPayload * payload)
444 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
446 g_return_val_if_fail (payload != NULL, 0);
447 g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, 0);
449 return p->params->len;
454 * gst_mikey_payload_sp_get_param:
455 * @payload: a #GstMIKEYPayload
458 * Get the Security Policy parameter in a %GST_MIKEY_PT_SP @payload
461 * Returns: the #GstMIKEYPayloadSPParam at @idx in @payload
465 const GstMIKEYPayloadSPParam *
466 gst_mikey_payload_sp_get_param (const GstMIKEYPayload * payload, guint idx)
468 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
470 g_return_val_if_fail (payload != NULL, NULL);
471 g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, NULL);
473 if (p->params->len <= idx)
476 return &g_array_index (p->params, GstMIKEYPayloadSPParam, idx);
480 * gst_mikey_payload_sp_remove_param:
481 * @payload: a #GstMIKEYPayload
484 * Remove the Security Policy parameters from a %GST_MIKEY_PT_SP
487 * Returns: %TRUE on success
492 gst_mikey_payload_sp_remove_param (GstMIKEYPayload * payload, guint idx)
494 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
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);
500 g_array_remove_index (p->params, idx);
506 * gst_mikey_payload_sp_add_param:
507 * @payload: a #GstMIKEYPayload
510 * @val: (array length=len): @len bytes of data
512 * Add a new parameter to the %GST_MIKEY_PT_SP @payload with @type, @len
515 * Returns: %TRUE on success
520 gst_mikey_payload_sp_add_param (GstMIKEYPayload * payload,
521 guint8 type, guint8 len, const guint8 * val)
523 GstMIKEYPayloadSPParam param = { 0 };
524 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
526 g_return_val_if_fail (payload != NULL, FALSE);
527 g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE);
531 INIT_MEMDUP (param.val, val, len);
533 g_array_append_val (p->params, param);
538 /* RAND payload (RAND) */
540 * gst_mikey_payload_rand_set:
541 * @payload: a #GstMIKEYPayload
542 * @len: the length of @rand
543 * @rand: (array length=len): random values
545 * Set the random values in a %GST_MIKEY_PT_RAND @payload.
547 * Returns: %TRUE on success
552 gst_mikey_payload_rand_set (GstMIKEYPayload * payload, guint8 len,
555 GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload;
557 g_return_val_if_fail (payload != NULL, FALSE);
558 g_return_val_if_fail (payload->type == GST_MIKEY_PT_RAND, FALSE);
561 INIT_MEMDUP (p->rand, rand, len);
567 gst_mikey_payload_rand_dispose (GstMIKEYPayloadRAND * payload)
569 FREE_MEMDUP (payload->rand);
574 static GstMIKEYPayloadRAND *
575 gst_mikey_payload_rand_copy (const GstMIKEYPayloadRAND * payload)
577 GstMIKEYPayloadRAND *copy = g_slice_dup (GstMIKEYPayloadRAND, payload);
578 gst_mikey_payload_rand_set (©->pt, payload->len, payload->rand);
584 /* Error payload (ERR) */
585 /* Key data sub-payload */
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
594 * Set @key_len bytes of @key_data of type @key_type as the key for the
595 * %GST_MIKEY_PT_KEY_DATA @payload.
597 * Returns: %TRUE on success
602 gst_mikey_payload_key_data_set_key (GstMIKEYPayload * payload,
603 GstMIKEYKeyDataType key_type, guint16 key_len, const guint8 * key_data)
605 GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
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);
611 p->key_type = key_type;
612 p->key_len = key_len;
613 INIT_MEMDUP (p->key_data, key_data, key_len);
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
624 * Set the salt key data. If @salt_len is 0 and @salt_data is %NULL, the
625 * salt data will be removed.
627 * Returns: %TRUE on success
632 gst_mikey_payload_key_data_set_salt (GstMIKEYPayload * payload,
633 guint16 salt_len, const guint8 * salt_data)
635 GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
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);
642 p->salt_len = salt_len;
643 INIT_MEMDUP (p->salt_data, salt_data, salt_len);
648 /* Key validity data */
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
656 * Set the SPI/MKI validity in the %GST_MIKEY_PT_KEY_DATA @payload.
658 * Returns: %TRUE on success
663 gst_mikey_payload_key_data_set_spi (GstMIKEYPayload * payload,
664 guint8 spi_len, const guint8 * spi_data)
666 GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
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);
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);
677 FREE_MEMDUP (p->kv_data[1]);
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
690 * Set the key validity period in the %GST_MIKEY_PT_KEY_DATA @payload.
692 * Returns: %TRUE on success
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)
701 GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
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);
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);
720 gst_mikey_payload_key_data_dispose (GstMIKEYPayloadKeyData * payload)
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]);
730 static GstMIKEYPayloadKeyData *
731 gst_mikey_payload_key_data_copy (const GstMIKEYPayloadKeyData * payload)
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,
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]);
745 FREE_MEMDUP (copy->kv_data[0]);
746 FREE_MEMDUP (copy->kv_data[1]);
751 /* General Extension Payload */
754 mikey_payload_free (GstMIKEYPayload * payload)
756 g_slice_free1 (payload->len, payload);
761 * gst_mikey_payload_new:
762 * @type: a #GstMIKEYPayloadType
764 * Make a new #GstMIKEYPayload with @type.
766 * Returns: (nullable): a new #GstMIKEYPayload or %NULL on failure.
771 gst_mikey_payload_new (GstMIKEYPayloadType type)
774 GstMIKEYPayload *result;
775 GstMiniObjectCopyFunction copy;
776 GstMiniObjectDisposeFunction clear;
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;
785 len = sizeof (GstMIKEYPayloadT);
786 clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_t_dispose;
787 copy = (GstMiniObjectCopyFunction) gst_mikey_payload_t_copy;
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;
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:
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;
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;
810 case GST_MIKEY_PT_ERR:
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;
817 case GST_MIKEY_PT_GEN_EXT:
818 case GST_MIKEY_PT_LAST:
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);
834 static GstMIKEYMessage *
835 mikey_message_copy (GstMIKEYMessage * msg)
837 GstMIKEYMessage *copy;
840 copy = gst_mikey_message_new ();
842 gst_mikey_message_set_info (copy, msg->version, msg->type, msg->V,
843 msg->prf_func, msg->CSB_id, msg->map_type);
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);
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));
860 mikey_message_free (GstMIKEYMessage * msg)
862 FREE_ARRAY (msg->map_info);
863 FREE_ARRAY (msg->payloads);
865 g_slice_free (GstMIKEYMessage, msg);
869 * gst_mikey_message_new:
871 * Make a new MIKEY message.
873 * Returns: a new #GstMIKEYMessage on success
878 gst_mikey_message_new (void)
880 GstMIKEYMessage *result;
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);
888 INIT_ARRAY (result->map_info, GstMIKEYMapSRTP, NULL);
889 INIT_ARRAY (result->payloads, GstMIKEYPayload *, payload_destroy);
895 * gst_mikey_message_new_from_bytes:
897 * @info: a #GstMIKEYDecryptInfo
900 * Make a new #GstMIKEYMessage from @bytes.
902 * Returns: a new #GstMIKEYMessage
907 gst_mikey_message_new_from_bytes (GBytes * bytes, GstMIKEYDecryptInfo * info,
913 g_return_val_if_fail (bytes != NULL, NULL);
915 data = g_bytes_get_data (bytes, &size);
916 return gst_mikey_message_new_from_data (data, size, info, error);
920 * gst_mikey_message_set_info:
921 * @msg: a #GstMIKEYMessage
922 * @version: a version
923 * @type: a #GstMIKEYType
925 * @prf_func: the #GstMIKEYPRFFunc function to use
926 * @CSB_id: the Crypto Session Bundle id
927 * @map_type: the #GstMIKEYMapType
929 * Set the information in @msg.
931 * Returns: %TRUE on success
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)
940 g_return_val_if_fail (msg != NULL, FALSE);
942 msg->version = version;
945 msg->prf_func = prf_func;
946 msg->CSB_id = CSB_id;
947 msg->map_type = map_type;
953 * gst_mikey_message_get_n_cs:
954 * @msg: a #GstMIKEYMessage
956 * Get the number of crypto sessions in @msg.
958 * Returns: the number of crypto sessions
963 gst_mikey_message_get_n_cs (const GstMIKEYMessage * msg)
965 g_return_val_if_fail (msg != NULL, 0);
967 return msg->map_info->len;
971 * gst_mikey_message_get_cs_srtp:
972 * @msg: a #GstMIKEYMessage
975 * Get the policy information of @msg at @idx.
977 * Returns: a #GstMIKEYMapSRTP
981 const GstMIKEYMapSRTP *
982 gst_mikey_message_get_cs_srtp (const GstMIKEYMessage * msg, guint idx)
984 g_return_val_if_fail (msg != NULL, NULL);
985 g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, NULL);
987 if (msg->map_info->len <= idx)
990 return &g_array_index (msg->map_info, GstMIKEYMapSRTP, idx);
994 * gst_mikey_message_insert_cs_srtp:
995 * @msg: a #GstMIKEYMessage
996 * @idx: the index to insert at
999 * Insert a Crypto Session map for SRTP in @msg at @idx
1001 * When @idx is -1, the policy will be appended.
1003 * Returns: %TRUE on success
1008 gst_mikey_message_insert_cs_srtp (GstMIKEYMessage * msg, gint idx,
1009 const GstMIKEYMapSRTP * map)
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);
1017 g_array_append_val (msg->map_info, *map);
1019 g_array_insert_val (msg->map_info, idx, *map);
1025 * gst_mikey_message_replace_cs_srtp:
1026 * @msg: a #GstMIKEYMessage
1027 * @idx: the index to insert at
1028 * @map: the map info
1030 * Replace a Crypto Session map for SRTP in @msg at @idx with @map.
1032 * Returns: %TRUE on success
1037 gst_mikey_message_replace_cs_srtp (GstMIKEYMessage * msg, gint idx,
1038 const GstMIKEYMapSRTP * map)
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);
1045 g_array_index (msg->map_info, GstMIKEYMapSRTP, idx) = *map;
1051 * gst_mikey_message_remove_cs_srtp:
1052 * @msg: a #GstMIKEYMessage
1053 * @idx: the index to remove
1055 * Remove the SRTP policy at @idx.
1057 * Returns: %TRUE on success
1062 gst_mikey_message_remove_cs_srtp (GstMIKEYMessage * msg, gint idx)
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);
1068 g_array_remove_index (msg->map_info, idx);
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
1080 * Add a Crypto policy for SRTP to @msg.
1082 * Returns: %TRUE on success
1087 gst_mikey_message_add_cs_srtp (GstMIKEYMessage * msg, guint8 policy,
1088 guint32 ssrc, guint32 roc)
1090 GstMIKEYMapSRTP val;
1092 g_return_val_if_fail (msg != NULL, FALSE);
1093 g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE);
1095 val.policy = policy;
1099 return gst_mikey_message_insert_cs_srtp (msg, -1, &val);
1102 /* adding/retrieving payloads */
1104 * gst_mikey_message_get_n_payloads:
1105 * @msg: a #GstMIKEYMessage
1107 * Get the number of payloads in @msg.
1109 * Returns: the number of payloads in @msg
1114 gst_mikey_message_get_n_payloads (const GstMIKEYMessage * msg)
1116 g_return_val_if_fail (msg != NULL, 0);
1118 return msg->payloads->len;
1122 * gst_mikey_message_get_payload:
1123 * @msg: a #GstMIKEYMessage
1126 * Get the #GstMIKEYPayload at @idx in @msg
1128 * Returns: (transfer none): the #GstMIKEYPayload at @idx. The payload
1129 * remains valid for as long as it is part of @msg.
1133 const GstMIKEYPayload *
1134 gst_mikey_message_get_payload (const GstMIKEYMessage * msg, guint idx)
1136 g_return_val_if_fail (msg != NULL, NULL);
1138 if (idx >= msg->payloads->len)
1141 return g_array_index (msg->payloads, GstMIKEYPayload *, idx);
1145 * gst_mikey_message_find_payload:
1146 * @msg: a #GstMIKEYMessage
1147 * @type: a #GstMIKEYPayloadType
1148 * @nth: payload to find
1150 * Find the @nth occurrence of the payload with @type in @msg.
1152 * Returns: the @nth #GstMIKEYPayload of @type.
1156 const GstMIKEYPayload *
1157 gst_mikey_message_find_payload (const GstMIKEYMessage * msg,
1158 GstMIKEYPayloadType type, guint idx)
1160 guint i, len, count;
1163 len = msg->payloads->len;
1164 for (i = 0; i < len; i++) {
1165 GstMIKEYPayload *payload =
1166 g_array_index (msg->payloads, GstMIKEYPayload *, i);
1168 if (payload->type == type) {
1179 * gst_mikey_message_remove_payload:
1180 * @msg: a #GstMIKEYMessage
1183 * Remove the payload in @msg at @idx
1185 * Returns: %TRUE on success
1190 gst_mikey_message_remove_payload (GstMIKEYMessage * msg, guint idx)
1192 g_return_val_if_fail (msg != NULL, FALSE);
1193 g_return_val_if_fail (msg->payloads->len > idx, FALSE);
1195 g_array_remove_index (msg->payloads, idx);
1201 * gst_mikey_message_insert_payload:
1202 * @msg: a #GstMIKEYMessage
1204 * @payload: (transfer full): a #GstMIKEYPayload
1206 * Insert the @payload at index @idx in @msg. If @idx is -1, the payload
1207 * will be appended to @msg.
1209 * Returns: %TRUE on success
1214 gst_mikey_message_insert_payload (GstMIKEYMessage * msg, guint idx,
1215 GstMIKEYPayload * payload)
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);
1222 g_array_append_val (msg->payloads, payload);
1224 g_array_insert_val (msg->payloads, idx, payload);
1230 * gst_mikey_message_add_payload:
1231 * @msg: a #GstMIKEYMessage
1232 * @payload: (transfer full): a #GstMIKEYPayload
1234 * Add a new payload to @msg.
1236 * Returns: %TRUE on success
1241 gst_mikey_message_add_payload (GstMIKEYMessage * msg, GstMIKEYPayload * payload)
1243 return gst_mikey_message_insert_payload (msg, -1, payload);
1247 * gst_mikey_message_replace_payload:
1248 * @msg: a #GstMIKEYMessage
1250 * @payload: (transfer full): a #GstMIKEYPayload
1252 * Replace the payload at @idx in @msg with @payload.
1254 * Returns: %TRUE on success
1259 gst_mikey_message_replace_payload (GstMIKEYMessage * msg, guint idx,
1260 GstMIKEYPayload * payload)
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);
1268 p = g_array_index (msg->payloads, GstMIKEYPayload *, idx);
1269 gst_mikey_payload_unref (p);
1270 g_array_index (msg->payloads, GstMIKEYPayload *, idx) = payload;
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
1282 * Add a new PKE payload to @msg with the given parameters.
1284 * Returns: %TRUE on success
1289 gst_mikey_message_add_pke (GstMIKEYMessage * msg, GstMIKEYCacheType C,
1290 guint16 data_len, const guint8 * data)
1294 g_return_val_if_fail (msg != NULL, FALSE);
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);
1302 return gst_mikey_message_insert_payload (msg, -1, p);
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
1311 * Add a new T payload to @msg with the given parameters.
1313 * Returns: %TRUE on success
1318 gst_mikey_message_add_t (GstMIKEYMessage * msg, GstMIKEYTSType type,
1319 const guint8 * ts_value)
1323 g_return_val_if_fail (msg != NULL, FALSE);
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);
1331 return gst_mikey_message_insert_payload (msg, -1, p);
1335 * gst_mikey_message_add_t_now_ntp_utc:
1336 * @msg: a #GstMIKEYMessage
1338 * Add a new T payload to @msg that contains the current time
1339 * in NTP-UTC format.
1341 * Returns: %TRUE on success
1346 gst_mikey_message_add_t_now_ntp_utc (GstMIKEYMessage * msg)
1352 now = g_get_real_time ();
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
1359 ntptime += (G_GUINT64_CONSTANT (2208988800) << 32);
1360 GST_WRITE_UINT64_BE (bytes, ntptime);
1362 return gst_mikey_message_add_t (msg, GST_MIKEY_TS_TYPE_NTP_UTC, bytes);
1366 * gst_mikey_message_add_rand:
1367 * @msg: a #GstMIKEYMessage
1368 * @len: the length of @rand
1369 * @rand: (array length=len): random data
1371 * Add a new RAND payload to @msg with the given parameters.
1373 * Returns: %TRUE on success
1378 gst_mikey_message_add_rand (GstMIKEYMessage * msg, guint8 len,
1379 const guint8 * rand)
1383 g_return_val_if_fail (msg != NULL, FALSE);
1384 g_return_val_if_fail (len != 0 && rand != NULL, FALSE);
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);
1392 return gst_mikey_message_insert_payload (msg, -1, p);
1396 * gst_mikey_message_add_rand_len:
1397 * @msg: a #GstMIKEYMessage
1400 * Add a new RAND payload to @msg with @len random bytes.
1402 * Returns: %TRUE on success
1407 gst_mikey_message_add_rand_len (GstMIKEYMessage * msg, guint8 len)
1409 GstMIKEYPayloadRAND *p;
1412 p = (GstMIKEYPayloadRAND *) gst_mikey_payload_new (GST_MIKEY_PT_RAND);
1414 p->rand = g_malloc (len);
1415 for (i = 0; i < len; i++)
1416 p->rand[i] = g_random_int_range (0, 256);
1418 return gst_mikey_message_add_payload (msg, &p->pt);
1421 #define ENSURE_SIZE(n) \
1423 guint offset = data - arr->data; \
1424 g_byte_array_set_size (arr, offset + n); \
1425 data = arr->data + offset; \
1428 payloads_to_bytes (GArray * payloads, GByteArray * arr, guint8 ** ptr,
1429 guint offset, GstMIKEYEncryptInfo * info, GError ** error)
1431 guint i, n_payloads, len, start, size;
1433 GstMIKEYPayload *next_payload;
1436 start = *ptr - arr->data;
1437 data = *ptr + offset;
1439 n_payloads = payloads->len;
1441 for (i = 0; i < n_payloads; i++) {
1442 GstMIKEYPayload *payload = g_array_index (payloads, GstMIKEYPayload *, i);
1444 if (i + 1 < n_payloads)
1445 next_payload = g_array_index (payloads, GstMIKEYPayload *, i + 1);
1447 next_payload = NULL;
1449 switch (payload->type) {
1450 case GST_MIKEY_PT_KEMAC:
1452 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
1456 if ((mac_len = get_mac_len (p->mac_alg)) == -1)
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1465 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1467 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1470 data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1471 data[1] = p->enc_alg;
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);
1477 ENSURE_SIZE (5 + mac_len);
1478 data[4] = p->mac_alg;
1479 /* FIXME, do mac here */
1480 data += 5 + mac_len;
1483 case GST_MIKEY_PT_T:
1485 GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload;
1488 if ((ts_len = get_ts_len (p->type)) == -1)
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1497 ENSURE_SIZE (2 + ts_len);
1498 data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1500 memcpy (&data[2], p->ts_value, ts_len);
1504 case GST_MIKEY_PT_PKE:
1507 GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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;
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:
1529 case GST_MIKEY_PT_SP:
1531 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
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;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1549 ENSURE_SIZE (5 + plen);
1550 data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1551 data[1] = p->policy;
1553 GST_WRITE_UINT16_BE (&data[3], plen);
1555 for (i = 0; i < len; i++) {
1556 GstMIKEYPayloadSPParam *param = &g_array_index (p->params,
1557 GstMIKEYPayloadSPParam, i);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1564 data[0] = param->type;
1565 data[1] = param->len;
1566 memcpy (&data[2], param->val, param->len);
1567 data += 2 + param->len;
1571 case GST_MIKEY_PT_RAND:
1573 GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1580 ENSURE_SIZE (2 + p->len);
1581 data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
1583 memcpy (&data[2], p->rand, p->len);
1587 case GST_MIKEY_PT_ERR:
1589 case GST_MIKEY_PT_KEY_DATA:
1591 GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1598 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1599 * ! Salt len (optional) ! Salt data (optional) ~
1600 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1601 * ! KV data (optional) ~
1602 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1604 ENSURE_SIZE (4 + p->key_len);
1605 data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST;
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;
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;
1618 if (p->kv_type == GST_MIKEY_KV_SPI) {
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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) {
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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];
1651 case GST_MIKEY_PT_GEN_EXT:
1652 case GST_MIKEY_PT_LAST:
1656 *ptr = arr->data + start;
1657 size = arr->len - len;
1663 * gst_mikey_message_to_bytes:
1664 * @msg: a #GstMIKEYMessage
1665 * @info: a #GstMIKEYEncryptInfo
1668 * Convert @msg to a #GBytes.
1670 * Returns: a new #GBytes for @msg.
1675 gst_mikey_message_to_bytes (GstMIKEYMessage * msg, GstMIKEYEncryptInfo * info,
1678 GByteArray *arr = NULL;
1680 GstMIKEYPayload *next_payload;
1682 arr = g_byte_array_new ();
1685 if (msg->payloads->len == 0)
1686 next_payload = NULL;
1688 next_payload = g_array_index (msg->payloads, GstMIKEYPayload *, 0);
1690 n_cs = msg->map_info->len;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1697 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1698 * ! #CS ! CS ID map type! CS ID map info ~
1699 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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);
1708 data[9] = msg->map_type;
1711 for (i = 0; i < n_cs; i++) {
1712 GstMIKEYMapSRTP *info = &g_array_index (msg->map_info, GstMIKEYMapSRTP, i);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ...
1727 data[0] = info->policy;
1728 GST_WRITE_UINT32_BE (&data[1], info->ssrc);
1729 GST_WRITE_UINT32_BE (&data[5], info->roc);
1733 payloads_to_bytes (msg->payloads, arr, &data, 0, info, error);
1735 return g_byte_array_free_to_bytes (arr);
1748 #define CHECK_SIZE(n) if (size < (n)) goto short_data;
1749 #define ADVANCE(n) (d += (n), size -= (n));
1751 payloads_from_bytes (ParseState state, GArray * payloads, const guint8 * d,
1752 gsize size, guint8 next_payload, GstMIKEYDecryptInfo * info,
1757 while (next_payload != GST_MIKEY_PT_LAST) {
1759 switch (next_payload) {
1760 case GST_MIKEY_PT_KEMAC:
1763 GstMIKEYEncAlg enc_alg;
1765 const guint8 *enc_data;
1766 GstMIKEYMacAlg mac_alg;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1774 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1776 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1779 next_payload = d[0];
1781 enc_len = GST_READ_UINT16_BE (&d[2]);
1782 CHECK_SIZE (5 + enc_len);
1784 /* FIXME, decrypt data */
1787 if ((mac_len = get_mac_len (mac_alg)) == -1)
1789 CHECK_SIZE (5 + mac_len);
1790 /* FIXME, check MAC */
1791 ADVANCE (5 + mac_len);
1793 p = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC);
1794 gst_mikey_payload_kemac_set (p, enc_alg, mac_alg);
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;
1805 payloads_from_bytes (STATE_KEMAC,
1806 ((GstMIKEYPayloadKEMAC *) p)->subpayloads, enc_data, enc_len, np,
1808 g_array_append_val (payloads, p);
1811 case GST_MIKEY_PT_T:
1813 GstMIKEYTSType type;
1815 const guint8 *ts_value;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1823 next_payload = d[0];
1825 if ((ts_len = get_ts_len (type)) == -1)
1827 CHECK_SIZE (2 + ts_len);
1829 ADVANCE (2 + ts_len);
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);
1836 case GST_MIKEY_PT_PKE:
1839 guint16 clen, data_len;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1848 next_payload = d[0];
1849 clen = GST_READ_UINT16_BE (&d[1]);
1851 data_len = clen & 0x3fff;
1852 CHECK_SIZE (3 + data_len);
1854 ADVANCE (3 + data_len);
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);
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:
1868 case GST_MIKEY_PT_SP:
1871 GstMIKEYSecProto proto;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1882 next_payload = d[0];
1885 plen = GST_READ_UINT16_BE (&d[3]);
1888 p = gst_mikey_payload_new (GST_MIKEY_PT_SP);
1889 gst_mikey_payload_sp_set (p, policy, proto);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1904 CHECK_SIZE (2 + len);
1905 gst_mikey_payload_sp_add_param (p, type, len, &d[2]);
1909 g_array_append_val (payloads, p);
1912 case GST_MIKEY_PT_RAND:
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1923 next_payload = d[0];
1925 CHECK_SIZE (2 + len);
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);
1934 case GST_MIKEY_PT_ERR:
1936 case GST_MIKEY_PT_KEY_DATA:
1938 GstMIKEYKeyDataType key_type;
1939 GstMIKEYKVType kv_type;
1940 guint16 key_len, salt_len = 0;
1941 const guint8 *key_data, *salt_data;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1948 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1949 * ! Salt len (optional) ! Salt data (optional) ~
1950 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1951 * ! KV data (optional) ~
1952 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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);
1961 ADVANCE (4 + key_len);
1964 salt_len = GST_READ_UINT16_BE (&d[0]);
1965 CHECK_SIZE (2 + salt_len);
1967 ADVANCE (2 + salt_len);
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);
1972 gst_mikey_payload_key_data_set_salt (p, salt_len, salt_data);
1974 if (kv_type == GST_MIKEY_KV_SPI) {
1976 const guint8 *spi_data;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1986 CHECK_SIZE (1 + spi_len);
1988 ADVANCE (1 + spi_len);
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;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2005 CHECK_SIZE (1 + vf_len);
2007 ADVANCE (1 + vf_len);
2010 CHECK_SIZE (1 + vt_len);
2012 ADVANCE (1 + vt_len);
2014 gst_mikey_payload_key_data_set_interval (p, vf_len, vf_data, vt_len,
2016 } else if (kv_type != GST_MIKEY_KV_NULL)
2019 g_array_append_val (payloads, p);
2022 case GST_MIKEY_PT_GEN_EXT:
2023 case GST_MIKEY_PT_LAST:
2032 GST_DEBUG ("not enough data");
2034 gst_mikey_payload_unref (p);
2039 GST_DEBUG ("invalid data");
2041 gst_mikey_payload_unref (p);
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
2053 * Parse @size bytes from @data into a #GstMIKEYMessage. @info contains the
2054 * parameters to decrypt and verify the data.
2056 * Returns: a #GstMIKEYMessage on success or %NULL when parsing failed and
2057 * @error will be set.
2062 gst_mikey_message_new_from_data (gconstpointer data, gsize size,
2063 GstMIKEYDecryptInfo * info, GError ** error)
2065 GstMIKEYMessage *msg;
2067 const guint8 *d = data;
2068 guint8 next_payload;
2071 g_return_val_if_fail (data != NULL, NULL);
2073 msg = gst_mikey_message_new ();
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2080 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2081 * ! #CS ! CS ID map type! CS ID map info ~
2082 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2085 msg->version = d[0];
2086 if (msg->version != GST_MIKEY_VERSION)
2087 goto unknown_version;
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]);
2095 msg->map_type = d[9];
2098 CHECK_SIZE (n_cs * 9);
2099 for (i = 0; i < n_cs; i++) {
2100 GstMIKEYMapSRTP map;
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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);
2118 if (msg->type == GST_MIKEY_TYPE_PSK_INIT)
2120 else if (msg->type == GST_MIKEY_TYPE_PK_INIT)
2123 state = STATE_OTHER;
2125 if (!payloads_from_bytes (state, msg->payloads, d, size, next_payload, info,
2134 GST_DEBUG ("not enough data");
2135 gst_mikey_message_unref (msg);
2140 GST_DEBUG ("unknown version");
2141 gst_mikey_message_unref (msg);
2146 GST_DEBUG ("failed to parse");
2147 gst_mikey_message_unref (msg);
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
2158 auth_alg_from_cipher_name (const gchar * cipher, guint8 * auth_alg)
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;
2169 GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2176 enc_alg_from_cipher_name (const gchar * cipher, guint8 * enc_alg)
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;
2187 GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2195 enc_key_length_from_cipher_name (const gchar * cipher, guint8 * enc_key_length)
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;
2206 GST_ERROR ("encryption algorithm '%s' not supported", cipher);
2213 auth_key_length_from_auth_cipher_name (const gchar * auth, const gchar * cipher,
2216 if (g_strcmp0 (cipher, "aes-128-gcm") == 0
2217 || g_strcmp0 (cipher, "aes-256-gcm") == 0) {
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;
2225 GST_ERROR ("authentication algorithm '%s' not supported", auth);
2233 * gst_mikey_message_new_from_caps:
2234 * @caps: a #GstCaps, including SRTP parameters (srtp/srtcp cipher, authorization, key data)
2236 * Makes mikey message including:
2237 * - Security Policy Payload
2238 * - Key Data Transport Payload
2239 * - Key Data Sub-Payload
2241 * Returns: (transfer full): a #GstMIKEYMessage,
2242 * or %NULL if there is no srtp information in the caps.
2247 gst_mikey_message_new_from_caps (GstCaps * caps)
2249 GstMIKEYMessage *msg;
2250 GstMIKEYPayload *payload, *pkd;
2254 guint8 enc_key_length;
2255 guint8 auth_key_length;
2260 const gchar *cipher, *auth;
2261 const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth;
2263 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), NULL);
2265 s = gst_caps_get_structure (caps, 0);
2266 g_return_val_if_fail (s != NULL, NULL);
2268 val = gst_structure_get_value (s, "srtp-key");
2272 srtpkey = gst_value_get_buffer (val);
2273 if (!srtpkey || !GST_IS_BUFFER (srtpkey))
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");
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");
2288 /* prefer srtp cipher over srtcp */
2289 cipher = srtpcipher;
2291 cipher = srtcpcipher;
2293 /* prefer srtp auth over srtcp */
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)) {
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);
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);
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);
2320 /* AES-CM or AES-GCM is supported */
2321 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1,
2323 /* encryption key length */
2324 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1,
2326 /* HMAC-SHA1 or NULL in case of GCM */
2327 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1,
2329 /* authentication key length */
2330 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1,
2332 /* we enable encryption on RTP and RTCP */
2334 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1,
2336 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1,
2338 /* we enable authentication on RTP and RTCP */
2339 gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1,
2341 gst_mikey_message_add_payload (msg, payload);
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,
2351 gst_buffer_unmap (srtpkey, &info);
2352 gst_mikey_payload_kemac_add_sub (payload, pkd);
2353 gst_mikey_message_add_payload (msg, payload);
2358 GST_INFO ("No srtp key");
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
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)
2372 * Returns: %TRUE on success
2377 gst_mikey_message_to_caps (const GstMIKEYMessage * msg, GstCaps * caps)
2379 gboolean res = FALSE;
2380 const GstMIKEYPayload *payload;
2381 const gchar *srtp_cipher;
2382 const gchar *srtp_auth;
2384 srtp_cipher = "aes-128-icm";
2385 srtp_auth = "hmac-sha1-80";
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;
2391 guint enc_alg = GST_MIKEY_ENC_NULL;
2393 if (p->proto != GST_MIKEY_SEC_PROTO_SRTP)
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);
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";
2408 case GST_MIKEY_ENC_AES_CM_128:
2409 case GST_MIKEY_ENC_AES_KW_128:
2410 srtp_cipher = "aes-128-icm";
2412 case GST_MIKEY_ENC_AES_GCM_128:
2413 srtp_cipher = "aes-128-gcm";
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";
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";
2441 case GST_MIKEY_SP_SRTP_AUTH_ALG:
2442 switch (param->val[0]) {
2443 case GST_MIKEY_MAC_NULL:
2446 case GST_MIKEY_MAC_HMAC_SHA_1_160:
2447 srtp_auth = "hmac-sha1-80";
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";
2458 case HMAC_80_KEY_LEN:
2459 srtp_auth = "hmac-sha1-80";
2465 case GST_MIKEY_SP_SRTP_SRTP_ENC:
2467 case GST_MIKEY_SP_SRTP_SRTCP_ENC:
2475 if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0)))
2478 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
2479 const GstMIKEYPayload *sub;
2480 GstMIKEYPayloadKeyData *pkd;
2483 if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL)
2486 if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0)))
2489 if (sub->type != GST_MIKEY_PT_KEY_DATA)
2492 pkd = (GstMIKEYPayloadKeyData *) sub;
2494 gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
2496 gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
2497 gst_buffer_unref (buf);
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);
2513 * gst_mikey_message_base64_encode:
2514 * @msg: a #GstMIKEYMessage
2516 * Returns: (transfer full): a #gchar, base64-encoded data
2521 gst_mikey_message_base64_encode (GstMIKEYMessage * msg)
2528 g_return_val_if_fail (msg != NULL, NULL);
2530 /* serialize mikey message to bytes */
2531 bytes = gst_mikey_message_to_bytes (msg, NULL, NULL);
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);