From 0ad968df367f5a44c568329834115018866ff8b9 Mon Sep 17 00:00:00 2001
From: fiaxh <git@lightrise.org>
Date: Fri, 30 Apr 2021 21:37:02 +0200
Subject: Use the same DTLS fingerprint in all contents. Display audio+video
 enc keys in UI if they differ.

---
 plugins/ice/src/dtls_srtp.vala            | 35 ++++++++++++++++++++-----------
 plugins/ice/src/module.vala               | 17 +++++++++++++--
 plugins/ice/src/transport_parameters.vala |  8 +++----
 3 files changed, 42 insertions(+), 18 deletions(-)

(limited to 'plugins/ice/src')

diff --git a/plugins/ice/src/dtls_srtp.vala b/plugins/ice/src/dtls_srtp.vala
index f5ef830a..0254351d 100644
--- a/plugins/ice/src/dtls_srtp.vala
+++ b/plugins/ice/src/dtls_srtp.vala
@@ -2,10 +2,10 @@ using GnuTLS;
 
 namespace Dino.Plugins.Ice.DtlsSrtp {
 
-public static Handler setup() throws GLib.Error {
-    var obj = new Handler();
-    obj.generate_credentials();
-    return obj;
+public class CredentialsCapsule {
+    public uint8[] own_fingerprint;
+    public X509.Certificate[] own_cert;
+    public X509.PrivateKey private_key;
 }
 
 public class Handler {
@@ -21,8 +21,7 @@ public class Handler {
     public uint8[] peer_fingerprint { get; set; }
     public string peer_fp_algo { get; set; }
 
-    private X509.Certificate[] own_cert;
-    private X509.PrivateKey private_key;
+    private CredentialsCapsule credentials;
     private Cond buffer_cond = Cond();
     private Mutex buffer_mutex = Mutex();
     private Gee.LinkedList<Bytes> buffer_queue = new Gee.LinkedList<Bytes>();
@@ -33,6 +32,11 @@ public class Handler {
 
     private Crypto.Srtp.Session srtp_session = new Crypto.Srtp.Session();
 
+    public Handler.with_cert(CredentialsCapsule creds) {
+        this.credentials = creds;
+        this.own_fingerprint = creds.own_fingerprint;
+    }
+
     public uint8[]? process_incoming_data(uint component_id, uint8[] data) {
         if (srtp_session.has_decrypt) {
             try {
@@ -78,10 +82,10 @@ public class Handler {
         buffer_mutex.unlock();
     }
 
-    internal void generate_credentials() throws GLib.Error {
+    internal static CredentialsCapsule generate_credentials() throws GLib.Error {
         int err = 0;
 
-        private_key = X509.PrivateKey.create();
+        X509.PrivateKey private_key = X509.PrivateKey.create();
         err = private_key.generate(PKAlgorithm.RSA, 2048);
         throw_if_error(err);
 
@@ -99,8 +103,15 @@ public class Handler {
 
         cert.sign(cert, private_key);
 
-        own_fingerprint = get_fingerprint(cert, DigestAlgorithm.SHA256);
-        own_cert = new X509.Certificate[] { (owned)cert };
+        uint8[] own_fingerprint = get_fingerprint(cert, DigestAlgorithm.SHA256);
+        X509.Certificate[] own_cert = new X509.Certificate[] { (owned)cert };
+
+        var creds = new CredentialsCapsule();
+        creds.own_fingerprint = own_fingerprint;
+        creds.own_cert = (owned) own_cert;
+        creds.private_key = (owned) private_key;
+
+        return creds;
     }
 
     public void stop_dtls_connection() {
@@ -129,7 +140,7 @@ public class Handler {
         debug("Setting up DTLS connection. We're %s", mode.to_string());
 
         CertificateCredentials cert_cred = CertificateCredentials.create();
-        int err = cert_cred.set_x509_key(own_cert, private_key);
+        int err = cert_cred.set_x509_key(credentials.own_cert, credentials.private_key);
         throw_if_error(err);
 
         Session? session = Session.create(server_or_client | InitFlags.DATAGRAM);
@@ -200,7 +211,7 @@ public class Handler {
             srtp_session.set_encryption_key(Crypto.Srtp.AES_CM_128_HMAC_SHA1_80, client_key.extract(), client_salt.extract());
             srtp_session.set_decryption_key(Crypto.Srtp.AES_CM_128_HMAC_SHA1_80, server_key.extract(), server_salt.extract());
         }
-        return new Xmpp.Xep.Jingle.ContentEncryption() { encryption_ns=Xmpp.Xep.JingleIceUdp.DTLS_NS_URI, encryption_name = "DTLS-SRTP", our_key=own_fingerprint, peer_key=peer_fingerprint };
+        return new Xmpp.Xep.Jingle.ContentEncryption() { encryption_ns=Xmpp.Xep.JingleIceUdp.DTLS_NS_URI, encryption_name = "DTLS-SRTP", our_key=credentials.own_fingerprint, peer_key=peer_fingerprint };
     }
 
     private static ssize_t pull_function(void* transport_ptr, uint8[] buffer) {
diff --git a/plugins/ice/src/module.vala b/plugins/ice/src/module.vala
index e961ffb6..2645d7dc 100644
--- a/plugins/ice/src/module.vala
+++ b/plugins/ice/src/module.vala
@@ -10,6 +10,7 @@ public class Dino.Plugins.Ice.Module : JingleIceUdp.Module {
     public Xep.ExternalServiceDiscovery.Service? turn_service = null;
 
     private weak Nice.Agent? agent;
+    private HashMap<string, DtlsSrtp.CredentialsCapsule> cerds = new HashMap<string, DtlsSrtp.CredentialsCapsule>();
 
     private Nice.Agent get_agent() {
         Nice.Agent? agent = this.agent;
@@ -29,11 +30,23 @@ public class Dino.Plugins.Ice.Module : JingleIceUdp.Module {
     }
 
     public override Jingle.TransportParameters create_transport_parameters(XmppStream stream, uint8 components, Jid local_full_jid, Jid peer_full_jid) {
-        return new TransportParameters(get_agent(), turn_service, turn_ip, components, local_full_jid, peer_full_jid);
+        DtlsSrtp.CredentialsCapsule? cred = get_create_credentials(local_full_jid, peer_full_jid);
+        return new TransportParameters(get_agent(), cred, turn_service, turn_ip, components, local_full_jid, peer_full_jid);
     }
 
     public override Jingle.TransportParameters parse_transport_parameters(XmppStream stream, uint8 components, Jid local_full_jid, Jid peer_full_jid, StanzaNode transport) throws Jingle.IqError {
-        return new TransportParameters(get_agent(), turn_service, turn_ip, components, local_full_jid, peer_full_jid, transport);
+        DtlsSrtp.CredentialsCapsule? cred = get_create_credentials(local_full_jid, peer_full_jid);
+        return new TransportParameters(get_agent(), cred, turn_service, turn_ip, components, local_full_jid, peer_full_jid, transport);
+    }
+
+    private DtlsSrtp.CredentialsCapsule? get_create_credentials(Jid local_full_jid, Jid peer_full_jid) {
+        string from_to_id = local_full_jid.to_string() + peer_full_jid.to_string();
+        try {
+            if (!cerds.has_key(from_to_id)) cerds[from_to_id] = DtlsSrtp.Handler.generate_credentials();
+        } catch (Error e) {
+            warning("Error creating dtls credentials: %s", e.message);
+        }
+        return cerds[from_to_id];
     }
 
     private void agent_unweak() {
diff --git a/plugins/ice/src/transport_parameters.vala b/plugins/ice/src/transport_parameters.vala
index 38652952..62c04906 100644
--- a/plugins/ice/src/transport_parameters.vala
+++ b/plugins/ice/src/transport_parameters.vala
@@ -60,13 +60,13 @@ public class Dino.Plugins.Ice.TransportParameters : JingleIceUdp.IceUdpTransport
         }
     }
 
-    public TransportParameters(Nice.Agent agent, Xep.ExternalServiceDiscovery.Service? turn_service, string? turn_ip, uint8 components, Jid local_full_jid, Jid peer_full_jid, StanzaNode? node = null) {
+    public TransportParameters(Nice.Agent agent, DtlsSrtp.CredentialsCapsule? credentials, Xep.ExternalServiceDiscovery.Service? turn_service, string? turn_ip, uint8 components, Jid local_full_jid, Jid peer_full_jid, StanzaNode? node = null) {
         base(components, local_full_jid, peer_full_jid, node);
         this.we_want_connection = (node == null);
         this.agent = agent;
 
         if (this.peer_fingerprint != null || !incoming) {
-            dtls_srtp_handler = setup_dtls(this);
+            dtls_srtp_handler = setup_dtls(this, credentials);
             own_fingerprint = dtls_srtp_handler.own_fingerprint;
             if (incoming) {
                 own_setup = "active";
@@ -113,9 +113,9 @@ public class Dino.Plugins.Ice.TransportParameters : JingleIceUdp.IceUdpTransport
         agent.gather_candidates(stream_id);
     }
 
-    private static DtlsSrtp.Handler setup_dtls(TransportParameters tp) {
+    private static DtlsSrtp.Handler setup_dtls(TransportParameters tp, DtlsSrtp.CredentialsCapsule credentials) {
         var weak_self = WeakRef(tp);
-        DtlsSrtp.Handler dtls_srtp = DtlsSrtp.setup();
+        DtlsSrtp.Handler dtls_srtp = new DtlsSrtp.Handler.with_cert(credentials);
         dtls_srtp.send_data.connect((data) => {
             TransportParameters self = (TransportParameters) weak_self.get();
             if (self != null) self.agent.send(self.stream_id, 1, data);
-- 
cgit v1.2.3-70-g09d2