Commit 8b2b7599 authored by akwizgran's avatar akwizgran

Generate and store handshake keys at startup if needed.

parent 8c315382
......@@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
......@@ -100,24 +101,32 @@ public class TestUtils {
}
public static LocalAuthor getLocalAuthor() {
return getLocalAuthor(1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH));
return getLocalAuthor(false);
}
public static LocalAuthor getLocalAuthor(int nameLength) {
public static LocalAuthor getLocalAuthor(boolean withHandshakeKeys) {
AuthorId id = new AuthorId(getRandomId());
int nameLength = 1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH);
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
byte[] privateKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey,
timestamp);
if (withHandshakeKeys) {
byte[] handshakePublicKey =
getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
byte[] handshakePrivateKey =
getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey,
privateKey, handshakePublicKey, handshakePrivateKey,
timestamp);
} else {
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey,
privateKey, timestamp);
}
}
public static Author getAuthor() {
return getAuthor(1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH));
}
public static Author getAuthor(int nameLength) {
AuthorId id = new AuthorId(getRandomId());
int nameLength = 1 + random.nextInt(MAX_AUTHOR_NAME_LENGTH);
String name = getRandomString(nameLength);
byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
return new Author(id, FORMAT_VERSION, name, publicKey);
......
package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
......@@ -9,6 +11,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import java.util.logging.Logger;
import javax.annotation.Nullable;
......@@ -27,6 +30,7 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
getLogger(IdentityManagerImpl.class.getName());
private final DatabaseComponent db;
private final CryptoComponent crypto;
private final AuthorFactory authorFactory;
// The local author is immutable so we can cache it
......@@ -34,8 +38,10 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
private volatile LocalAuthor cachedAuthor;
@Inject
IdentityManagerImpl(DatabaseComponent db, AuthorFactory authorFactory) {
IdentityManagerImpl(DatabaseComponent db, CryptoComponent crypto,
AuthorFactory authorFactory) {
this.db = db;
this.crypto = crypto;
this.authorFactory = authorFactory;
}
......@@ -57,38 +63,56 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
public void onDatabaseOpened(Transaction txn) throws DbException {
LocalAuthor cached = cachedAuthor;
if (cached == null) {
LOG.info("No local author to store");
return;
LocalAuthor loaded = loadLocalAuthor(txn);
if (loaded.getHandshakePublicKey() == null) {
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
byte[] handshakePublicKey =
handshakeKeyPair.getPublic().getEncoded();
byte[] handshakePrivateKey =
handshakeKeyPair.getPrivate().getEncoded();
db.setHandshakeKeyPair(txn, loaded.getId(),
handshakePublicKey, handshakePrivateKey);
cachedAuthor = new LocalAuthor(loaded.getId(),
loaded.getFormatVersion(), loaded.getName(),
loaded.getPublicKey(), loaded.getPrivateKey(),
handshakePublicKey, handshakePrivateKey,
loaded.getTimeCreated());
LOG.info("Handshake key pair added");
} else {
cachedAuthor = loaded;
LOG.info("Local author loaded");
}
} else {
db.addLocalAuthor(txn, cached);
LOG.info("Local author stored");
}
db.addLocalAuthor(txn, cached);
LOG.info("Local author stored");
}
@Override
public LocalAuthor getLocalAuthor() throws DbException {
if (cachedAuthor == null) {
cachedAuthor =
LocalAuthor cached = cachedAuthor;
if (cached == null) {
cachedAuthor = cached =
db.transactionWithResult(true, this::loadLocalAuthor);
LOG.info("Local author loaded");
}
LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError();
return cached;
}
@Override
public LocalAuthor getLocalAuthor(Transaction txn) throws DbException {
if (cachedAuthor == null) {
cachedAuthor = loadLocalAuthor(txn);
LocalAuthor cached = cachedAuthor;
if (cached == null) {
cachedAuthor = cached = loadLocalAuthor(txn);
LOG.info("Local author loaded");
}
LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError();
return cached;
}
private LocalAuthor loadLocalAuthor(Transaction txn) throws DbException {
return db.getLocalAuthors(txn).iterator().next();
Collection<LocalAuthor> authors = db.getLocalAuthors(txn);
if (authors.size() != 1) throw new IllegalStateException();
return authors.iterator().next();
}
}
package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
......@@ -7,47 +11,89 @@ import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class IdentityManagerImplTest extends BrambleMockTestCase {
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final AuthorFactory authorFactory =
context.mock(AuthorFactory.class);
private final PublicKey handshakePublicKey = context.mock(PublicKey.class);
private final PrivateKey handshakePrivateKey =
context.mock(PrivateKey.class);
private final Transaction txn = new Transaction(null, false);
private final LocalAuthor localAuthor = getLocalAuthor();
private final Collection<LocalAuthor> localAuthors =
singletonList(localAuthor);
private final LocalAuthor localAuthor = getLocalAuthor(true);
private final LocalAuthor localAuthorWithoutHandshakeKeys =
new LocalAuthor(localAuthor.getId(), localAuthor.getFormatVersion(),
localAuthor.getName(), localAuthor.getPublicKey(),
localAuthor.getPrivateKey(), localAuthor.getTimeCreated());
private final KeyPair handshakeKeyPair =
new KeyPair(handshakePublicKey, handshakePrivateKey);
private final byte[] handshakePublicKeyBytes =
localAuthor.getHandshakePublicKey();
private final byte[] handshakePrivateKeyBytes =
localAuthor.getHandshakePrivateKey();
private IdentityManagerImpl identityManager;
@Before
public void setUp() {
identityManager = new IdentityManagerImpl(db, authorFactory);
identityManager = new IdentityManagerImpl(db, crypto, authorFactory);
}
@Test
public void testOpenDatabaseHookLocalAuthorRegistered() throws Exception {
context.checking(new Expectations() {{
oneOf(db).addLocalAuthor(txn, localAuthor);
}});
identityManager.registerLocalAuthor(localAuthor);
identityManager.onDatabaseOpened(txn);
}
@Test
public void testOpenDatabaseHookWithoutLocalAuthorRegistered()
public void testOpenDatabaseHookNoLocalAuthorRegisteredHandshakeKeys()
throws Exception {
context.checking(new Expectations() {{
oneOf(db).getLocalAuthors(txn);
will(returnValue(singletonList(localAuthor)));
}});
identityManager.onDatabaseOpened(txn);
}
@Test
public void testOpenDatabaseHookWithLocalAuthorRegistered()
public void testOpenDatabaseHookNoLocalAuthorRegisteredNoHandshakeKeys()
throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).addLocalAuthor(txn, localAuthor);
context.checking(new Expectations() {{
oneOf(db).getLocalAuthors(txn);
will(returnValue(singletonList(localAuthorWithoutHandshakeKeys)));
oneOf(crypto).generateAgreementKeyPair();
will(returnValue(handshakeKeyPair));
oneOf(handshakePublicKey).getEncoded();
will(returnValue(handshakePublicKeyBytes));
oneOf(handshakePrivateKey).getEncoded();
will(returnValue(handshakePrivateKeyBytes));
oneOf(db).setHandshakeKeyPair(txn, localAuthor.getId(),
handshakePublicKeyBytes, handshakePrivateKeyBytes);
}});
identityManager.registerLocalAuthor(localAuthor);
identityManager.onDatabaseOpened(txn);
LocalAuthor cached = identityManager.getLocalAuthor();
assertArrayEquals(handshakePublicKeyBytes,
cached.getHandshakePublicKey());
assertArrayEquals(handshakePrivateKeyBytes,
cached.getHandshakePrivateKey());
}
@Test
......@@ -55,7 +101,7 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getLocalAuthors(txn);
will(returnValue(localAuthors));
will(returnValue(singletonList(localAuthor)));
}});
assertEquals(localAuthor, identityManager.getLocalAuthor());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment