From e899668213ee8f7d3566bb5754b488d8633c30c7 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 10 Sep 2019 20:56:00 +0200 Subject: Add JET support --- .../xep/0391_jingle_encrypted_transports.vala | 142 +++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 xmpp-vala/src/module/xep/0391_jingle_encrypted_transports.vala (limited to 'xmpp-vala/src/module/xep/0391_jingle_encrypted_transports.vala') diff --git a/xmpp-vala/src/module/xep/0391_jingle_encrypted_transports.vala b/xmpp-vala/src/module/xep/0391_jingle_encrypted_transports.vala new file mode 100644 index 00000000..e2b1326b --- /dev/null +++ b/xmpp-vala/src/module/xep/0391_jingle_encrypted_transports.vala @@ -0,0 +1,142 @@ +using Gee; +using Xmpp.Xep.Jingle; + +namespace Xmpp.Xep.Jet { +public const string NS_URI = "urn:xmpp:jingle:jet:0"; + +public class Module : XmppStreamModule, SecurityPrecondition { + public static Xmpp.ModuleIdentity IDENTITY = new Xmpp.ModuleIdentity(NS_URI, "0391_jet"); + private HashMap envelop_encodings = new HashMap(); + private HashMap ciphers = new HashMap(); + + public override void attach(XmppStream stream) { + stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI); + stream.get_module(Jingle.Module.IDENTITY).register_security_precondition(this); + } + + public override void detach(XmppStream stream) { + } + + public bool is_available(XmppStream stream, Jid full_jid) { + bool? has_feature = stream.get_flag(ServiceDiscovery.Flag.IDENTITY).has_entity_feature(full_jid, NS_URI); + return has_feature != null && (!)has_feature; + } + + public void register_envelop_encoding(EnvelopEncoding encoding) { + envelop_encodings[encoding.get_type_uri()] = encoding; + } + + public void register_cipher(Cipher cipher) { + ciphers[cipher.get_cipher_uri()] = cipher; + } + + public string security_ns_uri() { + return NS_URI; + } + + public Jingle.SecurityParameters? create_security_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, Object options) throws Jingle.Error requires (options is Options) { + Options jet_options = (Options) options; + string cipher = jet_options.cipher_uri; + string type = jet_options.type_uri; + if (!envelop_encodings.has_key(type) || !ciphers.has_key(cipher)) { + throw new IqError.NOT_IMPLEMENTED("JET cipher or type unknown"); + } + EnvelopEncoding encoding = envelop_encodings[type]; + return new SecurityParameters(ciphers[cipher], encoding, ciphers[cipher].generate_random_secret(), jet_options); + } + + public Jingle.SecurityParameters? parse_security_parameters(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, StanzaNode security) throws IqError { + string? cipher = security.get_attribute("cipher"); + string? type = security.get_attribute("type"); + if (cipher == null || type == null) { + throw new IqError.BAD_REQUEST("No cipher or type specified for JET"); + } + if (!envelop_encodings.has_key(type) || !ciphers.has_key(cipher)) { + throw new IqError.NOT_IMPLEMENTED("JET cipher or type unknown"); + } + EnvelopEncoding encoding = envelop_encodings[type]; + TransportSecret secret = encoding.decode_envolop(stream, local_full_jid, peer_full_jid, security); + return new SecurityParameters(ciphers[cipher], encoding, secret); + } + + public override string get_ns() { return NS_URI; } + public override string get_id() { return IDENTITY.id; } +} + +public class Options : Object { + public string type_uri { get; private set; } + public string cipher_uri { get; private set; } + + public Options(string type_uri, string cipher_uri) { + this.type_uri = type_uri; + this.cipher_uri = cipher_uri; + } +} + +public class SecurityParameters : Jingle.SecurityParameters, Object { + public Cipher cipher { get; private set; } + public EnvelopEncoding encoding { get; private set; } + public TransportSecret secret { get; private set; } + public Options? options { get; private set; } + + public SecurityParameters(Cipher cipher, EnvelopEncoding encoding, TransportSecret secret, Options? options = null) { + this.cipher = cipher; + this.encoding = encoding; + this.secret = secret; + this.options = options; + } + + public string security_ns_uri() { + return NS_URI; + } + public IOStream wrap_stream(IOStream stream) { + debug("Wrapping stream into encrypted stream for %s/%s", encoding.get_type_uri(), cipher.get_cipher_uri()); + return new EncryptedStream(cipher, secret, stream); + } + public StanzaNode to_security_stanza_node(XmppStream stream, Jid local_full_jid, Jid peer_full_jid) { + StanzaNode security = new StanzaNode.build("security", NS_URI) + .add_self_xmlns() + .put_attribute("cipher", cipher.get_cipher_uri()) + .put_attribute("type", encoding.get_type_uri()); + encoding.encode_envelop(stream, local_full_jid, peer_full_jid, this, security); + return security; + } +} + +public interface Cipher : Object { + public abstract string get_cipher_uri(); + public abstract TransportSecret generate_random_secret(); + public abstract InputStream wrap_input_stream(InputStream input, TransportSecret secret); + public abstract OutputStream wrap_output_stream(OutputStream output, TransportSecret secret); +} + +private class EncryptedStream : IOStream { + private IOStream stream; + private InputStream input; + private OutputStream output; + public override InputStream input_stream { get { return input; } } + public override OutputStream output_stream { get { return output; } } + + public EncryptedStream(Cipher cipher, TransportSecret secret, IOStream stream) { + this.stream = stream; + input = cipher.wrap_input_stream(stream.input_stream, secret); + output = cipher.wrap_output_stream(stream.output_stream, secret); + } +} + +public class TransportSecret { + public uint8[] transport_key { get; private set; } + public uint8[] initialization_vector { get; private set; } + public TransportSecret(uint8[] transport_key, uint8[] initialization_vector) { + this.transport_key = transport_key; + this.initialization_vector = initialization_vector; + } +} + +public interface EnvelopEncoding : Object { + public abstract string get_type_uri(); + public abstract TransportSecret decode_envolop(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, StanzaNode security) throws IqError; + public abstract void encode_envelop(XmppStream stream, Jid local_full_jid, Jid peer_full_jid, SecurityParameters security_params, StanzaNode security); +} + +} \ No newline at end of file -- cgit v1.2.3-70-g09d2