mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
Merge branch '1556-key-manager-methods-for-pending-contacts' into 'master'
Add key manager methods for pending contacts Closes #1556 See merge request briar/briar!1089
This commit is contained in:
@@ -73,8 +73,8 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).transactionWithResult(with(false), withDbCallable(txn));
|
||||
oneOf(db).addContact(txn, remote, local, verified);
|
||||
will(returnValue(contactId));
|
||||
oneOf(keyManager).addContact(txn, contactId, rootKey, timestamp,
|
||||
alice, active);
|
||||
oneOf(keyManager).addContactWithRotationKeys(txn, contactId,
|
||||
rootKey, timestamp, alice, active);
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
will(returnValue(contact));
|
||||
}});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.bramble.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
@@ -26,6 +27,7 @@ import static java.util.Collections.singletonMap;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -43,11 +45,17 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
||||
private final DeterministicExecutor executor = new DeterministicExecutor();
|
||||
private final Transaction txn = new Transaction(null, false);
|
||||
private final ContactId contactId = getContactId();
|
||||
private final PendingContactId pendingContactId =
|
||||
new PendingContactId(getRandomId());
|
||||
private final KeySetId keySetId = new KeySetId(345);
|
||||
private final TransportId transportId = getTransportId();
|
||||
private final TransportId unknownTransportId = getTransportId();
|
||||
private final StreamContext streamContext = new StreamContext(contactId,
|
||||
null, transportId, getSecretKey(), getSecretKey(), 1, false);
|
||||
private final StreamContext contactStreamContext =
|
||||
new StreamContext(contactId, null, transportId, getSecretKey(),
|
||||
getSecretKey(), 1, false);
|
||||
private final StreamContext pendingContactStreamContext =
|
||||
new StreamContext(null, pendingContactId, transportId,
|
||||
getSecretKey(), getSecretKey(), 1, true);
|
||||
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
||||
private final Random random = new Random();
|
||||
|
||||
@@ -83,41 +91,94 @@ 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();
|
||||
boolean active = random.nextBoolean();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
||||
timestamp, alice, active);
|
||||
oneOf(transportKeyManager).addContactWithRotationKeys(txn,
|
||||
contactId, secretKey, timestamp, alice, active);
|
||||
will(returnValue(keySetId));
|
||||
}});
|
||||
|
||||
Map<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
|
||||
secretKey, timestamp, alice, active);
|
||||
Map<TransportId, KeySetId> ids = keyManager.addContactWithRotationKeys(
|
||||
txn, contactId, secretKey, timestamp, alice, active);
|
||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForUnknownTransport() throws Exception {
|
||||
public void testAddContactWithHandshakeModeKeys() throws Exception {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
boolean alice = random.nextBoolean();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(transportKeyManager).addContactWithHandshakeKeys(
|
||||
txn, contactId, secretKey, alice);
|
||||
will(returnValue(keySetId));
|
||||
}});
|
||||
|
||||
Map<TransportId, KeySetId> ids = keyManager.addContactWithHandshakeKeys(
|
||||
txn, contactId, secretKey, alice);
|
||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddPendingContact() throws Exception {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
boolean alice = random.nextBoolean();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(transportKeyManager).addPendingContact(txn, pendingContactId,
|
||||
secretKey, alice);
|
||||
will(returnValue(keySetId));
|
||||
}});
|
||||
|
||||
Map<TransportId, KeySetId> ids = keyManager.addPendingContact(txn,
|
||||
pendingContactId, secretKey, alice);
|
||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForContactWithUnknownTransport()
|
||||
throws Exception {
|
||||
assertNull(keyManager.getStreamContext(contactId, unknownTransportId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForPendingContactWithUnknownTransport()
|
||||
throws Exception {
|
||||
assertNull(keyManager.getStreamContext(pendingContactId,
|
||||
unknownTransportId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForContact() throws Exception {
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(false),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(transportKeyManager).getStreamContext(txn, contactId);
|
||||
will(returnValue(streamContext));
|
||||
will(returnValue(contactStreamContext));
|
||||
}});
|
||||
|
||||
assertEquals(streamContext,
|
||||
assertEquals(contactStreamContext,
|
||||
keyManager.getStreamContext(contactId, transportId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForPendingContact() throws Exception {
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(false),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(transportKeyManager).getStreamContext(txn, pendingContactId);
|
||||
will(returnValue(pendingContactStreamContext));
|
||||
}});
|
||||
|
||||
assertEquals(pendingContactStreamContext,
|
||||
keyManager.getStreamContext(pendingContactId, transportId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStreamContextForTagAndUnknownTransport()
|
||||
throws Exception {
|
||||
@@ -130,10 +191,10 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).transactionWithNullableResult(with(false),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(transportKeyManager).getStreamContext(txn, tag);
|
||||
will(returnValue(streamContext));
|
||||
will(returnValue(contactStreamContext));
|
||||
}});
|
||||
|
||||
assertEquals(streamContext,
|
||||
assertEquals(contactStreamContext,
|
||||
keyManager.getStreamContext(transportId, tag));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.bramble.transport;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
@@ -37,6 +38,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||
@@ -61,6 +63,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
private final long timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
|
||||
private final ContactId contactId = getContactId();
|
||||
private final ContactId contactId1 = getContactId();
|
||||
private final PendingContactId pendingContactId =
|
||||
new PendingContactId(getRandomId());
|
||||
private final KeySetId keySetId = new KeySetId(345);
|
||||
private final KeySetId keySetId1 = new KeySetId(456);
|
||||
private final SecretKey tagKey = getSecretKey();
|
||||
@@ -70,14 +74,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 +116,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();
|
||||
@@ -148,11 +156,83 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// 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));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, active));
|
||||
assertEquals(active,
|
||||
transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandshakeKeysAreDerivedWhenAddingContact()
|
||||
throws Exception {
|
||||
boolean alice = random.nextBoolean();
|
||||
TransportKeys transportKeys = createHandshakeKeys(1000, 0, alice);
|
||||
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.addContactWithHandshakeKeys(
|
||||
txn, contactId, rootKey, alice));
|
||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandshakeKeysAreDerivedWhenAddingPendingContact()
|
||||
throws Exception {
|
||||
boolean alice = random.nextBoolean();
|
||||
TransportKeys transportKeys = createHandshakeKeys(1000, 0, alice);
|
||||
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, pendingContactId, transportKeys);
|
||||
will(returnValue(keySetId));
|
||||
}});
|
||||
|
||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||
maxLatency);
|
||||
assertEquals(keySetId, transportKeyManager.addPendingContact(txn,
|
||||
pendingContactId, rootKey, alice));
|
||||
assertTrue(transportKeyManager.canSendOutgoingStreams(
|
||||
pendingContactId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
||||
throws Exception {
|
||||
@@ -165,6 +245,19 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOutgoingStreamContextIsNullIfPendingContactIsNotFound()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||
maxLatency);
|
||||
assertNull(transportKeyManager.getStreamContext(txn, pendingContactId));
|
||||
assertFalse(transportKeyManager.canSendOutgoingStreams(
|
||||
pendingContactId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOutgoingStreamContextIsNullIfStreamCounterIsExhausted()
|
||||
throws Exception {
|
||||
@@ -181,8 +274,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, true));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, true));
|
||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||
}
|
||||
@@ -207,8 +300,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, true));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, true));
|
||||
// The first request should return a stream context
|
||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
||||
@@ -239,8 +332,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, active));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, active));
|
||||
assertEquals(active,
|
||||
transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
// The tag should not be recognised
|
||||
@@ -292,8 +385,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, true));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, true));
|
||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
// Use the first tag (previous time period, stream number 0)
|
||||
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
||||
@@ -395,8 +488,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, false));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, false));
|
||||
// The keys are inactive so no stream context should be returned
|
||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||
@@ -461,8 +554,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
maxLatency);
|
||||
// The timestamp is at the start of time period 1000
|
||||
long timestamp = timePeriodLength * 1000;
|
||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||
rootKey, timestamp, alice, false));
|
||||
assertEquals(keySetId, transportKeyManager.addContactWithRotationKeys(
|
||||
txn, contactId, rootKey, timestamp, alice, false));
|
||||
// The keys are inactive so no stream context should be returned
|
||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||
@@ -525,6 +618,21 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private TransportKeys createHandshakeKeys(long timePeriod,
|
||||
long streamCounter, boolean alice) {
|
||||
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
||||
timePeriod - 1);
|
||||
IncomingKeys inCurr = new IncomingKeys(tagKey, headerKey,
|
||||
timePeriod);
|
||||
IncomingKeys inNext = new IncomingKeys(tagKey, headerKey,
|
||||
timePeriod + 1);
|
||||
OutgoingKeys outCurr = new OutgoingKeys(tagKey, headerKey,
|
||||
timePeriod, streamCounter, true);
|
||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr,
|
||||
rootKey, alice);
|
||||
}
|
||||
|
||||
private class EncodeTagAction implements Action {
|
||||
|
||||
private final Collection<byte[]> tags;
|
||||
|
||||
Reference in New Issue
Block a user