From f42fc5213e1ac83a714580df8fb06eba26fc28cd Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 9 May 2019 12:10:07 +0100 Subject: [PATCH] Add key manager method for contacts with handshake keys. --- .../bramble/api/transport/KeyManager.java | 21 +++++-- .../bramble/transport/KeyManagerImpl.java | 12 ++++ .../transport/TransportKeyManager.java | 3 + .../transport/TransportKeyManagerImpl.java | 20 +++++++ .../bramble/transport/KeyManagerImplTest.java | 18 +++++- .../TransportKeyManagerImplTest.java | 58 ++++++++++++++++--- 6 files changed, 118 insertions(+), 14 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java index 827c94fb7..8a6e914b1 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/KeyManager.java @@ -18,19 +18,32 @@ public interface KeyManager { /** * Informs the key manager that a new contact has been added. Derives and - * stores a set of transport keys for communicating with the contact over - * each transport and returns the key set IDs. + * stores a set of rotation mode transport keys for communicating with the + * contact over each transport and returns the key set IDs. *

* {@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 + * @param alice True if the local party is Alice + * @param active Whether the derived keys can be used for outgoing streams */ Map addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; + /** + * Informs the key manager that a new contact has been added. Derives and + * stores a set of handshake mode transport keys for communicating with the + * contact over each transport and returns the key set IDs. + *

+ * {@link StreamContext StreamContexts} for the contact can be created + * after this method has returned. + * + * @param alice True if the local party is ALice + */ + Map addContact(Transaction txn, ContactId c, + SecretKey rootKey, boolean alice) throws DbException; + /** * Marks the given transport keys as usable for outgoing streams. */ diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java index 18d1b63ff..499e9dc22 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java @@ -100,6 +100,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { return ids; } + @Override + public Map addContact(Transaction txn, + ContactId c, SecretKey rootKey, boolean alice) throws DbException { + Map ids = new HashMap<>(); + for (Entry e : managers.entrySet()) { + TransportId t = e.getKey(); + TransportKeyManager m = e.getValue(); + ids.put(t, m.addContact(txn, c, rootKey, alice)); + } + return ids; + } + @Override public void activateKeys(Transaction txn, Map keys) throws DbException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java index fa3f54e11..d7758043f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManager.java @@ -18,6 +18,9 @@ interface TransportKeyManager { KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, long timestamp, boolean alice, boolean active) throws DbException; + KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, + boolean alice) throws DbException; + void activateKeys(Transaction txn, KeySetId k) throws DbException; void removeContact(ContactId c); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index 3e070e28f..86ce89e10 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -213,6 +213,26 @@ class TransportKeyManagerImpl implements TransportKeyManager { } } + @Override + public KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey, + boolean alice) throws DbException { + lock.lock(); + try { + // Work out what time period we're in + long timePeriod = clock.currentTimeMillis() / timePeriodLength; + // Derive the transport keys + TransportKeys k = transportCrypto.deriveHandshakeKeys(transportId, + rootKey, timePeriod, alice); + // Write the keys back to the DB + KeySetId keySetId = db.addTransportKeys(txn, c, k); + // Initialise mutable state for the contact + addKeys(keySetId, c, null, new MutableTransportKeys(k)); + return keySetId; + } finally { + lock.unlock(); + } + } + @Override public void activateKeys(Transaction txn, KeySetId k) throws DbException { lock.lock(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java index e81264c3f..5f25ff777 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/KeyManagerImplTest.java @@ -83,7 +83,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase { } @Test - public void testAddContact() throws Exception { + public void testAddContactWithRotationModeKeys() throws Exception { SecretKey secretKey = getSecretKey(); long timestamp = System.currentTimeMillis(); boolean alice = random.nextBoolean(); @@ -100,6 +100,22 @@ public class KeyManagerImplTest extends BrambleMockTestCase { assertEquals(singletonMap(transportId, keySetId), ids); } + @Test + public void testAddContactWithHandshakeModeKeys() throws Exception { + SecretKey secretKey = getSecretKey(); + boolean alice = random.nextBoolean(); + + context.checking(new Expectations() {{ + oneOf(transportKeyManager).addContact(txn, contactId, secretKey, + alice); + will(returnValue(keySetId)); + }}); + + Map ids = keyManager.addContact(txn, contactId, + secretKey, alice); + assertEquals(singletonMap(transportId, keySetId), ids); + } + @Test public void testGetStreamContextForUnknownTransport() throws Exception { assertNull(keyManager.getStreamContext(contactId, unknownTransportId)); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java index 1aeabdc44..188be95f2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/transport/TransportKeyManagerImplTest.java @@ -70,14 +70,15 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { @Test public void testKeysAreUpdatedAtStartup() throws Exception { - TransportKeys shouldUpdate = createTransportKeys(900, 0, true); - TransportKeys shouldNotUpdate = createTransportKeys(1000, 0, true); + boolean active = random.nextBoolean(); + TransportKeys shouldUpdate = createTransportKeys(900, 0, active); + TransportKeys shouldNotUpdate = createTransportKeys(1000, 0, active); Collection loaded = asList( new TransportKeySet(keySetId, contactId, null, shouldUpdate), new TransportKeySet(keySetId1, contactId1, null, shouldNotUpdate) ); - TransportKeys updated = createTransportKeys(1000, 0, true); + TransportKeys updated = createTransportKeys(1000, 0, active); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ @@ -111,19 +112,22 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { db, transportCrypto, dbExecutor, scheduler, clock, transportId, maxLatency); transportKeyManager.start(txn); - assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); + assertEquals(active, + transportKeyManager.canSendOutgoingStreams(contactId)); } @Test - public void testKeysAreUpdatedWhenAddingContact() throws Exception { + public void testRotationKeysAreDerivedAndUpdatedWhenAddingContact() + throws Exception { boolean alice = random.nextBoolean(); - TransportKeys transportKeys = createTransportKeys(999, 0, true); - TransportKeys updated = createTransportKeys(1000, 0, true); + boolean active = random.nextBoolean(); + TransportKeys transportKeys = createTransportKeys(999, 0, active); + TransportKeys updated = createTransportKeys(1000, 0, active); Transaction txn = new Transaction(null, false); context.checking(new Expectations() {{ oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey, - 999, alice, true); + 999, alice, active); will(returnValue(transportKeys)); // Get the current time (1 ms after start of time period 1000) oneOf(clock).currentTimeMillis(); @@ -149,7 +153,43 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase { // The timestamp is 1 ms before the start of time period 1000 long timestamp = timePeriodLength * 1000 - 1; assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, - rootKey, timestamp, alice, true)); + rootKey, timestamp, alice, active)); + assertEquals(active, + transportKeyManager.canSendOutgoingStreams(contactId)); + } + + @Test + public void testHandshakeKeysAreDerivedWhenAddingContact() + throws Exception { + boolean alice = random.nextBoolean(); + TransportKeys transportKeys = createTransportKeys(1000, 0, true); + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + // Get the current time (1 ms after start of time period 1000) + oneOf(clock).currentTimeMillis(); + will(returnValue(timePeriodLength * 1000 + 1)); + // Derive the transport keys + oneOf(transportCrypto).deriveHandshakeKeys(transportId, rootKey, + 1000, alice); + will(returnValue(transportKeys)); + // Encode the tags (3 sets) + for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) { + exactly(3).of(transportCrypto).encodeTag( + with(any(byte[].class)), with(tagKey), + with(PROTOCOL_VERSION), with(i)); + will(new EncodeTagAction()); + } + // Save the keys + oneOf(db).addTransportKeys(txn, contactId, transportKeys); + will(returnValue(keySetId)); + }}); + + TransportKeyManager transportKeyManager = new TransportKeyManagerImpl( + db, transportCrypto, dbExecutor, scheduler, clock, transportId, + maxLatency); + assertEquals(keySetId, transportKeyManager.addContact(txn, contactId, + rootKey, alice)); assertTrue(transportKeyManager.canSendOutgoingStreams(contactId)); }