mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Derive handshake root key when adding a pending contact.
This commit is contained in:
@@ -11,6 +11,12 @@ import java.security.GeneralSecurityException;
|
|||||||
*/
|
*/
|
||||||
public interface TransportCrypto {
|
public interface TransportCrypto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the local peer is Alice.
|
||||||
|
*/
|
||||||
|
boolean isAlice(PublicKey theirHandshakePublicKey,
|
||||||
|
KeyPair ourHandshakeKeyPair);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives the static master key shared with a contact or pending contact.
|
* Derives the static master key shared with a contact or pending contact.
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +25,7 @@ public interface TransportCrypto {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives the handshake mode root key from the static master key.
|
* Derives the handshake mode root key from the static master key.
|
||||||
|
*
|
||||||
* @param pendingContact Whether the static master key is shared with a
|
* @param pendingContact Whether the static master key is shared with a
|
||||||
* pending contact or a contact
|
* pending contact or a contact
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package org.briarproject.bramble.api.transport;
|
package org.briarproject.bramble.api.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -53,12 +56,10 @@ public interface KeyManager {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* {@link StreamContext StreamContexts} for the pending contact can be
|
* {@link StreamContext StreamContexts} for the pending contact can be
|
||||||
* created after this method has returned.
|
* created after this method has returned.
|
||||||
*
|
|
||||||
* @param alice True if the local party is Alice
|
|
||||||
*/
|
*/
|
||||||
Map<TransportId, KeySetId> addPendingContact(Transaction txn,
|
Map<TransportId, KeySetId> addPendingContact(Transaction txn,
|
||||||
PendingContactId p, SecretKey rootKey, boolean alice)
|
PendingContact p, KeyPair ourKeyPair)
|
||||||
throws DbException;
|
throws DbException, GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
|
|||||||
import org.briarproject.bramble.api.contact.PendingContact;
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -21,6 +22,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -51,6 +53,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
private final KeyManager keyManager;
|
private final KeyManager keyManager;
|
||||||
private final IdentityManager identityManager;
|
private final IdentityManager identityManager;
|
||||||
private final PendingContactFactory pendingContactFactory;
|
private final PendingContactFactory pendingContactFactory;
|
||||||
|
|
||||||
private final List<ContactHook> hooks;
|
private final List<ContactHook> hooks;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -123,7 +126,15 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
PendingContact p =
|
PendingContact p =
|
||||||
pendingContactFactory.createPendingContact(link, alias);
|
pendingContactFactory.createPendingContact(link, alias);
|
||||||
db.transaction(false, txn -> db.addPendingContact(txn, p));
|
db.transaction(false, txn -> {
|
||||||
|
db.addPendingContact(txn, p);
|
||||||
|
KeyPair ourKeyPair = identityManager.getHandshakeKeys(txn);
|
||||||
|
try {
|
||||||
|
keyManager.addPendingContact(txn, p, ourKeyPair);
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
});
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlice(PublicKey theirHandshakePublicKey,
|
||||||
|
KeyPair ourHandshakeKeyPair) {
|
||||||
|
byte[] theirPublic = theirHandshakePublicKey.getEncoded();
|
||||||
|
byte[] ourPublic = ourHandshakeKeyPair.getPublic().getEncoded();
|
||||||
|
return compare(ourPublic, theirPublic) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKey deriveStaticMasterKey(PublicKey theirHandshakePublicKey,
|
public SecretKey deriveStaticMasterKey(PublicKey theirHandshakePublicKey,
|
||||||
KeyPair ourHandshakeKeyPair) throws GeneralSecurityException {
|
KeyPair ourHandshakeKeyPair) throws GeneralSecurityException {
|
||||||
@@ -55,8 +63,8 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
byte[] ourPublic = ourHandshakeKeyPair.getPublic().getEncoded();
|
byte[] ourPublic = ourHandshakeKeyPair.getPublic().getEncoded();
|
||||||
boolean alice = compare(ourPublic, theirPublic) < 0;
|
boolean alice = compare(ourPublic, theirPublic) < 0;
|
||||||
byte[][] inputs = {
|
byte[][] inputs = {
|
||||||
alice ? ourPublic : theirPublic,
|
alice ? ourPublic : theirPublic,
|
||||||
alice ? theirPublic : ourPublic
|
alice ? theirPublic : ourPublic
|
||||||
};
|
};
|
||||||
return crypto.deriveSharedSecret(STATIC_MASTER_KEY_LABEL,
|
return crypto.deriveSharedSecret(STATIC_MASTER_KEY_LABEL,
|
||||||
theirHandshakePublicKey, ourHandshakeKeyPair, inputs);
|
theirHandshakePublicKey, ourHandshakeKeyPair, inputs);
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package org.briarproject.bramble.transport;
|
package org.briarproject.bramble.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -21,6 +24,7 @@ import org.briarproject.bramble.api.transport.KeyManager;
|
|||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -46,17 +50,22 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
private final Executor dbExecutor;
|
private final Executor dbExecutor;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final TransportKeyManagerFactory transportKeyManagerFactory;
|
private final TransportKeyManagerFactory transportKeyManagerFactory;
|
||||||
|
private final TransportCrypto transportCrypto;
|
||||||
|
|
||||||
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
KeyManagerImpl(DatabaseComponent db, @DatabaseExecutor Executor dbExecutor,
|
KeyManagerImpl(DatabaseComponent db,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
PluginConfig pluginConfig,
|
PluginConfig pluginConfig,
|
||||||
TransportKeyManagerFactory transportKeyManagerFactory) {
|
TransportKeyManagerFactory transportKeyManagerFactory,
|
||||||
|
TransportCrypto transportCrypto) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
this.transportKeyManagerFactory = transportKeyManagerFactory;
|
this.transportKeyManagerFactory = transportKeyManagerFactory;
|
||||||
|
this.transportCrypto = transportCrypto;
|
||||||
managers = new ConcurrentHashMap<>();
|
managers = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,13 +127,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<TransportId, KeySetId> addPendingContact(Transaction txn,
|
public Map<TransportId, KeySetId> addPendingContact(Transaction txn,
|
||||||
PendingContactId p, SecretKey rootKey, boolean alice)
|
PendingContact p, KeyPair ourKeyPair)
|
||||||
throws DbException {
|
throws DbException, GeneralSecurityException {
|
||||||
|
SecretKey staticMasterKey = transportCrypto
|
||||||
|
.deriveStaticMasterKey(p.getPublicKey(), ourKeyPair);
|
||||||
|
SecretKey rootKey =
|
||||||
|
transportCrypto.deriveHandshakeRootKey(staticMasterKey, true);
|
||||||
|
boolean alice = transportCrypto.isAlice(p.getPublicKey(), ourKeyPair);
|
||||||
Map<TransportId, KeySetId> ids = new HashMap<>();
|
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||||
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = e.getValue();
|
TransportKeyManager m = e.getValue();
|
||||||
ids.put(t, m.addPendingContact(txn, p, rootKey, alice));
|
ids.put(t, m.addPendingContact(txn, p.getId(), rootKey, alice));
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package org.briarproject.bramble.transport;
|
package org.briarproject.bramble.transport;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
@@ -25,9 +28,11 @@ import java.util.Random;
|
|||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getPendingContact;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
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.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -41,12 +46,14 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(TransportKeyManagerFactory.class);
|
context.mock(TransportKeyManagerFactory.class);
|
||||||
private final TransportKeyManager transportKeyManager =
|
private final TransportKeyManager transportKeyManager =
|
||||||
context.mock(TransportKeyManager.class);
|
context.mock(TransportKeyManager.class);
|
||||||
|
private final TransportCrypto transportCrypto =
|
||||||
|
context.mock(TransportCrypto.class);
|
||||||
|
|
||||||
private final DeterministicExecutor executor = new DeterministicExecutor();
|
private final DeterministicExecutor executor = new DeterministicExecutor();
|
||||||
private final Transaction txn = new Transaction(null, false);
|
private final Transaction txn = new Transaction(null, false);
|
||||||
private final ContactId contactId = getContactId();
|
private final ContactId contactId = getContactId();
|
||||||
private final PendingContactId pendingContactId =
|
private final PendingContact pendingContact = getPendingContact();
|
||||||
new PendingContactId(getRandomId());
|
private final PendingContactId pendingContactId = pendingContact.getId();
|
||||||
private final KeySetId keySetId = new KeySetId(345);
|
private final KeySetId keySetId = new KeySetId(345);
|
||||||
private final TransportId transportId = getTransportId();
|
private final TransportId transportId = getTransportId();
|
||||||
private final TransportId unknownTransportId = getTransportId();
|
private final TransportId unknownTransportId = getTransportId();
|
||||||
@@ -60,7 +67,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
||||||
pluginConfig, transportKeyManagerFactory);
|
pluginConfig, transportKeyManagerFactory, transportCrypto);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void testStartService() throws Exception {
|
public void testStartService() throws Exception {
|
||||||
@@ -126,17 +133,29 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddPendingContact() throws Exception {
|
public void testAddPendingContact() throws Exception {
|
||||||
SecretKey secretKey = getSecretKey();
|
KeyPair ourKeyPair =
|
||||||
|
new KeyPair(getAgreementPublicKey(), getAgreementPrivateKey());
|
||||||
|
SecretKey staticMasterKey = getSecretKey();
|
||||||
|
SecretKey rootKey = getSecretKey();
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportCrypto).deriveStaticMasterKey(
|
||||||
|
pendingContact.getPublicKey(), ourKeyPair);
|
||||||
|
will(returnValue(staticMasterKey));
|
||||||
|
oneOf(transportCrypto)
|
||||||
|
.deriveHandshakeRootKey(staticMasterKey, true);
|
||||||
|
will(returnValue(rootKey));
|
||||||
|
oneOf(transportCrypto).isAlice(pendingContact.getPublicKey(),
|
||||||
|
ourKeyPair);
|
||||||
|
will(returnValue(alice));
|
||||||
oneOf(transportKeyManager).addPendingContact(txn, pendingContactId,
|
oneOf(transportKeyManager).addPendingContact(txn, pendingContactId,
|
||||||
secretKey, alice);
|
rootKey, alice);
|
||||||
will(returnValue(keySetId));
|
will(returnValue(keySetId));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Map<TransportId, KeySetId> ids = keyManager.addPendingContact(txn,
|
Map<TransportId, KeySetId> ids = keyManager.addPendingContact(txn,
|
||||||
pendingContactId, secretKey, alice);
|
pendingContact, ourKeyPair);
|
||||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user