From: Wim Taymans Date: Thu, 3 Apr 2014 10:52:51 +0000 (+0200) Subject: client: parse the mikey response from the client X-Git-Tag: 1.19.3~495^2~832 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0d22b798ae02dd09e9d1d679d2c74b606140b5d3;p=platform%2Fupstream%2Fgstreamer.git client: parse the mikey response from the client Parse the mikey response from the client and update the policy for each SSRC. --- diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0bee547..12589be 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -42,6 +42,8 @@ #include #include +#include + #include "rtsp-client.h" #include "rtsp-sdp.h" #include "rtsp-params.h" @@ -1398,12 +1400,237 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx, } 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);