mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
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:
parent
377ca6ed0f
commit
0d22b798ae
1 changed files with 241 additions and 1 deletions
|
@ -42,6 +42,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gst/sdp/gstmikey.h>
|
||||||
|
|
||||||
#include "rtsp-client.h"
|
#include "rtsp-client.h"
|
||||||
#include "rtsp-sdp.h"
|
#include "rtsp-sdp.h"
|
||||||
#include "rtsp-params.h"
|
#include "rtsp-params.h"
|
||||||
|
@ -1397,13 +1399,238 @@ make_server_transport (GstRTSPClient * client, GstRTSPContext * ctx,
|
||||||
return st;
|
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
|
static gboolean
|
||||||
handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
{
|
{
|
||||||
GstRTSPClientPrivate *priv = client->priv;
|
GstRTSPClientPrivate *priv = client->priv;
|
||||||
GstRTSPResult res;
|
GstRTSPResult res;
|
||||||
GstRTSPUrl *uri;
|
GstRTSPUrl *uri;
|
||||||
gchar *transport;
|
gchar *transport, *keymgmt;
|
||||||
GstRTSPTransport *ct, *st;
|
GstRTSPTransport *ct, *st;
|
||||||
GstRTSPStatusCode code;
|
GstRTSPStatusCode code;
|
||||||
GstRTSPSession *session;
|
GstRTSPSession *session;
|
||||||
|
@ -1520,6 +1747,13 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
|
||||||
if (!klass->configure_client_transport (client, ctx, ct))
|
if (!klass->configure_client_transport (client, ctx, ct))
|
||||||
goto unsupported_client_transport;
|
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 */
|
/* set in the session media transport */
|
||||||
trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
|
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);
|
send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, ctx);
|
||||||
goto cleanup_transport;
|
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:
|
cleanup_transport:
|
||||||
gst_rtsp_transport_free (ct);
|
gst_rtsp_transport_free (ct);
|
||||||
|
|
Loading…
Reference in a new issue