mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Add key manager method for contacts with handshake keys.
This commit is contained in:
@@ -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.
|
||||
* <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
|
||||
* @param alice True if the local party is Alice
|
||||
* @param active Whether the derived keys can be used for outgoing streams
|
||||
*/
|
||||
Map<TransportId, KeySetId> 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.
|
||||
* <p/>
|
||||
* {@link StreamContext StreamContexts} for the contact can be created
|
||||
* after this method has returned.
|
||||
*
|
||||
* @param alice True if the local party is ALice
|
||||
*/
|
||||
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||
SecretKey rootKey, boolean alice) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given transport keys as usable for outgoing streams.
|
||||
*/
|
||||
|
||||
@@ -100,6 +100,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TransportId, KeySetId> addContact(Transaction txn,
|
||||
ContactId c, SecretKey rootKey, boolean alice) throws DbException {
|
||||
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||
for (Entry<TransportId, TransportKeyManager> 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<TransportId, KeySetId> keys)
|
||||
throws DbException {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
|
||||
secretKey, alice);
|
||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForUnknownTransport() throws Exception {
|
||||
assertNull(keyManager.getStreamContext(contactId, unknownTransportId));
|
||||
|
||||
@@ -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<TransportKeySet> 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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user