client: parse the mikey response from the client

Parse the mikey response from the client and update the policy for
each SSRC.
This commit is contained in:
Wim Taymans 2014-04-03 12:52:51 +02:00
parent 377ca6ed0f
commit 0d22b798ae

View file

@ -42,6 +42,8 @@
#include <stdio.h>
#include <string.h>
#include <gst/sdp/gstmikey.h>
#include "rtsp-client.h"
#include "rtsp-sdp.h"
#include "rtsp-params.h"
@ -1397,13 +1399,238 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx,
return st;
}
static gboolean
mikey_apply_policy (GstCaps * caps, GstMIKEYMessage * msg, guint8 policy)
{
const gchar *srtp_cipher;
const gchar *srtp_auth;
const GstMIKEYPayload *sp;
guint i;
/* loop over Security policy until we find one containing policy */
for (i = 0;; i++) {
if ((sp = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, i)) == NULL)
break;
if (((GstMIKEYPayloadSP *) sp)->policy == policy)
break;
}
/* the default ciphers */
srtp_cipher = "aes-128-icm";
srtp_auth = "hmac-sha1-80";
/* now override the defaults with what is in the Security Policy */
if (sp != NULL) {
guint len;
/* collect all the params and go over them */
len = gst_mikey_payload_sp_get_n_params (sp);
for (i = 0; i < len; i++) {
const GstMIKEYPayloadSPParam *param =
gst_mikey_payload_sp_get_param (sp, 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_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_SRTP_ENC:
break;
case GST_MIKEY_SP_SRTP_SRTCP_ENC:
break;
default:
break;
}
}
}
/* now configure the SRTP parameters */
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);
return TRUE;
}
static gboolean
handle_mikey_data (GstRTSPClient * client, GstRTSPContext * ctx,
guint8 * data, gsize size)
{
GstMIKEYMessage *msg;
guint i, n_cs;
GstCaps *caps = NULL;
GstMIKEYPayloadKEMAC *kemac;
GstBuffer *key;
/* the MIKEY message contains a CSB or crypto session bundle. It is a
* set of Crypto Sessions protected with the same master key.
* In the context of SRTP, an RTP and its RTCP stream is part of a
* crypto session */
if ((msg = gst_mikey_message_new_from_data (data, size)) == NULL)
goto parse_failed;
/* we can only handle SRTP crypto sessions for now */
if (msg->map_type != GST_MIKEY_MAP_TYPE_SRTP)
goto invalid_map_type;
/* get the number of crypto sessions. This maps SSRC to its
* security parameters */
n_cs = gst_mikey_message_get_n_cs (msg);
if (n_cs == 0)
goto no_crypto_sessions;
/* we also need keys */
if (!(kemac = (GstMIKEYPayloadKEMAC *) gst_mikey_message_find_payload
(msg, GST_MIKEY_PT_KEMAC, 0)))
goto no_keys;
/* we don't support encrypted keys */
if (kemac->enc_alg != GST_MIKEY_ENC_NULL
|| kemac->mac_alg != GST_MIKEY_MAC_NULL)
goto unsupported_encryption;
/* FIXME get Key data sub-payload */
key =
gst_buffer_new_wrapped (g_memdup (kemac->enc_data, kemac->enc_len),
kemac->enc_len);
/* go over all crypto sessions and create the security policy for each
* SSRC */
for (i = 0; i < n_cs; i++) {
const GstMIKEYMapSRTP *map = gst_mikey_message_get_cs_srtp (msg, i);
caps = gst_caps_new_simple ("application/x-srtp",
"ssrc", G_TYPE_UINT, map->ssrc,
"roc", G_TYPE_UINT, map->roc, "srtp-key", GST_TYPE_BUFFER, key, NULL);
mikey_apply_policy (caps, msg, map->policy);
gst_rtsp_stream_update_crypto (ctx->stream, map->ssrc, caps);
gst_caps_unref (caps);
}
gst_mikey_message_free (msg);
return TRUE;
/* ERRORS */
parse_failed:
{
GST_DEBUG_OBJECT (client, "failed to parse MIKEY message");
return FALSE;
}
invalid_map_type:
{
GST_DEBUG_OBJECT (client, "invalid map type %d", msg->map_type);
goto cleanup_message;
}
no_crypto_sessions:
{
GST_DEBUG_OBJECT (client, "no crypto sessions");
goto cleanup_message;
}
no_keys:
{
GST_DEBUG_OBJECT (client, "no keys found");
goto cleanup_message;
}
unsupported_encryption:
{
GST_DEBUG_OBJECT (client, "unsupported key encryption");
goto cleanup_message;
}
{
cleanup_message:
gst_mikey_message_free (msg);
return FALSE;
}
}
#define IS_STRIP_CHAR(c) (g_ascii_isspace ((guchar)(c)) || ((c) == '\"'))
static void
strip_chars (gchar * str)
{
gchar *s;
gsize len;
len = strlen (str);
while (len--) {
if (!IS_STRIP_CHAR (str[len]))
break;
str[len] = '\0';
}
for (s = str; *s && IS_STRIP_CHAR (*s); s++);
memmove (str, s, len + 1);
}
/**
* KeyMgmt = "KeyMgmt" ":" key-mgmt-spec 0*("," key-mgmt-spec)
* key-mgmt-spec = "prot" "=" KMPID ";" ["uri" "=" %x22 URI %x22 ";"]
*/
static gboolean
handle_keymgmt (GstRTSPClient * client, GstRTSPContext * ctx, gchar * keymgmt)
{
gchar **specs;
gint i, j;
specs = g_strsplit (keymgmt, ",", 0);
for (i = 0; specs[i]; i++) {
gchar **split;
split = g_strsplit (specs[i], ";", 0);
for (j = 0; split[j]; j++) {
g_strstrip (split[j]);
if (g_str_has_prefix (split[j], "prot=")) {
g_strstrip (split[j] + 5);
if (!g_str_equal (split[j] + 5, "mikey"))
break;
GST_DEBUG ("found mikey");
} else if (g_str_has_prefix (split[j], "uri=")) {
strip_chars (split[j] + 4);
GST_DEBUG ("found uri '%s'", split[j] + 4);
} else if (g_str_has_prefix (split[j], "data=")) {
guchar *data;
gsize size;
strip_chars (split[j] + 5);
GST_DEBUG ("found data '%s'", split[j] + 5);
data = g_base64_decode_inplace (split[j] + 5, &size);
handle_mikey_data (client, ctx, data, size);
}
}
}
return TRUE;
}
static gboolean
handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
{
GstRTSPClientPrivate *priv = client->priv;
GstRTSPResult res;
GstRTSPUrl *uri;
gchar *transport;
gchar *transport, *keymgmt;
GstRTSPTransport *ct, *st;
GstRTSPStatusCode code;
GstRTSPSession *session;
@ -1520,6 +1747,13 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
if (!klass->configure_client_transport (client, ctx, ct))
goto unsupported_client_transport;
/* parse the keymgmt */
if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
&keymgmt, 0) == GST_RTSP_OK) {
if (!handle_keymgmt (client, ctx, keymgmt))
goto keymgmt_error;
}
/* set in the session media transport */
trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
@ -1643,6 +1877,12 @@ unsupported_client_transport:
send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
goto cleanup_transport;
}
keymgmt_error:
{
GST_ERROR ("client %p: keymgmt error", client);
send_generic_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, ctx);
goto cleanup_transport;
}
{
cleanup_transport:
gst_rtsp_transport_free (ct);