Merge branch '2038-key-manager-methods' into '1802-sync-via-removable-storage'

Key manager changes to support transport key agreement client

See merge request briar/briar!1473
This commit is contained in:
akwizgran
2021-06-15 10:55:31 +00:00
3 changed files with 99 additions and 31 deletions

View File

@@ -22,8 +22,24 @@ public interface KeyManager {
/**
* Derives and stores a set of rotation mode transport keys for
* communicating with the given contact over each transport and returns the
* key set IDs.
* communicating with the given contact over the given transport and
* returns the key set ID, or null if the transport is not supported.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.
*
* @param alice True if the local party is Alice
* @param active Whether the derived keys can be used for outgoing streams
*/
@Nullable
KeySetId addRotationKeys(Transaction txn, ContactId c, TransportId t,
SecretKey rootKey, long timestamp, boolean alice,
boolean active) throws DbException;
/**
* Derives and stores a set of rotation mode transport keys for
* communicating with the given contact over each supported transport and
* returns the key set IDs.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.

View File

@@ -51,7 +51,6 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
private final DatabaseComponent db;
private final Executor dbExecutor;
private final PluginConfig pluginConfig;
private final TransportKeyManagerFactory transportKeyManagerFactory;
private final TransportCrypto transportCrypto;
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
@@ -61,34 +60,39 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
KeyManagerImpl(DatabaseComponent db,
@DatabaseExecutor Executor dbExecutor,
PluginConfig pluginConfig,
TransportKeyManagerFactory transportKeyManagerFactory,
TransportCrypto transportCrypto) {
TransportCrypto transportCrypto,
TransportKeyManagerFactory transportKeyManagerFactory) {
this.db = db;
this.dbExecutor = dbExecutor;
this.pluginConfig = pluginConfig;
this.transportKeyManagerFactory = transportKeyManagerFactory;
this.transportCrypto = transportCrypto;
managers = new ConcurrentHashMap<>();
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
TransportKeyManager m = transportKeyManagerFactory.
createTransportKeyManager(f.getId(), f.getMaxLatency());
managers.put(f.getId(), m);
}
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories()) {
TransportKeyManager m = transportKeyManagerFactory.
createTransportKeyManager(f.getId(), f.getMaxLatency());
managers.put(f.getId(), m);
}
}
@Override
public void startService() throws ServiceException {
if (used.getAndSet(true)) throw new IllegalStateException();
Map<TransportId, Integer> transports = new HashMap<>();
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories())
transports.put(f.getId(), f.getMaxLatency());
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories())
transports.put(f.getId(), f.getMaxLatency());
try {
db.transaction(false, txn -> {
for (Entry<TransportId, Integer> e : transports.entrySet())
db.addTransport(txn, e.getKey(), e.getValue());
for (Entry<TransportId, Integer> e : transports.entrySet()) {
TransportKeyManager m = transportKeyManagerFactory
.createTransportKeyManager(e.getKey(),
e.getValue());
managers.put(e.getKey(), m);
m.start(txn);
for (SimplexPluginFactory f :
pluginConfig.getSimplexFactories()) {
db.addTransport(txn, f.getId(), f.getMaxLatency());
managers.get(f.getId()).start(txn);
}
for (DuplexPluginFactory f :
pluginConfig.getDuplexFactories()) {
db.addTransport(txn, f.getId(), f.getMaxLatency());
managers.get(f.getId()).start(txn);
}
});
} catch (DbException e) {
@@ -101,9 +105,17 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
}
@Override
public Map<TransportId, KeySetId> addRotationKeys(
Transaction txn, ContactId c, SecretKey rootKey, long timestamp,
boolean alice, boolean active) throws DbException {
public KeySetId addRotationKeys(Transaction txn, ContactId c,
TransportId t, SecretKey rootKey, long timestamp, boolean alice,
boolean active) throws DbException {
return withManager(t, m ->
m.addRotationKeys(txn, c, rootKey, timestamp, alice, active));
}
@Override
public Map<TransportId, KeySetId> addRotationKeys(Transaction txn,
ContactId c, SecretKey rootKey, long timestamp, boolean alice,
boolean active) throws DbException {
Map<TransportId, KeySetId> ids = new HashMap<>();
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
TransportId t = e.getKey();
@@ -137,7 +149,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
PendingContactId p, PublicKey theirPublicKey, KeyPair ourKeyPair)
throws DbException, GeneralSecurityException {
SecretKey staticMasterKey = transportCrypto
.deriveStaticMasterKey(theirPublicKey, ourKeyPair);
.deriveStaticMasterKey(theirPublicKey, ourKeyPair);
SecretKey rootKey =
transportCrypto.deriveHandshakeRootKey(staticMasterKey, true);
boolean alice = transportCrypto.isAlice(theirPublicKey, ourKeyPair);

View File

@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Map;
import java.util.Random;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
@@ -71,8 +72,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
private final SecretKey rootKey = getSecretKey();
private final Random random = new Random();
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
pluginConfig, transportKeyManagerFactory, transportCrypto);
private KeyManagerImpl keyManager;
@Before
public void testStartService() throws Exception {
@@ -83,18 +83,25 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
singletonList(pluginFactory);
int maxLatency = 1337;
context.checking(new DbExpectations() {{
oneOf(pluginConfig).getSimplexFactories();
context.checking(new Expectations() {{
allowing(pluginConfig).getSimplexFactories();
will(returnValue(factories));
oneOf(pluginFactory).getId();
allowing(pluginFactory).getId();
will(returnValue(transportId));
oneOf(pluginFactory).getMaxLatency();
allowing(pluginFactory).getMaxLatency();
will(returnValue(maxLatency));
oneOf(db).addTransport(txn, transportId, maxLatency);
allowing(pluginConfig).getDuplexFactories();
will(returnValue(emptyList()));
oneOf(transportKeyManagerFactory)
.createTransportKeyManager(transportId, maxLatency);
will(returnValue(transportKeyManager));
oneOf(pluginConfig).getDuplexFactories();
}});
keyManager = new KeyManagerImpl(db, executor,
pluginConfig, transportCrypto, transportKeyManagerFactory);
context.checking(new DbExpectations() {{
oneOf(db).addTransport(txn, transportId, maxLatency);
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(transportKeyManager).start(txn);
}});
@@ -235,4 +242,37 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
keyManager.eventOccurred(event);
executor.runUntilIdle();
}
@Test
public void testAddMultipleRotationKeySets() throws Exception {
long timestamp = System.currentTimeMillis();
boolean alice = random.nextBoolean();
boolean active = random.nextBoolean();
context.checking(new Expectations() {{
oneOf(transportKeyManager).addRotationKeys(txn, contactId,
rootKey, timestamp, alice, active);
will(returnValue(keySetId));
}});
assertEquals(singletonMap(transportId, keySetId),
keyManager.addRotationKeys(txn, contactId, rootKey, timestamp,
alice, active));
}
@Test
public void testAddSingleRotationKeySet() throws Exception {
long timestamp = System.currentTimeMillis();
boolean alice = random.nextBoolean();
boolean active = random.nextBoolean();
context.checking(new Expectations() {{
oneOf(transportKeyManager).addRotationKeys(txn, contactId,
rootKey, timestamp, alice, active);
will(returnValue(keySetId));
}});
assertEquals(keySetId, keyManager.addRotationKeys(txn, contactId,
transportId, rootKey, timestamp, alice, active));
}
}