mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Add methods for adding unbound keys.
This commit is contained in:
@@ -16,13 +16,21 @@ 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 transport keys for communicating with the contact.
|
* stores a set of transport keys for communicating with the contact over
|
||||||
|
* each transport.
|
||||||
|
* <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.
|
||||||
*/
|
*/
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException;
|
long timestamp, boolean alice) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives and stores a set of unbound transport keys for each transport.
|
||||||
|
*/
|
||||||
|
void addUnboundKeys(Transaction txn, SecretKey master, long timestamp,
|
||||||
|
boolean alice) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link StreamContext} for sending a stream to the given
|
* Returns a {@link StreamContext} for sending a stream to the given
|
||||||
* contact over the given transport, or null if an error occurs or the
|
* contact over the given transport, or null if an error occurs or the
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||||
SecretKey master,long timestamp, boolean alice, boolean verified,
|
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||||
boolean active) throws DbException {
|
boolean active) throws DbException {
|
||||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||||
keyManager.addContact(txn, c, master, timestamp, alice);
|
keyManager.addContact(txn, c, master, timestamp, alice);
|
||||||
|
|||||||
@@ -104,6 +104,13 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
m.addContact(txn, c, master, timestamp, alice);
|
m.addContact(txn, c, master, timestamp, alice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnboundKeys(Transaction txn, SecretKey master,
|
||||||
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
for (TransportKeyManager m : managers.values())
|
||||||
|
m.addUnboundKeys(txn, master, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamContext getStreamContext(ContactId c, TransportId t)
|
public StreamContext getStreamContext(ContactId c, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ interface TransportKeyManager {
|
|||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException;
|
long timestamp, boolean alice) throws DbException;
|
||||||
|
|
||||||
|
void addUnboundKeys(Transaction txn, SecretKey master, long timestamp,
|
||||||
|
boolean alice) throws DbException;
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
void removeContact(ContactId c);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -172,6 +172,18 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
@Override
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException {
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
deriveAndAddKeys(txn, c, master, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnboundKeys(Transaction txn, SecretKey master,
|
||||||
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
deriveAndAddKeys(txn, null, master, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deriveAndAddKeys(Transaction txn, @Nullable ContactId c,
|
||||||
|
SecretKey master, long timestamp, boolean alice)
|
||||||
|
throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Work out what rotation period the timestamp belongs to
|
// Work out what rotation period the timestamp belongs to
|
||||||
|
|||||||
@@ -113,6 +113,21 @@ public class KeyManagerImplTest extends BrambleTestCase {
|
|||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddUnboundKeys() throws Exception {
|
||||||
|
SecretKey secretKey = getSecretKey();
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
boolean alice = new Random().nextBoolean();
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportKeyManager).addUnboundKeys(txn, secretKey,
|
||||||
|
timestamp, alice);
|
||||||
|
}});
|
||||||
|
|
||||||
|
keyManager.addUnboundKeys(txn, secretKey, timestamp, alice);
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetStreamContextForInactiveContact() throws Exception {
|
public void testGetStreamContextForInactiveContact() throws Exception {
|
||||||
assertEquals(null,
|
assertEquals(null,
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
@@ -57,6 +56,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ContactId contactId = new ContactId(123);
|
private final ContactId contactId = new ContactId(123);
|
||||||
private final ContactId contactId1 = new ContactId(234);
|
private final ContactId contactId1 = new ContactId(234);
|
||||||
private final KeySetId keySetId = new KeySetId(345);
|
private final KeySetId keySetId = new KeySetId(345);
|
||||||
|
private final KeySetId keySetId1 = new KeySetId(456);
|
||||||
|
private final KeySetId keySetId2 = new KeySetId(567);
|
||||||
private final SecretKey tagKey = TestUtils.getSecretKey();
|
private final SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey headerKey = TestUtils.getSecretKey();
|
private final SecretKey headerKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey masterKey = TestUtils.getSecretKey();
|
private final SecretKey masterKey = TestUtils.getSecretKey();
|
||||||
@@ -66,11 +67,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testKeysAreRotatedAtStartup() throws Exception {
|
public void testKeysAreRotatedAtStartup() throws Exception {
|
||||||
TransportKeys shouldRotate = createTransportKeys(900, 0);
|
TransportKeys shouldRotate = createTransportKeys(900, 0);
|
||||||
TransportKeys shouldNotRotate = createTransportKeys(1000, 0);
|
TransportKeys shouldNotRotate = createTransportKeys(1000, 0);
|
||||||
|
TransportKeys shouldRotate1 = createTransportKeys(999, 0);
|
||||||
Collection<KeySet> loaded = asList(
|
Collection<KeySet> loaded = asList(
|
||||||
new KeySet(keySetId, contactId, shouldRotate),
|
new KeySet(keySetId, contactId, shouldRotate),
|
||||||
new KeySet(keySetId, contactId1, shouldNotRotate)
|
new KeySet(keySetId1, contactId1, shouldNotRotate),
|
||||||
|
new KeySet(keySetId2, null, shouldRotate1)
|
||||||
);
|
);
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0);
|
TransportKeys rotated = createTransportKeys(1000, 0);
|
||||||
|
TransportKeys rotated1 = createTransportKeys(1000, 0);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -85,6 +89,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(rotated));
|
will(returnValue(rotated));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
||||||
will(returnValue(shouldNotRotate));
|
will(returnValue(shouldNotRotate));
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(shouldRotate1, 1000);
|
||||||
|
will(returnValue(rotated1));
|
||||||
// Encode the tags (3 sets per contact)
|
// Encode the tags (3 sets per contact)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(6).of(transportCrypto).encodeTag(
|
exactly(6).of(transportCrypto).encodeTag(
|
||||||
@@ -93,8 +99,10 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
oneOf(db).updateTransportKeys(txn,
|
oneOf(db).updateTransportKeys(txn, asList(
|
||||||
singletonList(new KeySet(keySetId, contactId, rotated)));
|
new KeySet(keySetId, contactId, rotated),
|
||||||
|
new KeySet(keySetId2, null, rotated1))
|
||||||
|
);
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
||||||
@@ -144,6 +152,36 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
alice);
|
alice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeysAreRotatedWhenAddingUnboundKeys() throws Exception {
|
||||||
|
boolean alice = random.nextBoolean();
|
||||||
|
TransportKeys transportKeys = createTransportKeys(999, 0);
|
||||||
|
TransportKeys rotated = createTransportKeys(1000, 0);
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
|
999, alice);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Get the current time (1 ms after start of rotation period 1000)
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(rotationPeriodLength * 1000 + 1));
|
||||||
|
// Rotate the transport keys
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
|
will(returnValue(rotated));
|
||||||
|
// Save the keys
|
||||||
|
oneOf(db).addTransportKeys(txn, null, rotated);
|
||||||
|
will(returnValue(keySetId));
|
||||||
|
}});
|
||||||
|
|
||||||
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
|
maxLatency);
|
||||||
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
|
transportKeyManager.addUnboundKeys(txn, masterKey, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -353,9 +391,13 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testKeysAreRotatedToCurrentPeriod() throws Exception {
|
public void testKeysAreRotatedToCurrentPeriod() throws Exception {
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0);
|
TransportKeys transportKeys = createTransportKeys(1000, 0);
|
||||||
Collection<KeySet> loaded =
|
TransportKeys transportKeys1 = createTransportKeys(1000, 0);
|
||||||
singletonList(new KeySet(keySetId, contactId, transportKeys));
|
Collection<KeySet> loaded = asList(
|
||||||
|
new KeySet(keySetId, contactId, transportKeys),
|
||||||
|
new KeySet(keySetId1, null, transportKeys1)
|
||||||
|
);
|
||||||
TransportKeys rotated = createTransportKeys(1001, 0);
|
TransportKeys rotated = createTransportKeys(1001, 0);
|
||||||
|
TransportKeys rotated1 = createTransportKeys(1001, 0);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Transaction txn1 = new Transaction(null, false);
|
Transaction txn1 = new Transaction(null, false);
|
||||||
|
|
||||||
@@ -369,6 +411,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
will(returnValue(transportKeys));
|
will(returnValue(transportKeys));
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys1, 1000);
|
||||||
|
will(returnValue(transportKeys1));
|
||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
@@ -392,6 +436,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(transportCrypto).rotateTransportKeys(
|
oneOf(transportCrypto).rotateTransportKeys(
|
||||||
with(any(TransportKeys.class)), with(1001L));
|
with(any(TransportKeys.class)), with(1001L));
|
||||||
will(returnValue(rotated));
|
will(returnValue(rotated));
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(
|
||||||
|
with(any(TransportKeys.class)), with(1001L));
|
||||||
|
will(returnValue(rotated1));
|
||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
@@ -400,8 +447,10 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
oneOf(db).updateTransportKeys(txn1,
|
oneOf(db).updateTransportKeys(txn1, asList(
|
||||||
singletonList(new KeySet(keySetId, contactId, rotated)));
|
new KeySet(keySetId, contactId, rotated),
|
||||||
|
new KeySet(keySetId1, null, rotated1)
|
||||||
|
));
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength), with(MILLISECONDS));
|
with(rotationPeriodLength), with(MILLISECONDS));
|
||||||
|
|||||||
Reference in New Issue
Block a user