From ec35f95e13f4f2f756c81a35ded0980245acc5f4 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Wed, 24 Mar 2021 14:12:42 +0100 Subject: Add initial support for DTLS-SRTP --- .../src/module/xep/0166_jingle/reason_element.vala | 1 + xmpp-vala/src/module/xep/0166_jingle/session.vala | 38 ++++++++++++---------- .../xep/0167_jingle_rtp/content_parameters.vala | 5 ++- .../xep/0167_jingle_rtp/jingle_rtp_module.vala | 2 +- .../xep/0167_jingle_rtp/session_info_type.vala | 2 +- .../0176_jingle_ice_udp/jingle_ice_udp_module.vala | 1 + .../0176_jingle_ice_udp/transport_parameters.vala | 27 +++++++++++++++ 7 files changed, 56 insertions(+), 20 deletions(-) (limited to 'xmpp-vala/src/module/xep') diff --git a/xmpp-vala/src/module/xep/0166_jingle/reason_element.vala b/xmpp-vala/src/module/xep/0166_jingle/reason_element.vala index 1cbdf936..4d47d4cd 100644 --- a/xmpp-vala/src/module/xep/0166_jingle/reason_element.vala +++ b/xmpp-vala/src/module/xep/0166_jingle/reason_element.vala @@ -24,6 +24,7 @@ namespace Xmpp.Xep.Jingle.ReasonElement { BUSY, CANCEL, DECLINE, + GONE, SUCCESS }; } \ No newline at end of file diff --git a/xmpp-vala/src/module/xep/0166_jingle/session.vala b/xmpp-vala/src/module/xep/0166_jingle/session.vala index e9ad9169..2d359f01 100644 --- a/xmpp-vala/src/module/xep/0166_jingle/session.vala +++ b/xmpp-vala/src/module/xep/0166_jingle/session.vala @@ -24,9 +24,10 @@ public class Xmpp.Xep.Jingle.Session : Object { public Jid peer_full_jid { get; private set; } public bool we_initiated { get; private set; } - public HashMap contents = new HashMap(); + public HashMap contents_map = new HashMap(); + public Gee.List contents = new ArrayList(); // Keep the order contents - public SecurityParameters? security { get { return contents.values.to_array()[0].security_params; } } + public SecurityParameters? security { get { return contents.to_array()[0].security_params; } } public Session.initiate_sent(XmppStream stream, string sid, Jid local_full_jid, Jid peer_full_jid) { this.stream = stream; @@ -94,7 +95,7 @@ public class Xmpp.Xep.Jingle.Session : Object { } else if (action.has_prefix("transport-")) { ContentNode content_node = get_single_content_node(jingle); - if (!contents.has_key(content_node.name)) { + if (!contents_map.has_key(content_node.name)) { throw new IqError.BAD_REQUEST("unknown content"); } @@ -102,7 +103,7 @@ public class Xmpp.Xep.Jingle.Session : Object { throw new IqError.BAD_REQUEST("missing transport node"); } - Content content = contents[content_node.name]; + Content content = contents_map[content_node.name]; if (content_node.creator != content.content_creator) { throw new IqError.BAD_REQUEST("unknown content; creator"); @@ -128,11 +129,11 @@ public class Xmpp.Xep.Jingle.Session : Object { } else if (action == "description-info") { ContentNode content_node = get_single_content_node(jingle); - if (!contents.has_key(content_node.name)) { + if (!contents_map.has_key(content_node.name)) { throw new IqError.BAD_REQUEST("unknown content"); } - Content content = contents[content_node.name]; + Content content = contents_map[content_node.name]; if (content_node.creator != content.content_creator) { throw new IqError.BAD_REQUEST("unknown content; creator"); @@ -149,7 +150,8 @@ public class Xmpp.Xep.Jingle.Session : Object { } internal void insert_content(Content content) { - this.contents[content.content_name] = content; + this.contents_map[content.content_name] = content; + this.contents.add(content); content.set_session(this); } @@ -209,7 +211,8 @@ public class Xmpp.Xep.Jingle.Session : Object { public async void add_content(Content content) { content.session = this; - this.contents[content.content_name] = content; + this.contents_map[content.content_name] = content; + contents.add(content); StanzaNode content_add_node = new StanzaNode.build("jingle", NS_URI) .add_self_xmlns() @@ -228,9 +231,9 @@ public class Xmpp.Xep.Jingle.Session : Object { private void handle_content_accept(ContentNode content_node) throws IqError { if (content_node.description == null || content_node.transport == null) throw new IqError.BAD_REQUEST("missing description or transport node"); - if (!contents.has_key(content_node.name)) throw new IqError.BAD_REQUEST("unknown content"); + if (!contents_map.has_key(content_node.name)) throw new IqError.BAD_REQUEST("unknown content"); - Content content = contents[content_node.name]; + Content content = contents_map[content_node.name]; if (content_node.creator != content.content_creator) warning("Counterpart accepts content with an unexpected `creator`"); if (content_node.senders != content.senders) warning("Counterpart accepts content with an unexpected `senders`"); @@ -242,7 +245,7 @@ public class Xmpp.Xep.Jingle.Session : Object { private void handle_content_modify(XmppStream stream, StanzaNode jingle_node, Iq.Stanza iq) throws IqError { ContentNode content_node = get_single_content_node(jingle_node); - Content? content = contents[content_node.name]; + Content? content = contents_map[content_node.name]; if (content == null) throw new IqError.BAD_REQUEST("no such content"); if (content_node.creator != content.content_creator) throw new IqError.BAD_REQUEST("mismatching creator"); @@ -301,7 +304,7 @@ public class Xmpp.Xep.Jingle.Session : Object { } } - foreach (Content content in contents.values) { + foreach (Content content in contents) { content.terminate(false, reason_name, reason_text); } @@ -336,7 +339,7 @@ public class Xmpp.Xep.Jingle.Session : Object { .add_self_xmlns() .put_attribute("action", "session-accept") .put_attribute("sid", sid); - foreach (Content content in contents.values) { + foreach (Content content in contents) { StanzaNode content_node = new StanzaNode.build("content", NS_URI) .put_attribute("creator", "initiator") .put_attribute("name", content.content_name) @@ -345,12 +348,13 @@ public class Xmpp.Xep.Jingle.Session : Object { .put_node(content.transport_params.to_transport_stanza_node()); jingle.put_node(content_node); } + Iq.Stanza iq = new Iq.Stanza.set(jingle) { to=peer_full_jid }; stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq); - foreach (Content content in contents.values) { - content.on_accept(stream); + foreach (Content content2 in contents) { + content2.on_accept(stream); } state = State.ACTIVE; @@ -359,7 +363,7 @@ public class Xmpp.Xep.Jingle.Session : Object { internal void accept_content(Content content) { if (state == State.INITIATE_RECEIVED) { bool all_accepted = true; - foreach (Content c in contents.values) { + foreach (Content c in contents) { if (c.state != Content.State.WANTS_TO_BE_ACCEPTED) { all_accepted = false; } @@ -413,7 +417,7 @@ public class Xmpp.Xep.Jingle.Session : Object { } else { reason_str = "local session-terminate"; } - foreach (Content content in contents.values) { + foreach (Content content in contents) { content.terminate(true, reason_name, reason_text); } } diff --git a/xmpp-vala/src/module/xep/0167_jingle_rtp/content_parameters.vala b/xmpp-vala/src/module/xep/0167_jingle_rtp/content_parameters.vala index cca03543..32ea1df6 100644 --- a/xmpp-vala/src/module/xep/0167_jingle_rtp/content_parameters.vala +++ b/xmpp-vala/src/module/xep/0167_jingle_rtp/content_parameters.vala @@ -34,7 +34,7 @@ public class Xmpp.Xep.JingleRtp.Parameters : Jingle.ContentParameters, Object { this.parent = parent; this.media = media; this.ssrc = ssrc; - this.rtcp_mux = rtcp_mux; + this.rtcp_mux = true; this.bandwidth = bandwidth; this.bandwidth_type = bandwidth_type; this.encryption_required = encryption_required; @@ -175,6 +175,9 @@ public class Xmpp.Xep.JingleRtp.Parameters : Jingle.ContentParameters, Object { ret.put_node(new StanzaNode.build("encryption", NS_URI) .put_node(local_crypto.to_xml())); } + if (rtcp_mux) { + ret.put_node(new StanzaNode.build("rtcp-mux", NS_URI)); + } return ret; } } \ No newline at end of file diff --git a/xmpp-vala/src/module/xep/0167_jingle_rtp/jingle_rtp_module.vala b/xmpp-vala/src/module/xep/0167_jingle_rtp/jingle_rtp_module.vala index 23aee6c9..3a9ea09f 100644 --- a/xmpp-vala/src/module/xep/0167_jingle_rtp/jingle_rtp_module.vala +++ b/xmpp-vala/src/module/xep/0167_jingle_rtp/jingle_rtp_module.vala @@ -84,7 +84,7 @@ public abstract class Module : XmppStreamModule { Jid receiver_full_jid = session.peer_full_jid; Jingle.Content? content = null; - foreach (Jingle.Content c in session.contents.values) { + foreach (Jingle.Content c in session.contents) { Parameters? parameters = c.content_params as Parameters; if (parameters == null) continue; diff --git a/xmpp-vala/src/module/xep/0167_jingle_rtp/session_info_type.vala b/xmpp-vala/src/module/xep/0167_jingle_rtp/session_info_type.vala index d36255f0..32cd9016 100644 --- a/xmpp-vala/src/module/xep/0167_jingle_rtp/session_info_type.vala +++ b/xmpp-vala/src/module/xep/0167_jingle_rtp/session_info_type.vala @@ -50,7 +50,7 @@ namespace Xmpp.Xep.JingleRtp { public void send_mute(Jingle.Session session, bool mute, string media) { string node_name = mute ? "mute" : "unmute"; - foreach (Jingle.Content content in session.contents.values) { + foreach (Jingle.Content content in session.contents) { Parameters? parameters = content.content_params as Parameters; if (parameters != null && parameters.media == media) { StanzaNode session_info_content = new StanzaNode.build(node_name, NS_URI).add_self_xmlns().put_attribute("name", content.content_name); diff --git a/xmpp-vala/src/module/xep/0176_jingle_ice_udp/jingle_ice_udp_module.vala b/xmpp-vala/src/module/xep/0176_jingle_ice_udp/jingle_ice_udp_module.vala index 9ed494ff..4b7c7a36 100644 --- a/xmpp-vala/src/module/xep/0176_jingle_ice_udp/jingle_ice_udp_module.vala +++ b/xmpp-vala/src/module/xep/0176_jingle_ice_udp/jingle_ice_udp_module.vala @@ -12,6 +12,7 @@ public abstract class Module : XmppStreamModule, Jingle.Transport { public override void attach(XmppStream stream) { stream.get_module(Jingle.Module.IDENTITY).register_transport(this); stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI); + stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, "urn:xmpp:jingle:apps:dtls:0"); } public override void detach(XmppStream stream) { stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI); diff --git a/xmpp-vala/src/module/xep/0176_jingle_ice_udp/transport_parameters.vala b/xmpp-vala/src/module/xep/0176_jingle_ice_udp/transport_parameters.vala index 8b8aa07d..3c69d0af 100644 --- a/xmpp-vala/src/module/xep/0176_jingle_ice_udp/transport_parameters.vala +++ b/xmpp-vala/src/module/xep/0176_jingle_ice_udp/transport_parameters.vala @@ -13,6 +13,9 @@ public abstract class Xmpp.Xep.JingleIceUdp.IceUdpTransportParameters : Jingle.T public ConcurrentList unsent_local_candidates = new ConcurrentList(Candidate.equals_func); public Gee.List remote_candidates = new ArrayList(Candidate.equals_func); + public string? own_fingerprint = null; + public string? peer_fingerprint = null; + public Jid local_full_jid { get; private set; } public Jid peer_full_jid { get; private set; } private uint8 components_; @@ -34,6 +37,11 @@ public abstract class Xmpp.Xep.JingleIceUdp.IceUdpTransportParameters : Jingle.T foreach (StanzaNode candidateNode in node.get_subnodes("candidate")) { remote_candidates.add(Candidate.parse(candidateNode)); } + + StanzaNode? fingerprint_node = node.get_subnode("fingerprint", "urn:xmpp:jingle:apps:dtls:0"); + if (fingerprint_node != null) { + peer_fingerprint = fingerprint_node.get_deep_string_content(); + } } } @@ -57,6 +65,20 @@ public abstract class Xmpp.Xep.JingleIceUdp.IceUdpTransportParameters : Jingle.T .add_self_xmlns() .put_attribute("ufrag", local_ufrag) .put_attribute("pwd", local_pwd); + + if (own_fingerprint != null) { + var fingerprint_node = new StanzaNode.build("fingerprint", "urn:xmpp:jingle:apps:dtls:0") + .add_self_xmlns() + .put_attribute("hash", "sha-256") + .put_node(new StanzaNode.text(own_fingerprint)); + if (incoming) { + fingerprint_node.put_attribute("setup", "active"); + } else { + fingerprint_node.put_attribute("setup", "actpass"); + } + node.put_node(fingerprint_node); + } + foreach (Candidate candidate in unsent_local_candidates) { node.put_node(candidate.to_xml()); } @@ -72,6 +94,11 @@ public abstract class Xmpp.Xep.JingleIceUdp.IceUdpTransportParameters : Jingle.T foreach (StanzaNode candidateNode in node.get_subnodes("candidate")) { remote_candidates.add(Candidate.parse(candidateNode)); } + + StanzaNode? fingerprint_node = node.get_subnode("fingerprint", "urn:xmpp:jingle:apps:dtls:0"); + if (fingerprint_node != null) { + peer_fingerprint = fingerprint_node.get_deep_string_content(); + } } public virtual void handle_transport_info(StanzaNode node) throws Jingle.IqError { -- cgit v1.2.3-70-g09d2