From 7439e5579f54f1158af76423124eb62ac29cf948 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Wed, 5 Jun 2019 11:23:56 +0100
Subject: [PATCH] Let plugins know if we're Alice or Bob.

---
 .../api/plugin/duplex/DuplexPlugin.java       |  2 +-
 .../plugin/bluetooth/BluetoothPlugin.java     |  2 +-
 .../bramble/plugin/tcp/TcpPlugin.java         |  2 +-
 .../bramble/plugin/tor/TorPlugin.java         |  2 +-
 .../rendezvous/RendezvousPollerImpl.java      | 62 ++++++++++++-------
 .../rendezvous/RendezvousPollerImplTest.java  | 20 +++++-
 .../bramble/plugin/modem/ModemPlugin.java     |  2 +-
 7 files changed, 60 insertions(+), 32 deletions(-)

diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java
index bc19732431..ce0e5787e7 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/duplex/DuplexPlugin.java
@@ -57,5 +57,5 @@ public interface DuplexPlugin extends Plugin {
 	 */
 	@Nullable
 	RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
-			ConnectionHandler incoming);
+			boolean alice, ConnectionHandler incoming);
 }
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
index 58d06c52e1..0dec35bc5d 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
@@ -399,7 +399,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
 
 	@Override
 	public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
-			ConnectionHandler incoming) {
+			boolean alice, ConnectionHandler incoming) {
 		throw new UnsupportedOperationException();
 	}
 
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
index 3529c58385..4ca15d0b98 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java
@@ -310,7 +310,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 
 	@Override
 	public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
-			ConnectionHandler incoming) {
+			boolean alice, ConnectionHandler incoming) {
 		throw new UnsupportedOperationException();
 	}
 
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java
index ec523b9503..76d8f6109a 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java
@@ -614,7 +614,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	@Override
 	public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
-			ConnectionHandler incoming) {
+			boolean alice, ConnectionHandler incoming) {
 		throw new UnsupportedOperationException();
 	}
 
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java
index 421d216fff..b7d355548a 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java
@@ -83,7 +83,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 	private final Executor worker;
 	// The following fields are only accessed on the worker
 	private final Map<TransportId, PluginState> pluginStates = new HashMap<>();
-	private final Map<PendingContactId, SecretKey> rendezvousKeys =
+	private final Map<PendingContactId, CryptoState> cryptoStates =
 			new HashMap<>();
 	@Nullable
 	private KeyPair handshakeKeyPair = null;
@@ -153,12 +153,15 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 					.deriveStaticMasterKey(p.getPublicKey(), handshakeKeyPair);
 			SecretKey rendezvousKey = rendezvousCrypto
 					.deriveRendezvousKey(staticMasterKey);
-			requireNull(rendezvousKeys.put(p.getId(), rendezvousKey));
-			for (PluginState state : pluginStates.values()) {
+			boolean alice = transportCrypto
+					.isAlice(p.getPublicKey(), handshakeKeyPair);
+			CryptoState cs = new CryptoState(rendezvousKey, alice);
+			requireNull(cryptoStates.put(p.getId(), cs));
+			for (PluginState ps : pluginStates.values()) {
 				RendezvousEndpoint endpoint =
-						createEndpoint(state.plugin, p.getId(), rendezvousKey);
+						createEndpoint(ps.plugin, p.getId(), cs);
 				if (endpoint != null)
-					requireNull(state.endpoints.put(p.getId(), endpoint));
+					requireNull(ps.endpoints.put(p.getId(), endpoint));
 			}
 		} catch (DbException | GeneralSecurityException e) {
 			logException(LOG, WARNING, e);
@@ -179,9 +182,9 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 	// Worker
 	private boolean removePendingContact(PendingContactId p) {
 		// We can come here twice if a pending contact fails and is then removed
-		if (rendezvousKeys.remove(p) == null) return false;
-		for (PluginState state : pluginStates.values()) {
-			RendezvousEndpoint endpoint = state.endpoints.remove(p);
+		if (cryptoStates.remove(p) == null) return false;
+		for (PluginState ps : pluginStates.values()) {
+			RendezvousEndpoint endpoint = ps.endpoints.remove(p);
 			if (endpoint != null) tryToClose(endpoint, LOG, INFO);
 		}
 		return true;
@@ -189,33 +192,33 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 
 	@Nullable
 	private RendezvousEndpoint createEndpoint(DuplexPlugin plugin,
-			PendingContactId p, SecretKey rendezvousKey) {
+			PendingContactId p, CryptoState cs) {
 		TransportId t = plugin.getId();
 		KeyMaterialSource k =
-				rendezvousCrypto.createKeyMaterialSource(rendezvousKey, t);
+				rendezvousCrypto.createKeyMaterialSource(cs.rendezvousKey, t);
 		Handler h = new Handler(p, t, true);
-		return plugin.createRendezvousEndpoint(k, h);
+		return plugin.createRendezvousEndpoint(k, cs.alice, h);
 	}
 
 	@Scheduler
 	private void poll() {
 		worker.execute(() -> {
-			for (PluginState state : pluginStates.values()) poll(state);
+			for (PluginState ps : pluginStates.values()) poll(ps);
 		});
 	}
 
 	// Worker
-	private void poll(PluginState state) {
+	private void poll(PluginState ps) {
 		List<Pair<TransportProperties, ConnectionHandler>> properties =
 				new ArrayList<>();
 		for (Entry<PendingContactId, RendezvousEndpoint> e :
-				state.endpoints.entrySet()) {
+				ps.endpoints.entrySet()) {
 			TransportProperties props =
 					e.getValue().getRemoteTransportProperties();
-			Handler h = new Handler(e.getKey(), state.plugin.getId(), false);
+			Handler h = new Handler(e.getKey(), ps.plugin.getId(), false);
 			properties.add(new Pair<>(props, h));
 		}
-		state.plugin.poll(properties);
+		ps.plugin.poll(properties);
 	}
 
 	@Override
@@ -249,13 +252,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 
 	// Worker
 	private void poll(PendingContactId p) {
-		for (PluginState state : pluginStates.values()) {
-			RendezvousEndpoint endpoint = state.endpoints.get(p);
+		for (PluginState ps : pluginStates.values()) {
+			RendezvousEndpoint endpoint = ps.endpoints.get(p);
 			if (endpoint != null) {
 				TransportProperties props =
 						endpoint.getRemoteTransportProperties();
-				Handler h = new Handler(p, state.plugin.getId(), false);
-				state.plugin.poll(singletonList(new Pair<>(props, h)));
+				Handler h = new Handler(p, ps.plugin.getId(), false);
+				ps.plugin.poll(singletonList(new Pair<>(props, h)));
 			}
 		}
 	}
@@ -279,7 +282,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 	private void addTransport(DuplexPlugin plugin) {
 		TransportId t = plugin.getId();
 		Map<PendingContactId, RendezvousEndpoint> endpoints = new HashMap<>();
-		for (Entry<PendingContactId, SecretKey> e : rendezvousKeys.entrySet()) {
+		for (Entry<PendingContactId, CryptoState> e : cryptoStates.entrySet()) {
 			RendezvousEndpoint endpoint =
 					createEndpoint(plugin, e.getKey(), e.getValue());
 			if (endpoint != null) endpoints.put(e.getKey(), endpoint);
@@ -294,9 +297,9 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 
 	// Worker
 	private void removeTransport(TransportId t) {
-		PluginState state = pluginStates.remove(t);
-		if (state != null) {
-			for (RendezvousEndpoint endpoint : state.endpoints.values()) {
+		PluginState ps = pluginStates.remove(t);
+		if (ps != null) {
+			for (RendezvousEndpoint endpoint : ps.endpoints.values()) {
 				tryToClose(endpoint, LOG, INFO);
 			}
 		}
@@ -314,6 +317,17 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
 		}
 	}
 
+	private static class CryptoState {
+
+		private final SecretKey rendezvousKey;
+		private final boolean alice;
+
+		private CryptoState(SecretKey rendezvousKey, boolean alice) {
+			this.rendezvousKey = rendezvousKey;
+			this.alice = alice;
+		}
+	}
+
 	private class Handler implements ConnectionHandler {
 
 		private final PendingContactId pendingContactId;
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java
index d88ff47d39..92af0f780e 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java
@@ -30,6 +30,7 @@ import org.jmock.Expectations;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Random;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.atomic.AtomicReference;
@@ -79,6 +80,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 	private final TransportId transportId = getTransportId();
 	private final TransportProperties transportProperties =
 			getTransportProperties(3);
+	private final boolean alice = new Random().nextBoolean();
 
 	private RendezvousPollerImpl rendezvousPoller;
 
@@ -122,6 +124,9 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 			will(returnValue(staticMasterKey));
 			oneOf(rendezvousCrypto).deriveRendezvousKey(staticMasterKey);
 			will(returnValue(rendezvousKey));
+			oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
+					handshakeKeyPair);
+			will(returnValue(alice));
 		}});
 
 		rendezvousPoller.startService();
@@ -182,11 +187,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 			will(returnValue(staticMasterKey));
 			oneOf(rendezvousCrypto).deriveRendezvousKey(staticMasterKey);
 			will(returnValue(rendezvousKey));
+			oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
+					handshakeKeyPair);
+			will(returnValue(alice));
 			oneOf(rendezvousCrypto).createKeyMaterialSource(rendezvousKey,
 					transportId);
 			will(returnValue(keyMaterialSource));
 			oneOf(plugin).createRendezvousEndpoint(with(keyMaterialSource),
-					with(any(ConnectionHandler.class)));
+					with(alice), with(any(ConnectionHandler.class)));
 			will(returnValue(rendezvousEndpoint));
 			// Poll newly added pending contact
 			oneOf(rendezvousEndpoint).getRemoteTransportProperties();
@@ -250,11 +258,14 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 			will(returnValue(staticMasterKey));
 			oneOf(rendezvousCrypto).deriveRendezvousKey(staticMasterKey);
 			will(returnValue(rendezvousKey));
+			oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
+					handshakeKeyPair);
+			will(returnValue(alice));
 			oneOf(rendezvousCrypto).createKeyMaterialSource(rendezvousKey,
 					transportId);
 			will(returnValue(keyMaterialSource));
 			oneOf(plugin).createRendezvousEndpoint(with(keyMaterialSource),
-					with(any(ConnectionHandler.class)));
+					with(alice), with(any(ConnectionHandler.class)));
 			will(returnValue(rendezvousEndpoint));
 			// Poll newly added pending contact
 			oneOf(rendezvousEndpoint).getRemoteTransportProperties();
@@ -305,6 +316,9 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 			will(returnValue(staticMasterKey));
 			oneOf(rendezvousCrypto).deriveRendezvousKey(staticMasterKey);
 			will(returnValue(rendezvousKey));
+			oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
+					handshakeKeyPair);
+			will(returnValue(alice));
 		}});
 
 		rendezvousPoller.eventOccurred(
@@ -323,7 +337,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
 					transportId);
 			will(returnValue(keyMaterialSource));
 			oneOf(plugin).createRendezvousEndpoint(with(keyMaterialSource),
-					with(any(ConnectionHandler.class)));
+					with(alice), with(any(ConnectionHandler.class)));
 			will(returnValue(rendezvousEndpoint));
 		}});
 
diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java
index 21bef9284a..16a0d0f31f 100644
--- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java
+++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java
@@ -193,7 +193,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 
 	@Override
 	public RendezvousEndpoint createRendezvousEndpoint(KeyMaterialSource k,
-			ConnectionHandler incoming) {
+			boolean alice, ConnectionHandler incoming) {
 		throw new UnsupportedOperationException();
 	}
 
-- 
GitLab