| /* GStreamer |
| * Copyright (C) <2014> Wim Taymans <wim.taymans@gmail.com> |
| * |
| * gstmikey.h: various helper functions to manipulate mikey messages |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| /** |
| * SECTION:gstmikey |
| * @title: GstMIKEYMessage |
| * @short_description: Helper methods for dealing with MIKEY messages |
| * |
| * The GstMIKEY helper functions makes it easy to parse and create MIKEY |
| * messages. |
| * |
| * Since: 1.4 |
| */ |
| |
| #include <string.h> |
| |
| #include "gstmikey.h" |
| |
| GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYPayload, gst_mikey_payload); |
| GST_DEFINE_MINI_OBJECT_TYPE (GstMIKEYMessage, gst_mikey_message); |
| |
| static void |
| payload_destroy (GstMIKEYPayload ** payload) |
| { |
| gst_mikey_payload_unref (*payload); |
| } |
| |
| #define INIT_ARRAY(field, type, init_func) \ |
| G_STMT_START { \ |
| if (field) \ |
| g_array_set_size ((field), 0); \ |
| else { \ |
| (field) = g_array_new (FALSE, TRUE, sizeof (type)); \ |
| g_array_set_clear_func ((field), (GDestroyNotify)init_func); \ |
| } \ |
| } G_STMT_END |
| |
| #define FREE_ARRAY(field) \ |
| G_STMT_START { \ |
| if (field) \ |
| g_array_free ((field), TRUE); \ |
| (field) = NULL; \ |
| } G_STMT_END |
| |
| #define INIT_MEMDUP(field, data, len) \ |
| G_STMT_START { \ |
| g_free ((field)); \ |
| (field) = g_memdup (data, len); \ |
| } G_STMT_END |
| #define FREE_MEMDUP(field) \ |
| G_STMT_START { \ |
| g_free ((field)); \ |
| (field) = NULL; \ |
| } G_STMT_END |
| |
| |
| /* Key data transport payload (KEMAC) */ |
| static guint |
| get_mac_len (GstMIKEYMacAlg mac_alg) |
| { |
| guint len; |
| |
| switch (mac_alg) { |
| case GST_MIKEY_MAC_NULL: |
| len = 0; /* no MAC key */ |
| break; |
| case GST_MIKEY_MAC_HMAC_SHA_1_160: |
| len = 20; /* 160 bits key */ |
| break; |
| default: |
| len = -1; |
| break; |
| } |
| return len; |
| } |
| |
| /** |
| * gst_mikey_payload_kemac_set: |
| * @payload: a #GstMIKEYPayload |
| * @enc_alg: the #GstMIKEYEncAlg |
| * @mac_alg: a #GstMIKEYMacAlg |
| * |
| * Set the KEMAC parameters. @payload should point to a %GST_MIKEY_PT_KEMAC |
| * payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_kemac_set (GstMIKEYPayload * payload, |
| GstMIKEYEncAlg enc_alg, GstMIKEYMacAlg mac_alg) |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, FALSE); |
| |
| p->enc_alg = enc_alg; |
| p->mac_alg = mac_alg; |
| INIT_ARRAY (p->subpayloads, GstMIKEYPayload *, payload_destroy); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_kemac_dispose (GstMIKEYPayloadKEMAC * payload) |
| { |
| FREE_ARRAY (payload->subpayloads); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadKEMAC * |
| gst_mikey_payload_kemac_copy (const GstMIKEYPayloadKEMAC * payload) |
| { |
| guint i, len; |
| GstMIKEYPayloadKEMAC *copy = g_slice_dup (GstMIKEYPayloadKEMAC, payload); |
| gst_mikey_payload_kemac_set (©->pt, payload->enc_alg, payload->mac_alg); |
| len = payload->subpayloads->len; |
| for (i = 0; i < len; i++) { |
| GstMIKEYPayload *pay = |
| g_array_index (payload->subpayloads, GstMIKEYPayload *, i); |
| gst_mikey_payload_kemac_add_sub (©->pt, gst_mikey_payload_copy (pay)); |
| } |
| return copy; |
| } |
| |
| /** |
| * gst_mikey_payload_kemac_get_n_sub: |
| * @payload: a #GstMIKEYPayload |
| * |
| * Get the number of sub payloads of @payload. @payload should be of type |
| * %GST_MIKEY_PT_KEMAC. |
| * |
| * Returns: the number of sub payloads in @payload |
| * |
| * Since: 1.4 |
| */ |
| guint |
| gst_mikey_payload_kemac_get_n_sub (const GstMIKEYPayload * payload) |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| |
| g_return_val_if_fail (payload != NULL, 0); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0); |
| |
| return p->subpayloads->len; |
| } |
| |
| /** |
| * gst_mikey_payload_kemac_get_sub: |
| * @payload: a #GstMIKEYPayload |
| * @idx: an index |
| * |
| * Get the sub payload of @payload at @idx. @payload should be of type |
| * %GST_MIKEY_PT_KEMAC. |
| * |
| * Returns: (transfer none): the #GstMIKEYPayload at @idx. |
| * |
| * Since: 1.4 |
| */ |
| const GstMIKEYPayload * |
| gst_mikey_payload_kemac_get_sub (const GstMIKEYPayload * payload, guint idx) |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| |
| g_return_val_if_fail (payload != NULL, 0); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0); |
| |
| if (p->subpayloads->len <= idx) |
| return NULL; |
| |
| return g_array_index (p->subpayloads, GstMIKEYPayload *, idx); |
| } |
| |
| /** |
| * gst_mikey_payload_kemac_remove_sub: |
| * @payload: a #GstMIKEYPayload |
| * @idx: the index to remove |
| * |
| * Remove the sub payload at @idx in @payload. |
| * |
| * Returns: %TRUE on success. |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_kemac_remove_sub (GstMIKEYPayload * payload, guint idx) |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| |
| g_return_val_if_fail (payload != NULL, 0); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0); |
| g_return_val_if_fail (p->subpayloads->len > idx, FALSE); |
| |
| g_array_remove_index (p->subpayloads, idx); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_payload_kemac_add_sub: |
| * @payload: a #GstMIKEYPayload |
| * @newpay: (transfer full): a #GstMIKEYPayload to add |
| * |
| * Add a new sub payload to @payload. |
| * |
| * Returns: %TRUE on success. |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_kemac_add_sub (GstMIKEYPayload * payload, |
| GstMIKEYPayload * newpay) |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| |
| g_return_val_if_fail (payload != NULL, 0); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEMAC, 0); |
| |
| g_array_append_val (p->subpayloads, newpay); |
| |
| return TRUE; |
| } |
| |
| /* Envelope data payload (PKE) */ |
| /** |
| * gst_mikey_payload_pke_set: |
| * @payload: a #GstMIKEYPayload |
| * @C: envelope key cache indicator |
| * @data_len: the length of @data |
| * @data: (array length=data_len): the encrypted envelope key |
| * |
| * Set the PKE values in @payload. @payload must be of type |
| * %GST_MIKEY_PT_PKE. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_pke_set (GstMIKEYPayload * payload, GstMIKEYCacheType C, |
| guint16 data_len, const guint8 * data) |
| { |
| GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_PKE, FALSE); |
| |
| p->C = C; |
| p->data_len = data_len; |
| INIT_MEMDUP (p->data, data, data_len); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_pke_dispose (GstMIKEYPayloadPKE * payload) |
| { |
| FREE_MEMDUP (payload->data); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadPKE * |
| gst_mikey_payload_pke_copy (const GstMIKEYPayloadPKE * payload) |
| { |
| GstMIKEYPayloadPKE *copy = g_slice_dup (GstMIKEYPayloadPKE, payload); |
| gst_mikey_payload_pke_set (©->pt, payload->C, payload->data_len, |
| payload->data); |
| return copy; |
| } |
| |
| /* DH data payload (DH) */ |
| /* Signature payload (SIGN) */ |
| |
| /* Timestamp payload (T) */ |
| static guint |
| get_ts_len (GstMIKEYTSType type) |
| { |
| guint len; |
| |
| switch (type) { |
| case GST_MIKEY_TS_TYPE_NTP_UTC: |
| case GST_MIKEY_TS_TYPE_NTP: |
| len = 8; |
| break; |
| case GST_MIKEY_TS_TYPE_COUNTER: |
| len = 4; |
| break; |
| default: |
| len = -1; |
| break; |
| } |
| return len; |
| } |
| |
| /** |
| * gst_mikey_payload_t_set: |
| * @payload: a #GstMIKEYPayload |
| * @type: the #GstMIKEYTSType |
| * @ts_value: (array): the timestamp value |
| * |
| * Set the timestamp in a %GST_MIKEY_PT_T @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_t_set (GstMIKEYPayload * payload, |
| GstMIKEYTSType type, const guint8 * ts_value) |
| { |
| GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload; |
| guint ts_len; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_T, FALSE); |
| |
| if ((ts_len = get_ts_len (type)) == -1) |
| return FALSE; |
| |
| p->type = type; |
| INIT_MEMDUP (p->ts_value, ts_value, ts_len); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_t_dispose (GstMIKEYPayloadT * payload) |
| { |
| FREE_MEMDUP (payload->ts_value); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadT * |
| gst_mikey_payload_t_copy (const GstMIKEYPayloadT * payload) |
| { |
| GstMIKEYPayloadT *copy = g_slice_dup (GstMIKEYPayloadT, payload); |
| gst_mikey_payload_t_set (©->pt, payload->type, payload->ts_value); |
| return copy; |
| } |
| |
| /* ID payload (ID) */ |
| /* Certificate Payload (CERT) */ |
| /* Cert hash payload (CHASH)*/ |
| /* Ver msg payload (V) */ |
| /* Security Policy payload (SP)*/ |
| static void |
| param_clear (GstMIKEYPayloadSPParam * param) |
| { |
| FREE_MEMDUP (param->val); |
| } |
| |
| /** |
| * gst_mikey_payload_sp_set: |
| * @payload: a #GstMIKEYPayload |
| * @policy: the policy number |
| * @proto: a #GstMIKEYSecProto |
| * |
| * Set the Security Policy parameters for @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_sp_set (GstMIKEYPayload * payload, |
| guint policy, GstMIKEYSecProto proto) |
| { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE); |
| |
| p->policy = policy; |
| p->proto = proto; |
| INIT_ARRAY (p->params, GstMIKEYPayloadSPParam, param_clear); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_sp_dispose (GstMIKEYPayloadSP * payload) |
| { |
| FREE_ARRAY (payload->params); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadSP * |
| gst_mikey_payload_sp_copy (const GstMIKEYPayloadSP * payload) |
| { |
| guint i, len; |
| GstMIKEYPayloadSP *copy = g_slice_dup (GstMIKEYPayloadSP, payload); |
| gst_mikey_payload_sp_set (©->pt, payload->policy, payload->proto); |
| len = payload->params->len; |
| for (i = 0; i < len; i++) { |
| GstMIKEYPayloadSPParam *param = &g_array_index (payload->params, |
| GstMIKEYPayloadSPParam, i); |
| gst_mikey_payload_sp_add_param (©->pt, param->type, param->len, |
| param->val); |
| } |
| return copy; |
| } |
| |
| /** |
| * gst_mikey_payload_sp_get_n_params: |
| * @payload: a #GstMIKEYPayload |
| * |
| * Get the number of security policy parameters in a %GST_MIKEY_PT_SP |
| * @payload. |
| * |
| * Returns: the number of parameters in @payload |
| * |
| * Since: 1.4 |
| */ |
| guint |
| gst_mikey_payload_sp_get_n_params (const GstMIKEYPayload * payload) |
| { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| |
| g_return_val_if_fail (payload != NULL, 0); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, 0); |
| |
| return p->params->len; |
| |
| } |
| |
| /** |
| * gst_mikey_payload_sp_get_param: |
| * @payload: a #GstMIKEYPayload |
| * @idx: an index |
| * |
| * Get the Security Policy parameter in a %GST_MIKEY_PT_SP @payload |
| * at @idx. |
| * |
| * Returns: the #GstMIKEYPayloadSPParam at @idx in @payload |
| * |
| * Since: 1.4 |
| */ |
| const GstMIKEYPayloadSPParam * |
| gst_mikey_payload_sp_get_param (const GstMIKEYPayload * payload, guint idx) |
| { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| |
| g_return_val_if_fail (payload != NULL, NULL); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, NULL); |
| |
| if (p->params->len <= idx) |
| return NULL; |
| |
| return &g_array_index (p->params, GstMIKEYPayloadSPParam, idx); |
| } |
| |
| /** |
| * gst_mikey_payload_sp_remove_param: |
| * @payload: a #GstMIKEYPayload |
| * @idx: an index |
| * |
| * Remove the Security Policy parameters from a %GST_MIKEY_PT_SP |
| * @payload at @idx. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_sp_remove_param (GstMIKEYPayload * payload, guint idx) |
| { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE); |
| g_return_val_if_fail (p->params->len > idx, FALSE); |
| |
| g_array_remove_index (p->params, idx); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_payload_sp_add_param: |
| * @payload: a #GstMIKEYPayload |
| * @type: a type |
| * @len: a length |
| * @val: (array length=len): @len bytes of data |
| * |
| * Add a new parameter to the %GST_MIKEY_PT_SP @payload with @type, @len |
| * and @val. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_sp_add_param (GstMIKEYPayload * payload, |
| guint8 type, guint8 len, const guint8 * val) |
| { |
| GstMIKEYPayloadSPParam param = { 0 }; |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_SP, FALSE); |
| |
| param.type = type; |
| param.len = len; |
| INIT_MEMDUP (param.val, val, len); |
| |
| g_array_append_val (p->params, param); |
| |
| return TRUE; |
| } |
| |
| /* RAND payload (RAND) */ |
| /** |
| * gst_mikey_payload_rand_set: |
| * @payload: a #GstMIKEYPayload |
| * @len: the length of @rand |
| * @rand: (array length=len): random values |
| * |
| * Set the random values in a %GST_MIKEY_PT_RAND @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_rand_set (GstMIKEYPayload * payload, guint8 len, |
| const guint8 * rand) |
| { |
| GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_RAND, FALSE); |
| |
| p->len = len; |
| INIT_MEMDUP (p->rand, rand, len); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_rand_dispose (GstMIKEYPayloadRAND * payload) |
| { |
| FREE_MEMDUP (payload->rand); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadRAND * |
| gst_mikey_payload_rand_copy (const GstMIKEYPayloadRAND * payload) |
| { |
| GstMIKEYPayloadRAND *copy = g_slice_dup (GstMIKEYPayloadRAND, payload); |
| gst_mikey_payload_rand_set (©->pt, payload->len, payload->rand); |
| return copy; |
| } |
| |
| |
| |
| /* Error payload (ERR) */ |
| /* Key data sub-payload */ |
| |
| /** |
| * gst_mikey_payload_key_data_set_key: |
| * @payload: a #GstMIKEYPayload |
| * @key_type: a #GstMIKEYKeyDataType |
| * @key_len: the length of @key_data |
| * @key_data: (array length=key_len): the key of type @key_type |
| * |
| * Set @key_len bytes of @key_data of type @key_type as the key for the |
| * %GST_MIKEY_PT_KEY_DATA @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_key_data_set_key (GstMIKEYPayload * payload, |
| GstMIKEYKeyDataType key_type, guint16 key_len, const guint8 * key_data) |
| { |
| GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE); |
| g_return_val_if_fail (key_len > 0 && key_data != NULL, FALSE); |
| |
| p->key_type = key_type; |
| p->key_len = key_len; |
| INIT_MEMDUP (p->key_data, key_data, key_len); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_payload_key_data_set_salt: |
| * @payload: a #GstMIKEYPayload |
| * @salt_len: the length of @salt_data |
| * @salt_data: (array length=salt_len) (allow-none): the salt |
| * |
| * Set the salt key data. If @salt_len is 0 and @salt_data is %NULL, the |
| * salt data will be removed. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_key_data_set_salt (GstMIKEYPayload * payload, |
| guint16 salt_len, const guint8 * salt_data) |
| { |
| GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE); |
| g_return_val_if_fail ((salt_len == 0 && salt_data == NULL) || |
| (salt_len > 0 && salt_data != NULL), FALSE); |
| |
| p->salt_len = salt_len; |
| INIT_MEMDUP (p->salt_data, salt_data, salt_len); |
| |
| return TRUE; |
| } |
| |
| /* Key validity data */ |
| |
| /** |
| * gst_mikey_payload_key_data_set_spi: |
| * @payload: a #GstMIKEYPayload |
| * @spi_len: the length of @spi_data |
| * @spi_data: (array length=spi_len): the SPI/MKI data |
| * |
| * Set the SPI/MKI validity in the %GST_MIKEY_PT_KEY_DATA @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_key_data_set_spi (GstMIKEYPayload * payload, |
| guint8 spi_len, const guint8 * spi_data) |
| { |
| GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE); |
| g_return_val_if_fail ((spi_len == 0 && spi_data == NULL) || |
| (spi_len > 0 && spi_data != NULL), FALSE); |
| |
| p->kv_type = GST_MIKEY_KV_SPI; |
| p->kv_len[0] = spi_len; |
| INIT_MEMDUP (p->kv_data[0], spi_data, spi_len); |
| p->kv_len[1] = 0; |
| FREE_MEMDUP (p->kv_data[1]); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_payload_key_data_set_interval: |
| * @payload: a #GstMIKEYPayload |
| * @vf_len: the length of @vf_data |
| * @vf_data: (array length=vf_data): the Valid From data |
| * @vt_len: the length of @vt_data |
| * @vt_data: (array length=vt_len): the Valid To data |
| * |
| * Set the key validity period in the %GST_MIKEY_PT_KEY_DATA @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_payload_key_data_set_interval (GstMIKEYPayload * payload, |
| guint8 vf_len, const guint8 * vf_data, guint8 vt_len, |
| const guint8 * vt_data) |
| { |
| GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload; |
| |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (payload->type == GST_MIKEY_PT_KEY_DATA, FALSE); |
| g_return_val_if_fail ((vf_len == 0 && vf_data == NULL) || |
| (vf_len > 0 && vf_data != NULL), FALSE); |
| g_return_val_if_fail ((vt_len == 0 && vt_data == NULL) || |
| (vt_len > 0 && vt_data != NULL), FALSE); |
| |
| p->kv_type = GST_MIKEY_KV_INTERVAL; |
| p->kv_len[0] = vf_len; |
| INIT_MEMDUP (p->kv_data[0], vf_data, vf_len); |
| p->kv_len[1] = vt_len; |
| INIT_MEMDUP (p->kv_data[1], vt_data, vt_len); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_mikey_payload_key_data_dispose (GstMIKEYPayloadKeyData * payload) |
| { |
| FREE_MEMDUP (payload->key_data); |
| FREE_MEMDUP (payload->salt_data); |
| FREE_MEMDUP (payload->kv_data[0]); |
| FREE_MEMDUP (payload->kv_data[1]); |
| |
| return TRUE; |
| } |
| |
| static GstMIKEYPayloadKeyData * |
| gst_mikey_payload_key_data_copy (const GstMIKEYPayloadKeyData * payload) |
| { |
| GstMIKEYPayloadKeyData *copy = g_slice_dup (GstMIKEYPayloadKeyData, payload); |
| gst_mikey_payload_key_data_set_key (©->pt, payload->key_type, |
| payload->key_len, payload->key_data); |
| gst_mikey_payload_key_data_set_salt (©->pt, payload->salt_len, |
| payload->salt_data); |
| if (payload->kv_type == GST_MIKEY_KV_SPI) |
| gst_mikey_payload_key_data_set_spi (©->pt, payload->kv_len[0], |
| payload->kv_data[0]); |
| else if (payload->kv_type == GST_MIKEY_KV_INTERVAL) |
| gst_mikey_payload_key_data_set_interval (©->pt, payload->kv_len[0], |
| payload->kv_data[0], payload->kv_len[1], payload->kv_data[1]); |
| else { |
| FREE_MEMDUP (copy->kv_data[0]); |
| FREE_MEMDUP (copy->kv_data[1]); |
| } |
| return copy; |
| } |
| |
| /* General Extension Payload */ |
| |
| static void |
| mikey_payload_free (GstMIKEYPayload * payload) |
| { |
| g_slice_free1 (payload->len, payload); |
| } |
| |
| |
| /** |
| * gst_mikey_payload_new: |
| * @type: a #GstMIKEYPayloadType |
| * |
| * Make a new #GstMIKEYPayload with @type. |
| * |
| * Returns: (nullable): a new #GstMIKEYPayload or %NULL on failure. |
| * |
| * Since: 1.4 |
| */ |
| GstMIKEYPayload * |
| gst_mikey_payload_new (GstMIKEYPayloadType type) |
| { |
| guint len = 0; |
| GstMIKEYPayload *result; |
| GstMiniObjectCopyFunction copy; |
| GstMiniObjectDisposeFunction clear; |
| |
| switch (type) { |
| case GST_MIKEY_PT_KEMAC: |
| len = sizeof (GstMIKEYPayloadKEMAC); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_kemac_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_kemac_copy; |
| break; |
| case GST_MIKEY_PT_T: |
| len = sizeof (GstMIKEYPayloadT); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_t_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_t_copy; |
| break; |
| case GST_MIKEY_PT_PKE: |
| len = sizeof (GstMIKEYPayloadPKE); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_pke_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_pke_copy; |
| break; |
| case GST_MIKEY_PT_DH: |
| case GST_MIKEY_PT_SIGN: |
| case GST_MIKEY_PT_ID: |
| case GST_MIKEY_PT_CERT: |
| case GST_MIKEY_PT_CHASH: |
| case GST_MIKEY_PT_V: |
| case GST_MIKEY_PT_SP: |
| len = sizeof (GstMIKEYPayloadSP); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_sp_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_sp_copy; |
| break; |
| case GST_MIKEY_PT_RAND: |
| len = sizeof (GstMIKEYPayloadRAND); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_rand_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_rand_copy; |
| break; |
| case GST_MIKEY_PT_ERR: |
| break; |
| case GST_MIKEY_PT_KEY_DATA: |
| len = sizeof (GstMIKEYPayloadKeyData); |
| clear = (GstMiniObjectDisposeFunction) gst_mikey_payload_key_data_dispose; |
| copy = (GstMiniObjectCopyFunction) gst_mikey_payload_key_data_copy; |
| break; |
| case GST_MIKEY_PT_GEN_EXT: |
| case GST_MIKEY_PT_LAST: |
| break; |
| } |
| if (len == 0) |
| return NULL; |
| |
| result = g_slice_alloc0 (len); |
| gst_mini_object_init (GST_MINI_OBJECT_CAST (result), |
| 0, GST_TYPE_MIKEY_PAYLOAD, copy, clear, |
| (GstMiniObjectFreeFunction) mikey_payload_free); |
| result->type = type; |
| result->len = len; |
| |
| return result; |
| } |
| |
| static GstMIKEYMessage * |
| mikey_message_copy (GstMIKEYMessage * msg) |
| { |
| GstMIKEYMessage *copy; |
| guint i, len; |
| |
| copy = gst_mikey_message_new (); |
| |
| gst_mikey_message_set_info (copy, msg->version, msg->type, msg->V, |
| msg->prf_func, msg->CSB_id, msg->map_type); |
| |
| len = msg->map_info->len; |
| for (i = 0; i < len; i++) { |
| const GstMIKEYMapSRTP *srtp = gst_mikey_message_get_cs_srtp (msg, i); |
| gst_mikey_message_add_cs_srtp (copy, srtp->policy, srtp->ssrc, srtp->roc); |
| } |
| |
| len = msg->payloads->len; |
| for (i = 0; i < len; i++) { |
| const GstMIKEYPayload *pay = gst_mikey_message_get_payload (msg, i); |
| gst_mikey_message_add_payload (copy, gst_mikey_payload_copy (pay)); |
| } |
| return copy; |
| } |
| |
| static void |
| mikey_message_free (GstMIKEYMessage * msg) |
| { |
| FREE_ARRAY (msg->map_info); |
| FREE_ARRAY (msg->payloads); |
| |
| g_slice_free (GstMIKEYMessage, msg); |
| } |
| |
| /** |
| * gst_mikey_message_new: |
| * |
| * Make a new MIKEY message. |
| * |
| * Returns: a new #GstMIKEYMessage on success |
| * |
| * Since: 1.4 |
| */ |
| GstMIKEYMessage * |
| gst_mikey_message_new (void) |
| { |
| GstMIKEYMessage *result; |
| |
| result = g_slice_new0 (GstMIKEYMessage); |
| gst_mini_object_init (GST_MINI_OBJECT_CAST (result), |
| 0, GST_TYPE_MIKEY_MESSAGE, |
| (GstMiniObjectCopyFunction) mikey_message_copy, NULL, |
| (GstMiniObjectFreeFunction) mikey_message_free); |
| |
| INIT_ARRAY (result->map_info, GstMIKEYMapSRTP, NULL); |
| INIT_ARRAY (result->payloads, GstMIKEYPayload *, payload_destroy); |
| |
| return result; |
| } |
| |
| /** |
| * gst_mikey_message_new_from_bytes: |
| * @bytes: a #GBytes |
| * @info: a #GstMIKEYDecryptInfo |
| * @error: a #GError |
| * |
| * Make a new #GstMIKEYMessage from @bytes. |
| * |
| * Returns: a new #GstMIKEYMessage |
| * |
| * Since: 1.4 |
| */ |
| GstMIKEYMessage * |
| gst_mikey_message_new_from_bytes (GBytes * bytes, GstMIKEYDecryptInfo * info, |
| GError ** error) |
| { |
| gconstpointer data; |
| gsize size; |
| |
| g_return_val_if_fail (bytes != NULL, NULL); |
| |
| data = g_bytes_get_data (bytes, &size); |
| return gst_mikey_message_new_from_data (data, size, info, error); |
| } |
| |
| /** |
| * gst_mikey_message_set_info: |
| * @msg: a #GstMIKEYMessage |
| * @version: a version |
| * @type: a #GstMIKEYType |
| * @V: verify flag |
| * @prf_func: the #GstMIKEYPRFFunc function to use |
| * @CSB_id: the Crypto Session Bundle id |
| * @map_type: the #GstMIKEYCSIDMapType |
| * |
| * Set the information in @msg. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_set_info (GstMIKEYMessage * msg, guint8 version, |
| GstMIKEYType type, gboolean V, GstMIKEYPRFFunc prf_func, guint32 CSB_id, |
| GstMIKEYMapType map_type) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| |
| msg->version = version; |
| msg->type = type; |
| msg->V = V; |
| msg->prf_func = prf_func; |
| msg->CSB_id = CSB_id; |
| msg->map_type = map_type; |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_get_n_cs: |
| * @msg: a #GstMIKEYMessage |
| * |
| * Get the number of crypto sessions in @msg. |
| * |
| * Returns: the number of crypto sessions |
| * |
| * Since: 1.4 |
| */ |
| guint |
| gst_mikey_message_get_n_cs (const GstMIKEYMessage * msg) |
| { |
| g_return_val_if_fail (msg != NULL, 0); |
| |
| return msg->map_info->len; |
| } |
| |
| /** |
| * gst_mikey_message_get_cs_srtp: |
| * @msg: a #GstMIKEYMessage |
| * @idx: an index |
| * |
| * Get the policy information of @msg at @idx. |
| * |
| * Returns: a #GstMIKEYMapSRTP |
| * |
| * Since: 1.4 |
| */ |
| const GstMIKEYMapSRTP * |
| gst_mikey_message_get_cs_srtp (const GstMIKEYMessage * msg, guint idx) |
| { |
| g_return_val_if_fail (msg != NULL, NULL); |
| g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, NULL); |
| |
| if (msg->map_info->len <= idx) |
| return NULL; |
| |
| return &g_array_index (msg->map_info, GstMIKEYMapSRTP, idx); |
| } |
| |
| /** |
| * gst_mikey_message_insert_cs_srtp: |
| * @msg: a #GstMIKEYMessage |
| * @idx: the index to insert at |
| * @map: the map info |
| * |
| * Insert a Crypto Session map for SRTP in @msg at @idx |
| * |
| * When @idx is -1, the policy will be appended. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_insert_cs_srtp (GstMIKEYMessage * msg, gint idx, |
| const GstMIKEYMapSRTP * map) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE); |
| g_return_val_if_fail (map != NULL, FALSE); |
| g_return_val_if_fail (idx == -1 || msg->map_info->len > idx, FALSE); |
| |
| if (idx == -1) |
| g_array_append_val (msg->map_info, *map); |
| else |
| g_array_insert_val (msg->map_info, idx, *map); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_replace_cs_srtp: |
| * @msg: a #GstMIKEYMessage |
| * @idx: the index to insert at |
| * @map: the map info |
| * |
| * Replace a Crypto Session map for SRTP in @msg at @idx with @map. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_replace_cs_srtp (GstMIKEYMessage * msg, gint idx, |
| const GstMIKEYMapSRTP * map) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE); |
| g_return_val_if_fail (map != NULL, FALSE); |
| g_return_val_if_fail (msg->map_info->len > idx, FALSE); |
| |
| g_array_index (msg->map_info, GstMIKEYMapSRTP, idx) = *map; |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_remove_cs_srtp: |
| * @msg: a #GstMIKEYMessage |
| * @idx: the index to remove |
| * |
| * Remove the SRTP policy at @idx. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_remove_cs_srtp (GstMIKEYMessage * msg, gint idx) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE); |
| g_return_val_if_fail (msg->map_info->len > idx, FALSE); |
| |
| g_array_remove_index (msg->map_info, idx); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_add_cs_srtp: |
| * @msg: a #GstMIKEYMessage |
| * @policy: The security policy applied for the stream with @ssrc |
| * @ssrc: the SSRC that must be used for the stream |
| * @roc: current rollover counter |
| * |
| * Add a Crypto policy for SRTP to @msg. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_cs_srtp (GstMIKEYMessage * msg, guint8 policy, |
| guint32 ssrc, guint32 roc) |
| { |
| GstMIKEYMapSRTP val; |
| |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (msg->map_type == GST_MIKEY_MAP_TYPE_SRTP, FALSE); |
| |
| val.policy = policy; |
| val.ssrc = ssrc; |
| val.roc = roc; |
| |
| return gst_mikey_message_insert_cs_srtp (msg, -1, &val); |
| } |
| |
| /* adding/retrieving payloads */ |
| /** |
| * gst_mikey_message_get_n_payloads: |
| * @msg: a #GstMIKEYMessage |
| * |
| * Get the number of payloads in @msg. |
| * |
| * Returns: the number of payloads in @msg |
| * |
| * Since: 1.4 |
| */ |
| guint |
| gst_mikey_message_get_n_payloads (const GstMIKEYMessage * msg) |
| { |
| g_return_val_if_fail (msg != NULL, 0); |
| |
| return msg->payloads->len; |
| } |
| |
| /** |
| * gst_mikey_message_get_payload: |
| * @msg: a #GstMIKEYMessage |
| * @idx: an index |
| * |
| * Get the #GstMIKEYPayload at @idx in @msg |
| * |
| * Returns: (transfer none): the #GstMIKEYPayload at @idx. The payload |
| * remains valid for as long as it is part of @msg. |
| * |
| * Since: 1.4 |
| */ |
| const GstMIKEYPayload * |
| gst_mikey_message_get_payload (const GstMIKEYMessage * msg, guint idx) |
| { |
| g_return_val_if_fail (msg != NULL, NULL); |
| |
| if (idx >= msg->payloads->len) |
| return NULL; |
| |
| return g_array_index (msg->payloads, GstMIKEYPayload *, idx); |
| } |
| |
| /** |
| * gst_mikey_message_find_payload: |
| * @msg: a #GstMIKEYMessage |
| * @type: a #GstMIKEYPayloadType |
| * @nth: payload to find |
| * |
| * Find the @nth occurence of the payload with @type in @msg. |
| * |
| * Returns: the @nth #GstMIKEYPayload of @type. |
| * |
| * Since: 1.4 |
| */ |
| const GstMIKEYPayload * |
| gst_mikey_message_find_payload (const GstMIKEYMessage * msg, |
| GstMIKEYPayloadType type, guint idx) |
| { |
| guint i, len, count; |
| |
| count = 0; |
| len = msg->payloads->len; |
| for (i = 0; i < len; i++) { |
| GstMIKEYPayload *payload = |
| g_array_index (msg->payloads, GstMIKEYPayload *, i); |
| |
| if (payload->type == type) { |
| if (count == idx) |
| return payload; |
| |
| count++; |
| } |
| } |
| return NULL; |
| } |
| |
| /** |
| * gst_mikey_message_remove_payload: |
| * @msg: a #GstMIKEYMessage |
| * @idx: an index |
| * |
| * Remove the payload in @msg at @idx |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_remove_payload (GstMIKEYMessage * msg, guint idx) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (msg->payloads->len > idx, FALSE); |
| |
| g_array_remove_index (msg->payloads, idx); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_insert_payload: |
| * @msg: a #GstMIKEYMessage |
| * @idx: an index |
| * @payload: (transfer full): a #GstMIKEYPayload |
| * |
| * Insert the @payload at index @idx in @msg. If @idx is -1, the payload |
| * will be appended to @msg. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_insert_payload (GstMIKEYMessage * msg, guint idx, |
| GstMIKEYPayload * payload) |
| { |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (idx == -1 || msg->payloads->len > idx, FALSE); |
| |
| if (idx == -1) |
| g_array_append_val (msg->payloads, payload); |
| else |
| g_array_insert_val (msg->payloads, idx, payload); |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_add_payload: |
| * @msg: a #GstMIKEYMessage |
| * @payload: (transfer full): a #GstMIKEYPayload |
| * |
| * Add a new payload to @msg. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_payload (GstMIKEYMessage * msg, GstMIKEYPayload * payload) |
| { |
| return gst_mikey_message_insert_payload (msg, -1, payload); |
| } |
| |
| /** |
| * gst_mikey_message_replace_payload: |
| * @msg: a #GstMIKEYMessage |
| * @idx: an index |
| * @payload: (transfer full): a #GstMIKEYPayload |
| * |
| * Replace the payload at @idx in @msg with @payload. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_replace_payload (GstMIKEYMessage * msg, guint idx, |
| GstMIKEYPayload * payload) |
| { |
| GstMIKEYPayload *p; |
| |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (payload != NULL, FALSE); |
| g_return_val_if_fail (msg->payloads->len > idx, FALSE); |
| |
| p = g_array_index (msg->payloads, GstMIKEYPayload *, idx); |
| gst_mikey_payload_unref (p); |
| g_array_index (msg->payloads, GstMIKEYPayload *, idx) = payload; |
| |
| return TRUE; |
| } |
| |
| /** |
| * gst_mikey_message_add_pke: |
| * @msg: a #GstMIKEYMessage |
| * @C: envelope key cache indicator |
| * @data_len: the length of @data |
| * @data: (array length=data_len): the encrypted envelope key |
| * |
| * Add a new PKE payload to @msg with the given parameters. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_pke (GstMIKEYMessage * msg, GstMIKEYCacheType C, |
| guint16 data_len, const guint8 * data) |
| { |
| GstMIKEYPayload *p; |
| |
| g_return_val_if_fail (msg != NULL, FALSE); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_PKE); |
| if (!gst_mikey_payload_pke_set (p, C, data_len, data)) { |
| gst_mikey_payload_unref (p); |
| return FALSE; |
| } |
| |
| return gst_mikey_message_insert_payload (msg, -1, p); |
| } |
| |
| /** |
| * gst_mikey_message_add_t: |
| * @msg: a #GstMIKEYMessage |
| * @type: specifies the timestamp type used |
| * @ts_value: (array): The timestamp value of the specified @type |
| * |
| * Add a new T payload to @msg with the given parameters. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_t (GstMIKEYMessage * msg, GstMIKEYTSType type, |
| const guint8 * ts_value) |
| { |
| GstMIKEYPayload *p; |
| |
| g_return_val_if_fail (msg != NULL, FALSE); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_T); |
| if (!gst_mikey_payload_t_set (p, type, ts_value)) { |
| gst_mikey_payload_unref (p); |
| return FALSE; |
| } |
| |
| return gst_mikey_message_insert_payload (msg, -1, p); |
| } |
| |
| /** |
| * gst_mikey_message_add_t_now_ntp_utc: |
| * @msg: a #GstMIKEYMessage |
| * |
| * Add a new T payload to @msg that contains the current time |
| * in NTP-UTC format. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_t_now_ntp_utc (GstMIKEYMessage * msg) |
| { |
| gint64 now; |
| guint64 ntptime; |
| guint8 bytes[8]; |
| |
| now = g_get_real_time (); |
| |
| /* convert clock time to NTP time. upper 32 bits should contain the seconds |
| * and the lower 32 bits, the fractions of a second. */ |
| ntptime = gst_util_uint64_scale (now, (G_GINT64_CONSTANT (1) << 32), 1000000); |
| /* conversion from UNIX timestamp (seconds since 1970) to NTP (seconds |
| * since 1900). */ |
| ntptime += (G_GUINT64_CONSTANT (2208988800) << 32); |
| GST_WRITE_UINT64_BE (bytes, ntptime); |
| |
| return gst_mikey_message_add_t (msg, GST_MIKEY_TS_TYPE_NTP_UTC, bytes); |
| } |
| |
| /** |
| * gst_mikey_message_add_rand: |
| * @msg: a #GstMIKEYMessage |
| * @len: the length of @rand |
| * @rand: (array length=len): random data |
| * |
| * Add a new RAND payload to @msg with the given parameters. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_rand (GstMIKEYMessage * msg, guint8 len, |
| const guint8 * rand) |
| { |
| GstMIKEYPayload *p; |
| |
| g_return_val_if_fail (msg != NULL, FALSE); |
| g_return_val_if_fail (len != 0 && rand != NULL, FALSE); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_RAND); |
| if (!gst_mikey_payload_rand_set (p, len, rand)) { |
| gst_mikey_payload_unref (p); |
| return FALSE; |
| } |
| |
| return gst_mikey_message_insert_payload (msg, -1, p); |
| } |
| |
| /** |
| * gst_mikey_message_add_rand_len: |
| * @msg: a #GstMIKEYMessage |
| * @len: length |
| * |
| * Add a new RAND payload to @msg with @len random bytes. |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.4 |
| */ |
| gboolean |
| gst_mikey_message_add_rand_len (GstMIKEYMessage * msg, guint8 len) |
| { |
| GstMIKEYPayloadRAND *p; |
| guint i; |
| |
| p = (GstMIKEYPayloadRAND *) gst_mikey_payload_new (GST_MIKEY_PT_RAND); |
| p->len = len; |
| p->rand = g_malloc (len); |
| for (i = 0; i < len; i++) |
| p->rand[i] = g_random_int_range (0, 256); |
| |
| return gst_mikey_message_add_payload (msg, &p->pt); |
| } |
| |
| #define ENSURE_SIZE(n) \ |
| G_STMT_START { \ |
| guint offset = data - arr->data; \ |
| g_byte_array_set_size (arr, offset + n); \ |
| data = arr->data + offset; \ |
| } G_STMT_END |
| static guint |
| payloads_to_bytes (GArray * payloads, GByteArray * arr, guint8 ** ptr, |
| guint offset, GstMIKEYEncryptInfo * info, GError ** error) |
| { |
| guint i, n_payloads, len, start, size; |
| guint8 *data; |
| GstMIKEYPayload *next_payload; |
| |
| len = arr->len; |
| start = *ptr - arr->data; |
| data = *ptr + offset; |
| |
| n_payloads = payloads->len; |
| |
| for (i = 0; i < n_payloads; i++) { |
| GstMIKEYPayload *payload = g_array_index (payloads, GstMIKEYPayload *, i); |
| |
| if (i + 1 < n_payloads) |
| next_payload = g_array_index (payloads, GstMIKEYPayload *, i + 1); |
| else |
| next_payload = NULL; |
| |
| switch (payload->type) { |
| case GST_MIKEY_PT_KEMAC: |
| { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| guint enc_len; |
| guint mac_len; |
| |
| if ((mac_len = get_mac_len (p->mac_alg)) == -1) |
| break; |
| |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! Encr alg ! Encr data len ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Encr data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Mac alg ! MAC ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (4); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[1] = p->enc_alg; |
| enc_len = |
| payloads_to_bytes (p->subpayloads, arr, &data, 4, info, error); |
| /* FIXME, encrypt data here */ |
| GST_WRITE_UINT16_BE (&data[2], enc_len); |
| data += enc_len; |
| ENSURE_SIZE (5 + mac_len); |
| data[4] = p->mac_alg; |
| /* FIXME, do mac here */ |
| data += 5 + mac_len; |
| break; |
| } |
| case GST_MIKEY_PT_T: |
| { |
| GstMIKEYPayloadT *p = (GstMIKEYPayloadT *) payload; |
| guint ts_len; |
| |
| if ((ts_len = get_ts_len (p->type)) == -1) |
| break; |
| |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! TS type ! TS value ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (2 + ts_len); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[1] = p->type; |
| memcpy (&data[2], p->ts_value, ts_len); |
| data += 2 + ts_len; |
| break; |
| } |
| case GST_MIKEY_PT_PKE: |
| { |
| guint16 clen; |
| GstMIKEYPayloadPKE *p = (GstMIKEYPayloadPKE *) payload; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! C ! Data len ! Data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (3 + p->data_len); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| clen = (p->C << 14) || (p->data_len & 0x3fff); |
| GST_WRITE_UINT16_BE (&data[1], clen); |
| memcpy (&data[3], p->data, p->data_len); |
| data += 3 + p->data_len; |
| break; |
| } |
| case GST_MIKEY_PT_DH: |
| case GST_MIKEY_PT_SIGN: |
| case GST_MIKEY_PT_ID: |
| case GST_MIKEY_PT_CERT: |
| case GST_MIKEY_PT_CHASH: |
| case GST_MIKEY_PT_V: |
| break; |
| case GST_MIKEY_PT_SP: |
| { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| guint len, plen, i; |
| |
| plen = 0; |
| len = p->params->len; |
| for (i = 0; i < len; i++) { |
| GstMIKEYPayloadSPParam *param = &g_array_index (p->params, |
| GstMIKEYPayloadSPParam, i); |
| plen += 2 + param->len; |
| } |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! Policy no ! Prot type ! Policy param ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ~ length (cont) ! Policy param ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (5 + plen); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[1] = p->policy; |
| data[2] = p->proto; |
| GST_WRITE_UINT16_BE (&data[3], plen); |
| data += 5; |
| for (i = 0; i < len; i++) { |
| GstMIKEYPayloadSPParam *param = &g_array_index (p->params, |
| GstMIKEYPayloadSPParam, i); |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Type ! Length ! Value ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| data[0] = param->type; |
| data[1] = param->len; |
| memcpy (&data[2], param->val, param->len); |
| data += 2 + param->len; |
| } |
| break; |
| } |
| case GST_MIKEY_PT_RAND: |
| { |
| GstMIKEYPayloadRAND *p = (GstMIKEYPayloadRAND *) payload; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! RAND len ! RAND ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (2 + p->len); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[1] = p->len; |
| memcpy (&data[2], p->rand, p->len); |
| data += 2 + p->len; |
| break; |
| } |
| case GST_MIKEY_PT_ERR: |
| break; |
| case GST_MIKEY_PT_KEY_DATA: |
| { |
| GstMIKEYPayloadKeyData *p = (GstMIKEYPayloadKeyData *) payload; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! Type ! KV ! Key data len ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Key data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Salt len (optional) ! Salt data (optional) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! KV data (optional) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (4 + p->key_len); |
| data[0] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[1] = |
| ((p->key_type | (p->salt_len ? 1 : 0)) << 4) | (p->kv_type & 0xf); |
| GST_WRITE_UINT16_BE (&data[2], p->key_len); |
| memcpy (&data[4], p->key_data, p->key_len); |
| data += 4 + p->key_len; |
| |
| if (p->salt_len > 0) { |
| ENSURE_SIZE (2 + p->salt_len); |
| GST_WRITE_UINT16_BE (&data[0], p->salt_len); |
| memcpy (&data[2], p->salt_data, p->salt_len); |
| data += 2 + p->salt_len; |
| } |
| if (p->kv_type == GST_MIKEY_KV_SPI) { |
| /* |
| * 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! SPI Length ! SPI ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (1 + p->kv_len[0]); |
| data[0] = p->kv_len[0]; |
| memcpy (&data[1], p->kv_data[0], p->kv_len[0]); |
| data += 1 + p->kv_len[0]; |
| } else if (p->kv_type == GST_MIKEY_KV_INTERVAL) { |
| /* |
| * 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! VF Length ! Valid From ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! VT Length ! Valid To (expires) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (1 + p->kv_len[0]); |
| data[0] = p->kv_len[0]; |
| memcpy (&data[1], p->kv_data[0], p->kv_len[0]); |
| data += 1 + p->kv_len[0]; |
| ENSURE_SIZE (1 + p->kv_len[1]); |
| data[0] = p->kv_len[1]; |
| memcpy (&data[1], p->kv_data[1], p->kv_len[1]); |
| data += 1 + p->kv_len[1]; |
| } |
| break; |
| } |
| case GST_MIKEY_PT_GEN_EXT: |
| case GST_MIKEY_PT_LAST: |
| break; |
| } |
| } |
| *ptr = arr->data + start; |
| size = arr->len - len; |
| |
| return size; |
| } |
| |
| /** |
| * gst_mikey_message_to_bytes: |
| * @msg: a #GstMIKEYMessage |
| * @info: a #GstMIKEYEncryptInfo |
| * @error: a #GError |
| * |
| * Convert @msg to a #GBytes. |
| * |
| * Returns: a new #GBytes for @msg. |
| * |
| * Since: 1.4 |
| */ |
| GBytes * |
| gst_mikey_message_to_bytes (GstMIKEYMessage * msg, GstMIKEYEncryptInfo * info, |
| GError ** error) |
| { |
| GByteArray *arr = NULL; |
| guint8 *data; |
| GstMIKEYPayload *next_payload; |
| guint i, n_cs; |
| arr = g_byte_array_new (); |
| data = arr->data; |
| |
| if (msg->payloads->len == 0) |
| next_payload = NULL; |
| else |
| next_payload = g_array_index (msg->payloads, GstMIKEYPayload *, 0); |
| |
| n_cs = msg->map_info->len; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! version ! data type ! next payload !V! PRF func ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! CSB ID ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! #CS ! CS ID map type! CS ID map info ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| ENSURE_SIZE (10 + 9 * n_cs); |
| data[0] = msg->version; |
| data[1] = msg->type; |
| data[2] = next_payload ? next_payload->type : GST_MIKEY_PT_LAST; |
| data[3] = (msg->V ? 0x80 : 0x00) | (msg->prf_func & 0x7f); |
| GST_WRITE_UINT32_BE (&data[4], msg->CSB_id); |
| data[8] = n_cs; |
| data[9] = msg->map_type; |
| data += 10; |
| |
| for (i = 0; i < n_cs; i++) { |
| GstMIKEYMapSRTP *info = &g_array_index (msg->map_info, GstMIKEYMapSRTP, i); |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Policy_no_1 ! SSRC_1 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! SSRC_1 (cont) ! ROC_1 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! ROC_1 (cont) ! Policy_no_2 ! SSRC_2 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! SSRC_2 (cont) ! ROC_2 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! ROC_2 (cont) ! : |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |
| */ |
| data[0] = info->policy; |
| GST_WRITE_UINT32_BE (&data[1], info->ssrc); |
| GST_WRITE_UINT32_BE (&data[5], info->roc); |
| data += 9; |
| } |
| |
| payloads_to_bytes (msg->payloads, arr, &data, 0, info, error); |
| |
| return g_byte_array_free_to_bytes (arr); |
| } |
| |
| #undef ENSURE_SIZE |
| |
| typedef enum |
| { |
| STATE_PSK, |
| STATE_PK, |
| STATE_KEMAC, |
| STATE_OTHER |
| } ParseState; |
| |
| #define CHECK_SIZE(n) if (size < (n)) goto short_data; |
| #define ADVANCE(n) (d += (n), size -= (n)); |
| static gboolean |
| payloads_from_bytes (ParseState state, GArray * payloads, const guint8 * d, |
| gsize size, guint8 next_payload, GstMIKEYDecryptInfo * info, |
| GError ** error) |
| { |
| GstMIKEYPayload *p; |
| |
| while (next_payload != GST_MIKEY_PT_LAST) { |
| p = NULL; |
| switch (next_payload) { |
| case GST_MIKEY_PT_KEMAC: |
| { |
| guint mac_len; |
| GstMIKEYEncAlg enc_alg; |
| guint16 enc_len; |
| const guint8 *enc_data; |
| GstMIKEYMacAlg mac_alg; |
| guint8 np; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! Encr alg ! Encr data len ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Encr data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Mac alg ! MAC ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (5); |
| next_payload = d[0]; |
| enc_alg = d[1]; |
| enc_len = GST_READ_UINT16_BE (&d[2]); |
| CHECK_SIZE (5 + enc_len); |
| enc_data = &d[4]; |
| /* FIXME, decrypt data */ |
| ADVANCE (enc_len); |
| mac_alg = d[4]; |
| if ((mac_len = get_mac_len (mac_alg)) == -1) |
| goto invalid_data; |
| CHECK_SIZE (5 + mac_len); |
| /* FIXME, check MAC */ |
| ADVANCE (5 + mac_len); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); |
| gst_mikey_payload_kemac_set (p, enc_alg, mac_alg); |
| |
| if (state == STATE_PSK) |
| /* we expect Key data for Preshared key */ |
| np = GST_MIKEY_PT_KEY_DATA; |
| else if (state == STATE_PK) |
| /* we expect ID for Public key */ |
| np = GST_MIKEY_PT_ID; |
| else |
| goto invalid_data; |
| |
| payloads_from_bytes (STATE_KEMAC, |
| ((GstMIKEYPayloadKEMAC *) p)->subpayloads, enc_data, enc_len, np, |
| info, error); |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_T: |
| { |
| GstMIKEYTSType type; |
| guint ts_len; |
| const guint8 *ts_value; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! TS type ! TS value ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (2); |
| next_payload = d[0]; |
| type = d[1]; |
| if ((ts_len = get_ts_len (type)) == -1) |
| goto invalid_data; |
| CHECK_SIZE (2 + ts_len); |
| ts_value = &d[2]; |
| ADVANCE (2 + ts_len); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_T); |
| gst_mikey_payload_t_set (p, type, ts_value); |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_PKE: |
| { |
| guint8 C; |
| guint16 clen, data_len; |
| const guint8 *data; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! C ! Data len ! Data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (3); |
| next_payload = d[0]; |
| clen = GST_READ_UINT16_BE (&d[1]); |
| C = clen >> 14; |
| data_len = clen & 0x3fff; |
| CHECK_SIZE (3 + data_len); |
| data = &d[3]; |
| ADVANCE (3 + data_len); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_PKE); |
| gst_mikey_payload_pke_set (p, C, data_len, data); |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_DH: |
| case GST_MIKEY_PT_SIGN: |
| case GST_MIKEY_PT_ID: |
| case GST_MIKEY_PT_CERT: |
| case GST_MIKEY_PT_CHASH: |
| case GST_MIKEY_PT_V: |
| break; |
| case GST_MIKEY_PT_SP: |
| { |
| guint8 policy; |
| GstMIKEYSecProto proto; |
| guint16 plen; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! Policy no ! Prot type ! Policy param ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ~ length (cont) ! Policy param ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (5); |
| next_payload = d[0]; |
| policy = d[1]; |
| proto = d[2]; |
| plen = GST_READ_UINT16_BE (&d[3]); |
| ADVANCE (5); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_SP); |
| gst_mikey_payload_sp_set (p, policy, proto); |
| |
| CHECK_SIZE (plen); |
| while (plen) { |
| guint8 type, len; |
| |
| CHECK_SIZE (2); |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Type ! Length ! Value ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| type = d[0]; |
| len = d[1]; |
| CHECK_SIZE (2 + len); |
| gst_mikey_payload_sp_add_param (p, type, len, &d[2]); |
| ADVANCE (2 + len); |
| plen -= 2 + len; |
| } |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_RAND: |
| { |
| guint8 len; |
| const guint8 *rand; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next payload ! RAND len ! RAND ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (2); |
| next_payload = d[0]; |
| len = d[1]; |
| CHECK_SIZE (2 + len); |
| rand = &d[2]; |
| ADVANCE (2 + len); |
| |
| p = gst_mikey_payload_new (GST_MIKEY_PT_RAND); |
| gst_mikey_payload_rand_set (p, len, rand); |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_ERR: |
| break; |
| case GST_MIKEY_PT_KEY_DATA: |
| { |
| GstMIKEYKeyDataType key_type; |
| GstMIKEYKVType kv_type; |
| guint16 key_len, salt_len = 0; |
| const guint8 *key_data, *salt_data; |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Next Payload ! Type ! KV ! Key data len ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Key data ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Salt len (optional) ! Salt data (optional) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! KV data (optional) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (4); |
| next_payload = d[0]; |
| key_type = d[1] >> 4; |
| kv_type = d[1] & 0xf; |
| key_len = GST_READ_UINT16_BE (&d[2]); |
| CHECK_SIZE (4 + key_len); |
| key_data = &d[4]; |
| ADVANCE (4 + key_len); |
| if (key_type & 1) { |
| CHECK_SIZE (2); |
| salt_len = GST_READ_UINT16_BE (&d[0]); |
| CHECK_SIZE (2 + salt_len); |
| salt_data = &d[2]; |
| ADVANCE (2 + salt_len); |
| } |
| p = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); |
| gst_mikey_payload_key_data_set_key (p, key_type & 2, key_len, key_data); |
| if (salt_len > 0) |
| gst_mikey_payload_key_data_set_salt (p, salt_len, salt_data); |
| |
| if (kv_type == GST_MIKEY_KV_SPI) { |
| guint8 spi_len; |
| const guint8 *spi_data; |
| /* |
| * 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! SPI Length ! SPI ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (1); |
| spi_len = d[0]; |
| CHECK_SIZE (1 + spi_len); |
| spi_data = &d[1]; |
| ADVANCE (1 + spi_len); |
| |
| gst_mikey_payload_key_data_set_spi (p, spi_len, spi_data); |
| } else if (kv_type == GST_MIKEY_KV_INTERVAL) { |
| guint8 vf_len, vt_len; |
| const guint8 *vf_data, *vt_data; |
| /* |
| * 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! VF Length ! Valid From ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! VT Length ! Valid To (expires) ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (1); |
| vf_len = d[0]; |
| CHECK_SIZE (1 + vf_len); |
| vf_data = &d[1]; |
| ADVANCE (1 + vf_len); |
| CHECK_SIZE (1); |
| vt_len = d[0]; |
| CHECK_SIZE (1 + vt_len); |
| vt_data = &d[1]; |
| ADVANCE (1 + vt_len); |
| |
| gst_mikey_payload_key_data_set_interval (p, vf_len, vf_data, vt_len, |
| vt_data); |
| } else if (kv_type != GST_MIKEY_KV_NULL) |
| goto invalid_data; |
| |
| g_array_append_val (payloads, p); |
| break; |
| } |
| case GST_MIKEY_PT_GEN_EXT: |
| case GST_MIKEY_PT_LAST: |
| break; |
| } |
| } |
| return TRUE; |
| |
| /* ERRORS */ |
| short_data: |
| { |
| GST_DEBUG ("not enough data"); |
| if (p) |
| gst_mikey_payload_unref (p); |
| return FALSE; |
| } |
| invalid_data: |
| { |
| GST_DEBUG ("invalid data"); |
| if (p) |
| gst_mikey_payload_unref (p); |
| return FALSE; |
| } |
| } |
| |
| /** |
| * gst_mikey_message_new_from_data: |
| * @data: (array length=size) (element-type guint8): bytes to read |
| * @size: length of @data |
| * @info: #GstMIKEYDecryptInfo |
| * @error: a #GError |
| * |
| * Parse @size bytes from @data into a #GstMIKEYMessage. @info contains the |
| * parameters to decrypt and verify the data. |
| * |
| * Returns: a #GstMIKEYMessage on success or %NULL when parsing failed and |
| * @error will be set. |
| * |
| * Since: 1.4 |
| */ |
| GstMIKEYMessage * |
| gst_mikey_message_new_from_data (gconstpointer data, gsize size, |
| GstMIKEYDecryptInfo * info, GError ** error) |
| { |
| GstMIKEYMessage *msg; |
| guint n_cs, i; |
| const guint8 *d = data; |
| guint8 next_payload; |
| ParseState state; |
| |
| g_return_val_if_fail (data != NULL, NULL); |
| |
| msg = gst_mikey_message_new (); |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! version ! data type ! next payload !V! PRF func ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! CSB ID ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! #CS ! CS ID map type! CS ID map info ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| CHECK_SIZE (10); |
| msg->version = d[0]; |
| if (msg->version != GST_MIKEY_VERSION) |
| goto unknown_version; |
| |
| msg->type = d[1]; |
| next_payload = d[2]; |
| msg->V = d[3] & 0x80 ? TRUE : FALSE; |
| msg->prf_func = d[3] & 0x7f; |
| msg->CSB_id = GST_READ_UINT32_BE (&d[4]); |
| n_cs = d[8]; |
| msg->map_type = d[9]; |
| ADVANCE (10); |
| |
| CHECK_SIZE (n_cs * 9); |
| for (i = 0; i < n_cs; i++) { |
| GstMIKEYMapSRTP map; |
| |
| /* 1 2 3 |
| * 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 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! Policy_no_1 ! SSRC_1 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! SSRC_1 (cont) ! ROC_1 ! |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * ! ROC_1 (cont) ! Policy_no_2 ! SSRC_2 ~ |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| map.policy = d[0]; |
| map.ssrc = GST_READ_UINT32_BE (&d[1]); |
| map.roc = GST_READ_UINT32_BE (&d[5]); |
| gst_mikey_message_insert_cs_srtp (msg, -1, &map); |
| ADVANCE (9); |
| } |
| if (msg->type == GST_MIKEY_TYPE_PSK_INIT) |
| state = STATE_PSK; |
| else if (msg->type == GST_MIKEY_TYPE_PK_INIT) |
| state = STATE_PK; |
| else |
| state = STATE_OTHER; |
| |
| if (!payloads_from_bytes (state, msg->payloads, d, size, next_payload, info, |
| error)) |
| goto parse_error; |
| |
| return msg; |
| |
| /* ERRORS */ |
| short_data: |
| { |
| GST_DEBUG ("not enough data"); |
| gst_mikey_message_unref (msg); |
| return NULL; |
| } |
| unknown_version: |
| { |
| GST_DEBUG ("unknown version"); |
| gst_mikey_message_unref (msg); |
| return NULL; |
| } |
| parse_error: |
| { |
| GST_DEBUG ("failed to parse"); |
| gst_mikey_message_unref (msg); |
| return NULL; |
| } |
| } |
| |
| #define AES_128_KEY_LEN 16 |
| #define AES_256_KEY_LEN 32 |
| #define HMAC_32_KEY_LEN 4 |
| #define HMAC_80_KEY_LEN 10 |
| |
| static guint8 |
| enc_key_length_from_cipher_name (const gchar * cipher) |
| { |
| if (g_strcmp0 (cipher, "aes-128-icm") == 0) |
| return AES_128_KEY_LEN; |
| else if (g_strcmp0 (cipher, "aes-256-icm") == 0) |
| return AES_256_KEY_LEN; |
| else { |
| GST_ERROR ("encryption algorithm '%s' not supported", cipher); |
| return 0; |
| } |
| } |
| |
| static guint8 |
| auth_key_length_from_auth_name (const gchar * auth) |
| { |
| if (g_strcmp0 (auth, "hmac-sha1-32") == 0) |
| return HMAC_32_KEY_LEN; |
| else if (g_strcmp0 (auth, "hmac-sha1-80") == 0) |
| return HMAC_80_KEY_LEN; |
| else { |
| GST_ERROR ("authentication algorithm '%s' not supported", auth); |
| return 0; |
| } |
| } |
| |
| /** |
| * gst_mikey_message_new_from_caps: |
| * @caps: a #GstCaps, including SRTP parameters (srtp/srtcp cipher, authorization, key data) |
| * |
| * Makes mikey message including: |
| * - Security Policy Payload |
| * - Key Data Transport Payload |
| * - Key Data Sub-Payload |
| * |
| * Returns: (transfer full): a #GstMIKEYMessage, |
| * or %NULL if there is no srtp information in the caps. |
| * |
| * Since: 1.8 |
| */ |
| GstMIKEYMessage * |
| gst_mikey_message_new_from_caps (GstCaps * caps) |
| { |
| GstMIKEYMessage *msg; |
| GstMIKEYPayload *payload, *pkd; |
| guint8 byte; |
| GstStructure *s; |
| GstMapInfo info; |
| GstBuffer *srtpkey; |
| const GValue *val; |
| const gchar *cipher, *auth; |
| const gchar *srtpcipher, *srtpauth, *srtcpcipher, *srtcpauth; |
| |
| g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), NULL); |
| |
| s = gst_caps_get_structure (caps, 0); |
| g_return_val_if_fail (s != NULL, NULL); |
| |
| val = gst_structure_get_value (s, "srtp-key"); |
| if (!val) |
| goto no_key; |
| |
| srtpkey = gst_value_get_buffer (val); |
| if (!srtpkey || !GST_IS_BUFFER (srtpkey)) |
| goto no_key; |
| |
| srtpcipher = gst_structure_get_string (s, "srtp-cipher"); |
| srtpauth = gst_structure_get_string (s, "srtp-auth"); |
| srtcpcipher = gst_structure_get_string (s, "srtcp-cipher"); |
| srtcpauth = gst_structure_get_string (s, "srtcp-auth"); |
| |
| /* we need srtp cipher/auth or srtcp cipher/auth */ |
| if ((srtpcipher == NULL || srtpauth == NULL) |
| && (srtcpcipher == NULL || srtcpauth == NULL)) { |
| GST_WARNING ("could not find the right SRTP parameters in caps"); |
| return NULL; |
| } |
| |
| /* prefer srtp cipher over srtcp */ |
| cipher = srtpcipher; |
| if (cipher == NULL) |
| cipher = srtcpcipher; |
| |
| /* prefer srtp auth over srtcp */ |
| auth = srtpauth; |
| if (auth == NULL) |
| auth = srtcpauth; |
| |
| msg = gst_mikey_message_new (); |
| /* unencrypted MIKEY message, we send this over TLS so this is allowed */ |
| gst_mikey_message_set_info (msg, GST_MIKEY_VERSION, GST_MIKEY_TYPE_PSK_INIT, |
| FALSE, GST_MIKEY_PRF_MIKEY_1, g_random_int (), GST_MIKEY_MAP_TYPE_SRTP); |
| |
| /* timestamp is now */ |
| gst_mikey_message_add_t_now_ntp_utc (msg); |
| /* add some random data */ |
| gst_mikey_message_add_rand_len (msg, 16); |
| |
| /* the policy '0' is SRTP */ |
| payload = gst_mikey_payload_new (GST_MIKEY_PT_SP); |
| gst_mikey_payload_sp_set (payload, 0, GST_MIKEY_SEC_PROTO_SRTP); |
| |
| /* only AES-CM is supported */ |
| byte = 1; |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte); |
| /* encryption key length */ |
| byte = enc_key_length_from_cipher_name (cipher); |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1, |
| &byte); |
| /* only HMAC-SHA1 */ |
| byte = 1; |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1, |
| &byte); |
| /* authentication key length */ |
| byte = auth_key_length_from_auth_name (auth); |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1, |
| &byte); |
| /* we enable encryption on RTP and RTCP */ |
| byte = 1; |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1, |
| &byte); |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTCP_ENC, 1, |
| &byte); |
| /* we enable authentication on RTP and RTCP */ |
| gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_AUTH, 1, |
| &byte); |
| gst_mikey_message_add_payload (msg, payload); |
| |
| /* make unencrypted KEMAC */ |
| payload = gst_mikey_payload_new (GST_MIKEY_PT_KEMAC); |
| gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL); |
| /* add the key in KEMAC */ |
| pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA); |
| gst_buffer_map (srtpkey, &info, GST_MAP_READ); |
| gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size, |
| info.data); |
| gst_buffer_unmap (srtpkey, &info); |
| gst_mikey_payload_kemac_add_sub (payload, pkd); |
| gst_mikey_message_add_payload (msg, payload); |
| |
| return msg; |
| |
| no_key: |
| GST_INFO ("No srtp key"); |
| return NULL; |
| } |
| |
| #define AES_128_KEY_LEN 16 |
| #define AES_256_KEY_LEN 32 |
| #define HMAC_32_KEY_LEN 4 |
| #define HMAC_80_KEY_LEN 10 |
| |
| /** |
| * gst_mikey_message_to_caps: |
| * @msg: a #GstMIKEYMessage |
| * @caps: a #GstCaps to be filled with SRTP parameters (srtp/srtcp cipher, authorization, key data) |
| * |
| * Returns: %TRUE on success |
| * |
| * Since: 1.8.1 |
| */ |
| gboolean |
| gst_mikey_message_to_caps (const GstMIKEYMessage * msg, GstCaps * caps) |
| { |
| gboolean res = FALSE; |
| const GstMIKEYPayload *payload; |
| const gchar *srtp_cipher; |
| const gchar *srtp_auth; |
| |
| srtp_cipher = "aes-128-icm"; |
| srtp_auth = "hmac-sha1-80"; |
| |
| /* check the Security policy if any */ |
| if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) { |
| GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload; |
| guint len, i; |
| |
| if (p->proto != GST_MIKEY_SEC_PROTO_SRTP) |
| goto done; |
| |
| len = gst_mikey_payload_sp_get_n_params (payload); |
| for (i = 0; i < len; i++) { |
| const GstMIKEYPayloadSPParam *param = |
| gst_mikey_payload_sp_get_param (payload, i); |
| |
| switch (param->type) { |
| case GST_MIKEY_SP_SRTP_ENC_ALG: |
| switch (param->val[0]) { |
| case 0: |
| srtp_cipher = "null"; |
| break; |
| case 2: |
| case 1: |
| srtp_cipher = "aes-128-icm"; |
| break; |
| default: |
| break; |
| } |
| break; |
| case GST_MIKEY_SP_SRTP_ENC_KEY_LEN: |
| switch (param->val[0]) { |
| case AES_128_KEY_LEN: |
| srtp_cipher = "aes-128-icm"; |
| break; |
| case AES_256_KEY_LEN: |
| srtp_cipher = "aes-256-icm"; |
| break; |
| default: |
| break; |
| } |
| break; |
| case GST_MIKEY_SP_SRTP_AUTH_ALG: |
| switch (param->val[0]) { |
| case 0: |
| srtp_auth = "null"; |
| break; |
| case 2: |
| case 1: |
| srtp_auth = "hmac-sha1-80"; |
| break; |
| default: |
| break; |
| } |
| break; |
| case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN: |
| switch (param->val[0]) { |
| case HMAC_32_KEY_LEN: |
| srtp_auth = "hmac-sha1-32"; |
| break; |
| case HMAC_80_KEY_LEN: |
| srtp_auth = "hmac-sha1-80"; |
| break; |
| default: |
| break; |
| } |
| break; |
| case GST_MIKEY_SP_SRTP_SRTP_ENC: |
| break; |
| case GST_MIKEY_SP_SRTP_SRTCP_ENC: |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0))) |
| goto done; |
| else { |
| GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload; |
| const GstMIKEYPayload *sub; |
| GstMIKEYPayloadKeyData *pkd; |
| GstBuffer *buf; |
| |
| if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL) |
| goto done; |
| |
| if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0))) |
| goto done; |
| |
| if (sub->type != GST_MIKEY_PT_KEY_DATA) |
| goto done; |
| |
| pkd = (GstMIKEYPayloadKeyData *) sub; |
| buf = |
| gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len), |
| pkd->key_len); |
| gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL); |
| gst_buffer_unref (buf); |
| } |
| |
| gst_caps_set_simple (caps, |
| "srtp-cipher", G_TYPE_STRING, srtp_cipher, |
| "srtp-auth", G_TYPE_STRING, srtp_auth, |
| "srtcp-cipher", G_TYPE_STRING, srtp_cipher, |
| "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL); |
| |
| res = TRUE; |
| |
| done: |
| return res; |
| } |
| |
| /** |
| * gst_mikey_message_base64_encode: |
| * @msg: a #GstMIKEYMessage |
| * |
| * Returns: (transfer full): a #gchar, base64-encoded data |
| * |
| * Since: 1.8 |
| */ |
| gchar * |
| gst_mikey_message_base64_encode (GstMIKEYMessage * msg) |
| { |
| GBytes *bytes; |
| gchar *base64; |
| const guint8 *data; |
| gsize size; |
| |
| g_return_val_if_fail (msg != NULL, NULL); |
| |
| /* serialize mikey message to bytes */ |
| bytes = gst_mikey_message_to_bytes (msg, NULL, NULL); |
| |
| /* and make it into base64 */ |
| data = g_bytes_get_data (bytes, &size); |
| base64 = g_base64_encode (data, size); |
| g_bytes_unref (bytes); |
| |
| return base64; |
| } |