mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
Implement BQP transport descriptors
This commit is contained in:
@@ -14,6 +14,9 @@ import org.briarproject.api.TransportId;
|
|||||||
import org.briarproject.android.api.AndroidExecutor;
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -67,6 +70,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private static final String DISCOVERY_FINISHED =
|
private static final String DISCOVERY_FINISHED =
|
||||||
"android.bluetooth.adapter.action.DISCOVERY_FINISHED";
|
"android.bluetooth.adapter.action.DISCOVERY_FINISHED";
|
||||||
|
|
||||||
|
private static final String PROP_ADDRESS = "address";
|
||||||
|
private static final String PROP_UUID = "uuid";
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
@@ -161,7 +167,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
if (!StringUtils.isNullOrEmpty(address)) {
|
if (!StringUtils.isNullOrEmpty(address)) {
|
||||||
// Advertise the Bluetooth address to contacts
|
// Advertise the Bluetooth address to contacts
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("address", address);
|
p.put(PROP_ADDRESS, address);
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
}
|
}
|
||||||
// Bind a server socket to accept connections from contacts
|
// Bind a server socket to accept connections from contacts
|
||||||
@@ -187,13 +193,13 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private UUID getUuid() {
|
private UUID getUuid() {
|
||||||
String uuid = callback.getLocalProperties().get("uuid");
|
String uuid = callback.getLocalProperties().get(PROP_UUID);
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
byte[] random = new byte[UUID_BYTES];
|
byte[] random = new byte[UUID_BYTES];
|
||||||
secureRandom.nextBytes(random);
|
secureRandom.nextBytes(random);
|
||||||
uuid = UUID.nameUUIDFromBytes(random).toString();
|
uuid = UUID.nameUUIDFromBytes(random).toString();
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("uuid", uuid);
|
p.put(PROP_UUID, uuid);
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
}
|
}
|
||||||
return UUID.fromString(uuid);
|
return UUID.fromString(uuid);
|
||||||
@@ -264,9 +270,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
final ContactId c = e.getKey();
|
final ContactId c = e.getKey();
|
||||||
if (connected.contains(c)) continue;
|
if (connected.contains(c)) continue;
|
||||||
final String address = e.getValue().get("address");
|
final String address = e.getValue().get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
final String uuid = e.getValue().get("uuid");
|
final String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -325,9 +331,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
if (p == null) return null;
|
if (p == null) return null;
|
||||||
String address = p.get("address");
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get("uuid");
|
String uuid = p.get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
if (s == null) return null;
|
if (s == null) return null;
|
||||||
@@ -417,6 +423,48 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsKeyAgreement() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAgreementListener createKeyAgreementListener(
|
||||||
|
byte[] localCommitment) {
|
||||||
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
|
UUID uuid = UUID.nameUUIDFromBytes(localCommitment);
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
|
// Bind a server socket for receiving invitation connections
|
||||||
|
BluetoothServerSocket ss;
|
||||||
|
try {
|
||||||
|
ss = InsecureBluetooth.listen(adapter, "RFCOMM", uuid);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TransportProperties p = new TransportProperties();
|
||||||
|
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
||||||
|
if (!StringUtils.isNullOrEmpty(address))
|
||||||
|
p.put(PROP_ADDRESS, address);
|
||||||
|
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||||
|
return new BluetoothKeyAgreementListener(d, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
|
||||||
|
if (!isRunning()) return null;
|
||||||
|
if (!ID.equals(d.getIdentifier())) return null;
|
||||||
|
TransportProperties p = d.getProperties();
|
||||||
|
if (p == null) return null;
|
||||||
|
String address = p.get(PROP_ADDRESS);
|
||||||
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
|
UUID uuid = UUID.nameUUIDFromBytes(remoteCommitment);
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||||
|
BluetoothSocket s = connect(address, uuid.toString());
|
||||||
|
if (s == null) return null;
|
||||||
|
return new DroidtoothTransportConnection(this, s);
|
||||||
|
}
|
||||||
|
|
||||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -545,4 +593,39 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
|
private final BluetoothServerSocket ss;
|
||||||
|
|
||||||
|
public BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
||||||
|
BluetoothServerSocket ss) {
|
||||||
|
super(descriptor);
|
||||||
|
this.ss = ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callable<KeyAgreementConnection> listen() {
|
||||||
|
return new Callable<KeyAgreementConnection>() {
|
||||||
|
@Override
|
||||||
|
public KeyAgreementConnection call() throws IOException {
|
||||||
|
BluetoothSocket s = ss.accept();
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(ID.getString() + ": Incoming connection");
|
||||||
|
return new KeyAgreementConnection(
|
||||||
|
new DroidtoothTransportConnection(
|
||||||
|
DroidtoothPlugin.this, s), ID);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
ss.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import org.briarproject.api.crypto.PseudoRandom;
|
|||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -570,6 +572,20 @@ class TorPlugin implements DuplexPlugin, EventHandler,
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsKeyAgreement() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAgreementListener createKeyAgreementListener(
|
||||||
|
byte[] commitment) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
public void circuitStatus(String status, String id, String path) {
|
public void circuitStatus(String status, String id, String path) {
|
||||||
if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
|
if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
|
||||||
|
public class KeyAgreementConnection {
|
||||||
|
private final DuplexTransportConnection conn;
|
||||||
|
private final TransportId id;
|
||||||
|
|
||||||
|
public KeyAgreementConnection(DuplexTransportConnection conn,
|
||||||
|
TransportId id) {
|
||||||
|
this.conn = conn;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection getConnection() {
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportId getTransportId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An class for managing a particular key agreement listener.
|
||||||
|
*/
|
||||||
|
public abstract class KeyAgreementListener {
|
||||||
|
|
||||||
|
private final TransportDescriptor descriptor;
|
||||||
|
|
||||||
|
public KeyAgreementListener(TransportDescriptor descriptor) {
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the descriptor that a remote peer can use to connect to this
|
||||||
|
* listener.
|
||||||
|
*/
|
||||||
|
public TransportDescriptor getDescriptor() {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts listening for incoming connections, and returns a Callable that
|
||||||
|
* will return a KeyAgreementConnection when an incoming connection is
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
public abstract Callable<KeyAgreementConnection> listen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the underlying server socket.
|
||||||
|
*/
|
||||||
|
public abstract void close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.properties.TransportProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how to connect to a device over a short-range transport.
|
||||||
|
*/
|
||||||
|
public class TransportDescriptor {
|
||||||
|
|
||||||
|
private final TransportId id;
|
||||||
|
private final TransportProperties properties;
|
||||||
|
|
||||||
|
public TransportDescriptor(TransportId id, TransportProperties properties) {
|
||||||
|
this.id = id;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the transport identifier. */
|
||||||
|
public TransportId getIdentifier() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the transport properties. */
|
||||||
|
public TransportProperties getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,4 +19,7 @@ public interface PluginManager {
|
|||||||
|
|
||||||
/** Returns any running duplex plugins that support invitations. */
|
/** Returns any running duplex plugins that support invitations. */
|
||||||
Collection<DuplexPlugin> getInvitationPlugins();
|
Collection<DuplexPlugin> getInvitationPlugins();
|
||||||
|
|
||||||
|
/** Returns any running duplex plugins that support key agreement. */
|
||||||
|
Collection<DuplexPlugin> getKeyAgreementPlugins();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.api.plugins.duplex;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
|
|
||||||
/** An interface for transport plugins that support duplex communication. */
|
/** An interface for transport plugins that support duplex communication. */
|
||||||
@@ -24,4 +26,19 @@ public interface DuplexPlugin extends Plugin {
|
|||||||
*/
|
*/
|
||||||
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice);
|
long timeout, boolean alice);
|
||||||
|
|
||||||
|
/** Returns true if the plugin supports short-range key agreement. */
|
||||||
|
boolean supportsKeyAgreement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a listener that can be used to perform key agreement.
|
||||||
|
*/
|
||||||
|
KeyAgreementListener createKeyAgreementListener(byte[] localCommitment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to connect to the remote peer specified in the given descriptor.
|
||||||
|
* Returns null if no connection can be established within the given time.
|
||||||
|
*/
|
||||||
|
DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] remoteCommitment, TransportDescriptor d, long timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,13 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
return Collections.unmodifiableList(supported);
|
return Collections.unmodifiableList(supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<DuplexPlugin> getKeyAgreementPlugins() {
|
||||||
|
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||||
|
for (DuplexPlugin d : duplexPlugins)
|
||||||
|
if (d.supportsKeyAgreement()) supported.add(d);
|
||||||
|
return Collections.unmodifiableList(supported);
|
||||||
|
}
|
||||||
|
|
||||||
private class SimplexPluginStarter implements Runnable {
|
private class SimplexPluginStarter implements Runnable {
|
||||||
|
|
||||||
private final SimplexPluginFactory factory;
|
private final SimplexPluginFactory factory;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -250,6 +252,20 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsKeyAgreement() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAgreementListener createKeyAgreementListener(
|
||||||
|
byte[] commitment) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
protected Collection<InetAddress> getLocalIpAddresses() {
|
protected Collection<InetAddress> getLocalIpAddresses() {
|
||||||
List<NetworkInterface> ifaces;
|
List<NetworkInterface> ifaces;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package org.briarproject.plugins.bluetooth;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -50,6 +53,9 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
Logger.getLogger(BluetoothPlugin.class.getName());
|
Logger.getLogger(BluetoothPlugin.class.getName());
|
||||||
private static final int UUID_BYTES = 16;
|
private static final int UUID_BYTES = 16;
|
||||||
|
|
||||||
|
private static final String PROP_ADDRESS = "address";
|
||||||
|
private static final String PROP_UUID = "uuid";
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
@@ -106,7 +112,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
if (!running) return;
|
if (!running) return;
|
||||||
// Advertise the Bluetooth address to contacts
|
// Advertise the Bluetooth address to contacts
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("address", localDevice.getBluetoothAddress());
|
p.put(PROP_ADDRESS, localDevice.getBluetoothAddress());
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
// Bind a server socket to accept connections from contacts
|
// Bind a server socket to accept connections from contacts
|
||||||
String url = makeUrl("localhost", getUuid());
|
String url = makeUrl("localhost", getUuid());
|
||||||
@@ -135,13 +141,13 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getUuid() {
|
private String getUuid() {
|
||||||
String uuid = callback.getLocalProperties().get("uuid");
|
String uuid = callback.getLocalProperties().get(PROP_UUID);
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
byte[] random = new byte[UUID_BYTES];
|
byte[] random = new byte[UUID_BYTES];
|
||||||
secureRandom.nextBytes(random);
|
secureRandom.nextBytes(random);
|
||||||
uuid = UUID.nameUUIDFromBytes(random).toString();
|
uuid = UUID.nameUUIDFromBytes(random).toString();
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("uuid", uuid);
|
p.put(PROP_UUID, uuid);
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
}
|
}
|
||||||
return uuid;
|
return uuid;
|
||||||
@@ -203,9 +209,9 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
final ContactId c = e.getKey();
|
final ContactId c = e.getKey();
|
||||||
if (connected.contains(c)) continue;
|
if (connected.contains(c)) continue;
|
||||||
final String address = e.getValue().get("address");
|
final String address = e.getValue().get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
final String uuid = e.getValue().get("uuid");
|
final String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -236,9 +242,9 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
if (p == null) return null;
|
if (p == null) return null;
|
||||||
String address = p.get("address");
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get("uuid");
|
String uuid = p.get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||||
String url = makeUrl(address, uuid);
|
String url = makeUrl(address, uuid);
|
||||||
StreamConnection s = connect(url);
|
StreamConnection s = connect(url);
|
||||||
@@ -335,6 +341,54 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsKeyAgreement() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAgreementListener createKeyAgreementListener(
|
||||||
|
byte[] localCommitment) {
|
||||||
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
|
String uuid = UUID.nameUUIDFromBytes(localCommitment).toString();
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
|
String url = makeUrl("localhost", uuid);
|
||||||
|
// Make the device discoverable if possible
|
||||||
|
makeDeviceDiscoverable();
|
||||||
|
// Bind a server socket for receiving invitation connections
|
||||||
|
final StreamConnectionNotifier ss;
|
||||||
|
try {
|
||||||
|
ss = (StreamConnectionNotifier) Connector.open(url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!running) {
|
||||||
|
tryToClose(ss);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TransportProperties p = new TransportProperties();
|
||||||
|
p.put(PROP_ADDRESS, localDevice.getBluetoothAddress());
|
||||||
|
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||||
|
return new BluetoothKeyAgreementListener(d, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
|
||||||
|
if (!isRunning()) return null;
|
||||||
|
if (!ID.equals(d.getIdentifier())) return null;
|
||||||
|
TransportProperties p = d.getProperties();
|
||||||
|
if (p == null) return null;
|
||||||
|
String address = p.get(PROP_ADDRESS);
|
||||||
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
|
String uuid = UUID.nameUUIDFromBytes(remoteCommitment).toString();
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||||
|
String url = makeUrl(address, uuid);
|
||||||
|
StreamConnection s = connect(url);
|
||||||
|
if (s == null) return null;
|
||||||
|
return new BluetoothTransportConnection(this, s);
|
||||||
|
}
|
||||||
|
|
||||||
private void makeDeviceDiscoverable() {
|
private void makeDeviceDiscoverable() {
|
||||||
// Try to make the device discoverable (requires root on Linux)
|
// Try to make the device discoverable (requires root on Linux)
|
||||||
try {
|
try {
|
||||||
@@ -414,4 +468,39 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
|
private final StreamConnectionNotifier ss;
|
||||||
|
|
||||||
|
public BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
||||||
|
StreamConnectionNotifier ss) {
|
||||||
|
super(descriptor);
|
||||||
|
this.ss = ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callable<KeyAgreementConnection> listen() {
|
||||||
|
return new Callable<KeyAgreementConnection>() {
|
||||||
|
@Override
|
||||||
|
public KeyAgreementConnection call() throws Exception {
|
||||||
|
StreamConnection s = ss.acceptAndOpen();
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(ID.getString() + ": Incoming connection");
|
||||||
|
return new KeyAgreementConnection(
|
||||||
|
new BluetoothTransportConnection(
|
||||||
|
BluetoothPlugin.this, s), ID);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
ss.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.briarproject.plugins.modem;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||||
import org.briarproject.api.plugins.TransportConnectionReader;
|
import org.briarproject.api.plugins.TransportConnectionReader;
|
||||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
@@ -158,6 +160,20 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsKeyAgreement() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyAgreementListener createKeyAgreementListener(
|
||||||
|
byte[] commitment) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
public void incomingCallConnected() {
|
public void incomingCallConnected() {
|
||||||
LOG.info("Incoming call connected");
|
LOG.info("Incoming call connected");
|
||||||
callback.incomingConnectionCreated(new ModemTransportConnection());
|
callback.incomingConnectionCreated(new ModemTransportConnection());
|
||||||
|
|||||||
Reference in New Issue
Block a user