mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 20:59:54 +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
|
* 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
|
* stores a set of rotation mode transport keys for communicating with the
|
||||||
* each transport and returns the key set IDs.
|
* contact over each transport and returns the key set IDs.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link StreamContext StreamContexts} for the contact can be created
|
* {@link StreamContext StreamContexts} for the contact can be created
|
||||||
* after this method has returned.
|
* after this method has returned.
|
||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice True if the local party is Alice
|
||||||
* @param active whether the derived keys can be used for outgoing streams
|
* @param active Whether the derived keys can be used for outgoing streams
|
||||||
*/
|
*/
|
||||||
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
SecretKey rootKey, long timestamp, boolean alice, boolean active)
|
||||||
throws DbException;
|
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.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -100,6 +100,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
return ids;
|
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
|
@Override
|
||||||
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ interface TransportKeyManager {
|
|||||||
KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey,
|
KeySetId addContact(Transaction txn, ContactId c, SecretKey rootKey,
|
||||||
long timestamp, boolean alice, boolean active) throws DbException;
|
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 activateKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
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
|
@Override
|
||||||
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddContact() throws Exception {
|
public void testAddContactWithRotationModeKeys() throws Exception {
|
||||||
SecretKey secretKey = getSecretKey();
|
SecretKey secretKey = getSecretKey();
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
@@ -100,6 +100,22 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
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
|
@Test
|
||||||
public void testGetStreamContextForUnknownTransport() throws Exception {
|
public void testGetStreamContextForUnknownTransport() throws Exception {
|
||||||
assertNull(keyManager.getStreamContext(contactId, unknownTransportId));
|
assertNull(keyManager.getStreamContext(contactId, unknownTransportId));
|
||||||
|
|||||||
@@ -70,14 +70,15 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeysAreUpdatedAtStartup() throws Exception {
|
public void testKeysAreUpdatedAtStartup() throws Exception {
|
||||||
TransportKeys shouldUpdate = createTransportKeys(900, 0, true);
|
boolean active = random.nextBoolean();
|
||||||
TransportKeys shouldNotUpdate = createTransportKeys(1000, 0, true);
|
TransportKeys shouldUpdate = createTransportKeys(900, 0, active);
|
||||||
|
TransportKeys shouldNotUpdate = createTransportKeys(1000, 0, active);
|
||||||
Collection<TransportKeySet> loaded = asList(
|
Collection<TransportKeySet> loaded = asList(
|
||||||
new TransportKeySet(keySetId, contactId, null, shouldUpdate),
|
new TransportKeySet(keySetId, contactId, null, shouldUpdate),
|
||||||
new TransportKeySet(keySetId1, contactId1, null,
|
new TransportKeySet(keySetId1, contactId1, null,
|
||||||
shouldNotUpdate)
|
shouldNotUpdate)
|
||||||
);
|
);
|
||||||
TransportKeys updated = createTransportKeys(1000, 0, true);
|
TransportKeys updated = createTransportKeys(1000, 0, active);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -111,19 +112,22 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
transportKeyManager.start(txn);
|
transportKeyManager.start(txn);
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertEquals(active,
|
||||||
|
transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeysAreUpdatedWhenAddingContact() throws Exception {
|
public void testRotationKeysAreDerivedAndUpdatedWhenAddingContact()
|
||||||
|
throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(999, 0, true);
|
boolean active = random.nextBoolean();
|
||||||
TransportKeys updated = createTransportKeys(1000, 0, true);
|
TransportKeys transportKeys = createTransportKeys(999, 0, active);
|
||||||
|
TransportKeys updated = createTransportKeys(1000, 0, active);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
|
oneOf(transportCrypto).deriveRotationKeys(transportId, rootKey,
|
||||||
999, alice, true);
|
999, alice, active);
|
||||||
will(returnValue(transportKeys));
|
will(returnValue(transportKeys));
|
||||||
// Get the current time (1 ms after start of time period 1000)
|
// Get the current time (1 ms after start of time period 1000)
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -149,7 +153,43 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// The timestamp is 1 ms before the start of time period 1000
|
// The timestamp is 1 ms before the start of time period 1000
|
||||||
long timestamp = timePeriodLength * 1000 - 1;
|
long timestamp = timePeriodLength * 1000 - 1;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
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));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user