mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Add a MAC to the ACTIVATE message to prevent the introducer to fake them
A fake ACTIVATE message would cause us to activate the transport keys before the contact has received our auth message, which would compromise forward secrecy.
This commit is contained in:
@@ -26,4 +26,7 @@ public interface IntroductionConstants {
|
||||
|
||||
String LABEL_AUTH_NONCE = "org.briarproject.briar.introduction/AUTH_NONCE";
|
||||
|
||||
String LABEL_ACTIVATE_MAC =
|
||||
"org.briarproject.briar.introduction/ACTIVATE_MAC";
|
||||
|
||||
}
|
||||
|
||||
@@ -110,11 +110,11 @@ abstract class AbstractProtocolEngine<S extends Session>
|
||||
return m;
|
||||
}
|
||||
|
||||
Message sendActivateMessage(Transaction txn, PeerSession s, long timestamp)
|
||||
throws DbException {
|
||||
Message sendActivateMessage(Transaction txn, PeerSession s, long timestamp,
|
||||
byte[] mac) throws DbException {
|
||||
Message m = messageEncoder
|
||||
.encodeActivateMessage(s.getContactGroupId(), timestamp,
|
||||
s.getLastLocalMessageId(), s.getSessionId());
|
||||
s.getLastLocalMessageId(), s.getSessionId(), mac);
|
||||
sendMessage(txn, ACTIVATE, s.getSessionId(), m, false);
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -12,15 +12,22 @@ import javax.annotation.concurrent.Immutable;
|
||||
class ActivateMessage extends AbstractIntroductionMessage {
|
||||
|
||||
private final SessionId sessionId;
|
||||
private final byte[] mac;
|
||||
|
||||
protected ActivateMessage(MessageId messageId, GroupId groupId,
|
||||
long timestamp, MessageId previousMessageId, SessionId sessionId) {
|
||||
long timestamp, MessageId previousMessageId, SessionId sessionId,
|
||||
byte[] mac) {
|
||||
super(messageId, groupId, timestamp, previousMessageId);
|
||||
this.sessionId = sessionId;
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public byte[] getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
@@ -13,7 +12,6 @@ import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
@@ -354,7 +352,7 @@ class IntroduceeProtocolEngine
|
||||
IntroductionResponse request =
|
||||
new IntroductionResponse(s.getSessionId(), m.getMessageId(),
|
||||
m.getGroupId(), INTRODUCEE, m.getTimestamp(), false,
|
||||
false, false, false, s.getRemoteAuthor().getName(),
|
||||
false, false, false, s.getRemote().author.getName(),
|
||||
false);
|
||||
IntroductionResponseReceivedEvent e =
|
||||
new IntroductionResponseReceivedEvent(c.getId(), request);
|
||||
@@ -383,16 +381,18 @@ class IntroduceeProtocolEngine
|
||||
|
||||
private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s)
|
||||
throws DbException {
|
||||
boolean alice = isAlice(txn, s);
|
||||
byte[] mac;
|
||||
byte[] signature;
|
||||
SecretKey masterKey;
|
||||
SecretKey masterKey, aliceMacKey, bobMacKey;
|
||||
try {
|
||||
masterKey = crypto.deriveMasterKey(s, alice);
|
||||
SecretKey macKey = crypto.deriveMacKey(masterKey, alice);
|
||||
masterKey = crypto.deriveMasterKey(s);
|
||||
aliceMacKey = crypto.deriveMacKey(masterKey, true);
|
||||
bobMacKey = crypto.deriveMacKey(masterKey, false);
|
||||
SecretKey ourMacKey = s.getLocal().alice ? aliceMacKey : bobMacKey;
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||
mac = crypto.mac(macKey, s, localAuthor.getId(), alice);
|
||||
signature = crypto.sign(macKey, localAuthor.getPrivateKey());
|
||||
mac = crypto.authMac(ourMacKey, s, localAuthor.getId(),
|
||||
s.getLocal().alice);
|
||||
signature = crypto.sign(ourMacKey, localAuthor.getPrivateKey());
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO
|
||||
return abort(txn, s);
|
||||
@@ -400,7 +400,8 @@ class IntroduceeProtocolEngine
|
||||
if (s.getState() != AWAIT_AUTH) throw new AssertionError();
|
||||
Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac,
|
||||
signature);
|
||||
return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, masterKey, sent);
|
||||
return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey,
|
||||
aliceMacKey, bobMacKey);
|
||||
}
|
||||
|
||||
private IntroduceeSession onRemoteAuth(Transaction txn,
|
||||
@@ -411,33 +412,50 @@ class IntroduceeProtocolEngine
|
||||
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||
try {
|
||||
crypto.verifyMac(m.getMac(), s, localAuthor.getId());
|
||||
crypto.verifyAuthMac(m.getMac(), s, localAuthor.getId());
|
||||
crypto.verifySignature(m.getSignature(), s, localAuthor.getId());
|
||||
} catch (GeneralSecurityException e) {
|
||||
return abort(txn, s);
|
||||
}
|
||||
long timestamp =
|
||||
Math.min(s.getAcceptTimestamp(), s.getRemoteAcceptTimestamp());
|
||||
long timestamp = Math.min(s.getLocal().acceptTimestamp,
|
||||
s.getRemote().acceptTimestamp);
|
||||
if (timestamp == -1) throw new AssertionError();
|
||||
|
||||
Map<TransportId, KeySetId> keys = null;
|
||||
boolean contactAdded = false;
|
||||
try {
|
||||
ContactId c = contactManager
|
||||
.addContact(txn, s.getRemoteAuthor(), localAuthor.getId(),
|
||||
false, false);
|
||||
if (s.getRemoteTransportProperties() == null ||
|
||||
s.getMasterKey() == null) throw new AssertionError();
|
||||
transportPropertyManager.addRemoteProperties(txn, c,
|
||||
s.getRemoteTransportProperties());
|
||||
keys = keyManager
|
||||
.addUnboundKeys(txn, new SecretKey(s.getMasterKey()),
|
||||
timestamp, isAlice(txn, s));
|
||||
contactManager
|
||||
.addContact(txn, s.getRemote().author, localAuthor.getId(),
|
||||
false, true);
|
||||
contactAdded = true;
|
||||
} catch (ContactExistsException e) {
|
||||
// Ignore this and continue without adding transport properties
|
||||
// or unbound transport keys. Continue with keys as null.
|
||||
// Ignore this, because the other introducee might have deleted us.
|
||||
// So we still want updated transport properties
|
||||
// and new transport keys.
|
||||
}
|
||||
Contact c = contactManager.getContact(txn, s.getRemote().author.getId(),
|
||||
localAuthor.getId());
|
||||
|
||||
Message sent = sendActivateMessage(txn, s, getLocalTimestamp(s));
|
||||
// bind the keys to the new (or existing) contact
|
||||
//noinspection ConstantConditions
|
||||
Map<TransportId, KeySetId> keys = keyManager
|
||||
.addUnboundKeys(txn, new SecretKey(s.getMasterKey()),
|
||||
timestamp, s.getRemote().alice);
|
||||
keyManager.bindKeys(txn, c.getId(), keys);
|
||||
|
||||
// add signed transport properties for the contact
|
||||
//noinspection ConstantConditions
|
||||
transportPropertyManager.addRemoteProperties(txn, c.getId(),
|
||||
s.getRemote().transportProperties);
|
||||
|
||||
// send ACTIVATE message with a MAC
|
||||
byte[] mac = crypto.activateMac(s);
|
||||
Message sent = sendActivateMessage(txn, s, getLocalTimestamp(s), mac);
|
||||
|
||||
if (contactAdded) {
|
||||
// Broadcast IntroductionSucceededEvent, because contact got added
|
||||
IntroductionSucceededEvent e = new IntroductionSucceededEvent(c);
|
||||
txn.attach(e);
|
||||
}
|
||||
|
||||
// Move to AWAIT_ACTIVATE state and clear key material from session
|
||||
return IntroduceeSession.awaitActivate(s, m, sent, keys);
|
||||
@@ -449,23 +467,17 @@ class IntroduceeProtocolEngine
|
||||
if (isInvalidDependency(s, m.getPreviousMessageId()))
|
||||
return abort(txn, s);
|
||||
|
||||
// Only bind keys if contact did not exist during AUTH
|
||||
if (s.getTransportKeys() != null) {
|
||||
Contact c =
|
||||
contactManager.getContact(txn, s.getRemoteAuthor().getId(),
|
||||
identityManager.getLocalAuthor(txn).getId());
|
||||
keyManager.bindKeys(txn, c.getId(), s.getTransportKeys());
|
||||
keyManager.activateKeys(txn, s.getTransportKeys());
|
||||
|
||||
// TODO remove when concept of inactive contacts is removed
|
||||
contactManager.setContactActive(txn, c.getId(), true);
|
||||
|
||||
// TODO move this to AUTH step when concept of inactive contacts is removed
|
||||
// Broadcast IntroductionSucceededEvent
|
||||
IntroductionSucceededEvent e = new IntroductionSucceededEvent(c);
|
||||
txn.attach(e);
|
||||
// Validate MAC
|
||||
try {
|
||||
crypto.verifyActivateMac(m.getMac(), s);
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO remove transport keys?
|
||||
return abort(txn, s);
|
||||
}
|
||||
|
||||
// Activate transport keys
|
||||
keyManager.activateKeys(txn, s.getTransportKeys());
|
||||
|
||||
// Move back to START state
|
||||
return IntroduceeSession
|
||||
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
|
||||
@@ -513,12 +525,6 @@ class IntroduceeProtocolEngine
|
||||
s.getRequestTimestamp());
|
||||
}
|
||||
|
||||
private boolean isAlice(Transaction txn, IntroduceeSession s)
|
||||
throws DbException {
|
||||
Author localAuthor = identityManager.getLocalAuthor(txn);
|
||||
return crypto.isAlice(localAuthor.getId(), s.getRemoteAuthor().getId());
|
||||
}
|
||||
|
||||
private void addSessionId(Transaction txn, MessageId m, SessionId sessionId)
|
||||
throws DbException {
|
||||
BdfDictionary meta = new BdfDictionary();
|
||||
|
||||
@@ -27,68 +27,44 @@ class IntroduceeSession extends Session<IntroduceeState>
|
||||
implements PeerSession {
|
||||
|
||||
private final GroupId contactGroupId;
|
||||
private final long localTimestamp, acceptTimestamp, remoteAcceptTimestamp;
|
||||
private final Author introducer;
|
||||
private final Local local;
|
||||
private final Remote remote;
|
||||
@Nullable
|
||||
private final MessageId lastLocalMessageId, lastRemoteMessageId;
|
||||
private final Author introducer, remoteAuthor;
|
||||
@Nullable
|
||||
private final byte[] ephemeralPublicKey, ephemeralPrivateKey;
|
||||
@Nullable
|
||||
private final byte[] masterKey, remoteEphemeralPublicKey;
|
||||
@Nullable
|
||||
private final Map<TransportId, TransportProperties> transportProperties;
|
||||
@Nullable
|
||||
private final Map<TransportId, TransportProperties>
|
||||
remoteTransportProperties;
|
||||
private final byte[] masterKey;
|
||||
@Nullable
|
||||
private final Map<TransportId, KeySetId> transportKeys;
|
||||
|
||||
IntroduceeSession(SessionId sessionId, IntroduceeState state,
|
||||
long requestTimestamp, GroupId contactGroupId,
|
||||
@Nullable MessageId lastLocalMessageId, long localTimestamp,
|
||||
@Nullable MessageId lastRemoteMessageId, Author introducer,
|
||||
@Nullable byte[] ephemeralPublicKey,
|
||||
@Nullable byte[] ephemeralPrivateKey,
|
||||
@Nullable Map<TransportId, TransportProperties> transportProperties,
|
||||
long acceptTimestamp, @Nullable byte[] masterKey,
|
||||
Author remoteAuthor,
|
||||
@Nullable byte[] remoteEphemeralPublicKey, @Nullable
|
||||
Map<TransportId, TransportProperties> remoteTransportProperties,
|
||||
long remoteAcceptTimestamp,
|
||||
long requestTimestamp, GroupId contactGroupId, Author introducer,
|
||||
Local local, Remote remote, @Nullable byte[] masterKey,
|
||||
@Nullable Map<TransportId, KeySetId> transportKeys) {
|
||||
super(sessionId, state, requestTimestamp);
|
||||
this.contactGroupId = contactGroupId;
|
||||
this.lastLocalMessageId = lastLocalMessageId;
|
||||
this.localTimestamp = localTimestamp;
|
||||
this.lastRemoteMessageId = lastRemoteMessageId;
|
||||
this.introducer = introducer;
|
||||
this.ephemeralPublicKey = ephemeralPublicKey;
|
||||
this.ephemeralPrivateKey = ephemeralPrivateKey;
|
||||
this.transportProperties = transportProperties;
|
||||
this.acceptTimestamp = acceptTimestamp;
|
||||
this.local = local;
|
||||
this.remote = remote;
|
||||
this.masterKey = masterKey;
|
||||
this.remoteAuthor = remoteAuthor;
|
||||
this.remoteEphemeralPublicKey = remoteEphemeralPublicKey;
|
||||
this.remoteTransportProperties = remoteTransportProperties;
|
||||
this.remoteAcceptTimestamp = remoteAcceptTimestamp;
|
||||
this.transportKeys = transportKeys;
|
||||
}
|
||||
|
||||
static IntroduceeSession getInitial(GroupId contactGroupId,
|
||||
SessionId sessionId, Author introducer, Author remoteAuthor) {
|
||||
return new IntroduceeSession(sessionId, START, -1, contactGroupId, null,
|
||||
-1, null, introducer, null, null, null, -1, null, remoteAuthor,
|
||||
null, null, -1, null);
|
||||
SessionId sessionId, Author introducer, boolean localIsAlice,
|
||||
Author remoteAuthor) {
|
||||
Local local =
|
||||
new Local(localIsAlice, null, -1, null, null, null, -1, null);
|
||||
Remote remote =
|
||||
new Remote(!localIsAlice, remoteAuthor, null, null, null, -1,
|
||||
null);
|
||||
return new IntroduceeSession(sessionId, START, -1, contactGroupId,
|
||||
introducer, local, remote, null, null);
|
||||
}
|
||||
|
||||
static IntroduceeSession addRemoteRequest(IntroduceeSession s,
|
||||
IntroduceeState state, RequestMessage m) {
|
||||
Remote remote = new Remote(s.remote, m.getMessageId());
|
||||
return new IntroduceeSession(s.getSessionId(), state, m.getTimestamp(),
|
||||
s.contactGroupId, s.lastLocalMessageId, s.localTimestamp,
|
||||
m.getMessageId(), s.introducer, s.ephemeralPublicKey,
|
||||
s.ephemeralPrivateKey, s.transportProperties, s.acceptTimestamp,
|
||||
s.masterKey, s.remoteAuthor, s.remoteEphemeralPublicKey,
|
||||
s.remoteTransportProperties, s.remoteAcceptTimestamp,
|
||||
s.contactGroupId, s.introducer, s.local, remote, s.masterKey,
|
||||
s.transportKeys);
|
||||
}
|
||||
|
||||
@@ -97,57 +73,66 @@ class IntroduceeSession extends Session<IntroduceeState>
|
||||
byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey,
|
||||
long acceptTimestamp,
|
||||
Map<TransportId, TransportProperties> transportProperties) {
|
||||
Local local = new Local(s.local.alice, acceptMessage.getId(),
|
||||
acceptMessage.getTimestamp(), ephemeralPublicKey,
|
||||
ephemeralPrivateKey, transportProperties, acceptTimestamp,
|
||||
null);
|
||||
return new IntroduceeSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), s.contactGroupId,
|
||||
acceptMessage.getId(), acceptMessage.getTimestamp(),
|
||||
s.lastRemoteMessageId, s.introducer, ephemeralPublicKey,
|
||||
ephemeralPrivateKey, transportProperties,
|
||||
acceptTimestamp, s.masterKey, s.remoteAuthor,
|
||||
s.remoteEphemeralPublicKey, s.remoteTransportProperties,
|
||||
s.remoteAcceptTimestamp, s.transportKeys);
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
||||
s.remote, s.masterKey, s.transportKeys);
|
||||
}
|
||||
|
||||
static IntroduceeSession addRemoteAccept(IntroduceeSession s,
|
||||
IntroduceeState state, AcceptMessage acceptMessage) {
|
||||
IntroduceeState state, AcceptMessage m) {
|
||||
Remote remote =
|
||||
new Remote(s.remote.alice, s.remote.author, m.getMessageId(),
|
||||
m.getEphemeralPublicKey(), m.getTransportProperties(),
|
||||
m.getAcceptTimestamp(), s.remote.macKey);
|
||||
return new IntroduceeSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.lastLocalMessageId,
|
||||
s.localTimestamp, acceptMessage.getMessageId(), s.introducer,
|
||||
s.ephemeralPublicKey, s.ephemeralPrivateKey,
|
||||
s.transportProperties, s.acceptTimestamp, s.masterKey,
|
||||
s.remoteAuthor, acceptMessage.getEphemeralPublicKey(),
|
||||
acceptMessage.getTransportProperties(),
|
||||
acceptMessage.getAcceptTimestamp(), s.transportKeys);
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer,
|
||||
s.local, remote, s.masterKey, s.transportKeys);
|
||||
}
|
||||
|
||||
static IntroduceeSession addLocalAuth(IntroduceeSession s,
|
||||
IntroduceeState state, SecretKey masterKey, Message m) {
|
||||
IntroduceeState state, Message m, SecretKey masterKey,
|
||||
SecretKey aliceMacKey, SecretKey bobMacKey) {
|
||||
// add mac key and sent message
|
||||
Local local = new Local(s.local.alice, m.getId(), m.getTimestamp(),
|
||||
s.local.ephemeralPublicKey, s.local.ephemeralPrivateKey,
|
||||
s.local.transportProperties, s.local.acceptTimestamp,
|
||||
s.local.alice ? aliceMacKey.getBytes() : bobMacKey.getBytes());
|
||||
// just add the mac key
|
||||
Remote remote = new Remote(s.remote.alice, s.remote.author,
|
||||
s.remote.lastMessageId, s.remote.ephemeralPublicKey,
|
||||
s.remote.transportProperties, s.remote.acceptTimestamp,
|
||||
s.remote.alice ? aliceMacKey.getBytes() : bobMacKey.getBytes());
|
||||
// add master key
|
||||
return new IntroduceeSession(s.getSessionId(), state,
|
||||
s.getRequestTimestamp(), s.contactGroupId, m.getId(),
|
||||
m.getTimestamp(), s.lastRemoteMessageId, s.introducer,
|
||||
s.ephemeralPublicKey, s.ephemeralPrivateKey,
|
||||
s.transportProperties, s.acceptTimestamp, masterKey.getBytes(),
|
||||
s.remoteAuthor, s.remoteEphemeralPublicKey,
|
||||
s.remoteTransportProperties, s.remoteAcceptTimestamp,
|
||||
s.transportKeys);
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
||||
remote, masterKey.getBytes(), s.transportKeys);
|
||||
}
|
||||
|
||||
static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m,
|
||||
Message sent, @Nullable Map<TransportId, KeySetId> transportKeys) {
|
||||
Local local = new Local(s.local, sent.getId(), sent.getTimestamp());
|
||||
Remote remote = new Remote(s.remote, m.getMessageId());
|
||||
return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE,
|
||||
s.getRequestTimestamp(), s.contactGroupId, sent.getId(),
|
||||
sent.getTimestamp(), m.getMessageId(), s.introducer, null, null,
|
||||
null, s.acceptTimestamp, null, s.getRemoteAuthor(), null, null,
|
||||
s.remoteAcceptTimestamp, transportKeys);
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
||||
remote, null, transportKeys);
|
||||
}
|
||||
|
||||
static IntroduceeSession clear(IntroduceeSession s,
|
||||
@Nullable MessageId lastLocalMessageId, long localTimestamp,
|
||||
@Nullable MessageId lastRemoteMessageId) {
|
||||
Local local =
|
||||
new Local(s.local.alice, lastLocalMessageId, localTimestamp,
|
||||
null, null, null, -1, null);
|
||||
Remote remote =
|
||||
new Remote(s.remote.alice, s.remote.author, lastRemoteMessageId,
|
||||
null, null, -1, null);
|
||||
return new IntroduceeSession(s.getSessionId(), START,
|
||||
s.getRequestTimestamp(), s.getContactGroupId(),
|
||||
lastLocalMessageId, localTimestamp, lastRemoteMessageId,
|
||||
s.getIntroducer(), null, null, null, -1, null,
|
||||
s.getRemoteAuthor(), null, null, -1, null);
|
||||
s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
|
||||
remote, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,45 +140,38 @@ class IntroduceeSession extends Session<IntroduceeState>
|
||||
return INTRODUCEE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupId getContactGroupId() {
|
||||
return contactGroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLocalTimestamp() {
|
||||
return localTimestamp;
|
||||
return local.lastMessageTimestamp;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MessageId getLastLocalMessageId() {
|
||||
return lastLocalMessageId;
|
||||
return local.lastMessageId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MessageId getLastRemoteMessageId() {
|
||||
return lastRemoteMessageId;
|
||||
return remote.lastMessageId;
|
||||
}
|
||||
|
||||
Author getIntroducer() {
|
||||
return introducer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
byte[] getEphemeralPublicKey() {
|
||||
return ephemeralPublicKey;
|
||||
public Local getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
byte[] getEphemeralPrivateKey() {
|
||||
return ephemeralPrivateKey;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Map<TransportId, TransportProperties> getTransportProperties() {
|
||||
return transportProperties;
|
||||
}
|
||||
|
||||
long getAcceptTimestamp() {
|
||||
return acceptTimestamp;
|
||||
public Remote getRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -201,27 +179,77 @@ class IntroduceeSession extends Session<IntroduceeState>
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
Author getRemoteAuthor() {
|
||||
return remoteAuthor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
byte[] getRemotePublicKey() {
|
||||
return remoteEphemeralPublicKey;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Map<TransportId, TransportProperties> getRemoteTransportProperties() {
|
||||
return remoteTransportProperties;
|
||||
}
|
||||
|
||||
long getRemoteAcceptTimestamp() {
|
||||
return remoteAcceptTimestamp;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Map<TransportId, KeySetId> getTransportKeys() {
|
||||
return transportKeys;
|
||||
}
|
||||
|
||||
abstract static class Common {
|
||||
final boolean alice;
|
||||
@Nullable
|
||||
final MessageId lastMessageId;
|
||||
@Nullable
|
||||
final byte[] ephemeralPublicKey;
|
||||
@Nullable
|
||||
final Map<TransportId, TransportProperties> transportProperties;
|
||||
final long acceptTimestamp;
|
||||
@Nullable
|
||||
final byte[] macKey;
|
||||
|
||||
private Common(boolean alice, @Nullable MessageId lastMessageId,
|
||||
@Nullable byte[] ephemeralPublicKey, @Nullable
|
||||
Map<TransportId, TransportProperties> transportProperties,
|
||||
long acceptTimestamp, @Nullable byte[] macKey) {
|
||||
this.alice = alice;
|
||||
this.lastMessageId = lastMessageId;
|
||||
this.ephemeralPublicKey = ephemeralPublicKey;
|
||||
this.transportProperties = transportProperties;
|
||||
this.acceptTimestamp = acceptTimestamp;
|
||||
this.macKey = macKey;
|
||||
}
|
||||
}
|
||||
|
||||
static class Local extends Common {
|
||||
final long lastMessageTimestamp;
|
||||
@Nullable
|
||||
final byte[] ephemeralPrivateKey;
|
||||
|
||||
Local(boolean alice, @Nullable MessageId lastMessageId,
|
||||
long lastMessageTimestamp, @Nullable byte[] ephemeralPublicKey,
|
||||
@Nullable byte[] ephemeralPrivateKey, @Nullable
|
||||
Map<TransportId, TransportProperties> transportProperties,
|
||||
long acceptTimestamp, @Nullable byte[] macKey) {
|
||||
super(alice, lastMessageId, ephemeralPublicKey, transportProperties,
|
||||
acceptTimestamp, macKey);
|
||||
this.lastMessageTimestamp = lastMessageTimestamp;
|
||||
this.ephemeralPrivateKey = ephemeralPrivateKey;
|
||||
}
|
||||
|
||||
private Local(Local s, @Nullable MessageId lastMessageId,
|
||||
long lastMessageTimestamp) {
|
||||
this(s.alice, lastMessageId, lastMessageTimestamp,
|
||||
s.ephemeralPublicKey, s.ephemeralPrivateKey,
|
||||
s.transportProperties, s.acceptTimestamp, s.macKey);
|
||||
}
|
||||
}
|
||||
|
||||
static class Remote extends Common {
|
||||
final Author author;
|
||||
|
||||
Remote(boolean alice, Author author,
|
||||
@Nullable MessageId lastMessageId,
|
||||
@Nullable byte[] ephemeralPublicKey, @Nullable
|
||||
Map<TransportId, TransportProperties> transportProperties,
|
||||
long acceptTimestamp, @Nullable byte[] macKey) {
|
||||
super(alice, lastMessageId, ephemeralPublicKey, transportProperties,
|
||||
acceptTimestamp, macKey);
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
private Remote(Remote s, @Nullable MessageId lastMessageId) {
|
||||
this(s.alice, s.author, lastMessageId, s.ephemeralPublicKey,
|
||||
s.transportProperties, s.acceptTimestamp, s.macKey);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ class IntroducerProtocolEngine
|
||||
// Forward ACTIVATE message
|
||||
Introducee i = getOtherIntroducee(s, m.getGroupId());
|
||||
long timestamp = getLocalTimestamp(s, i);
|
||||
Message sent = sendActivateMessage(txn, i, timestamp);
|
||||
Message sent = sendActivateMessage(txn, i, timestamp, m.getMac());
|
||||
|
||||
// Move to the next state
|
||||
IntroducerState state = START;
|
||||
|
||||
@@ -30,16 +30,19 @@ interface IntroductionConstants {
|
||||
|
||||
// Session Keys Introducee
|
||||
String SESSION_KEY_INTRODUCER = "introducer";
|
||||
String SESSION_KEY_LOCAL = "local";
|
||||
String SESSION_KEY_REMOTE = "remote";
|
||||
|
||||
String SESSION_KEY_MASTER_KEY = "masterKey";
|
||||
String SESSION_KEY_TRANSPORT_KEYS = "transportKeys";
|
||||
|
||||
String SESSION_KEY_ALICE = "alice";
|
||||
String SESSION_KEY_EPHEMERAL_PUBLIC_KEY = "ephemeralPublicKey";
|
||||
String SESSION_KEY_EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey";
|
||||
String SESSION_KEY_TRANSPORT_PROPERTIES = "transportProperties";
|
||||
String SESSION_KEY_ACCEPT_TIMESTAMP = "acceptTimestamp";
|
||||
String SESSION_KEY_MASTER_KEY = "masterKey";
|
||||
String SESSION_KEY_MAC_KEY = "macKey";
|
||||
|
||||
String SESSION_KEY_REMOTE_AUTHOR = "remoteAuthor";
|
||||
String SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY = "remoteEphemeralPublicKey";
|
||||
String SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES =
|
||||
"remoteTransportProperties";
|
||||
String SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP = "remoteAcceptTimestamp";
|
||||
String SESSION_KEY_TRANSPORT_KEYS = "transportKeys";
|
||||
|
||||
}
|
||||
|
||||
@@ -30,16 +30,15 @@ interface IntroductionCrypto {
|
||||
/**
|
||||
* Derives a session master key for Alice or Bob.
|
||||
*
|
||||
* @param alice true if the session owner is Alice
|
||||
* @return The secret master key
|
||||
*/
|
||||
SecretKey deriveMasterKey(IntroduceeSession s, boolean alice)
|
||||
SecretKey deriveMasterKey(IntroduceeSession s)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Derives a MAC key from the session's master key for Alice or Bob.
|
||||
*
|
||||
* @param masterKey The key returned by {@link #deriveMasterKey(IntroduceeSession, boolean)}
|
||||
* @param masterKey The key returned by {@link #deriveMasterKey(IntroduceeSession)}
|
||||
* @param alice true for Alice's MAC key, false for Bob's
|
||||
* @return The MAC key
|
||||
*/
|
||||
@@ -49,17 +48,17 @@ interface IntroductionCrypto {
|
||||
* Generates a MAC that covers both introducee's ephemeral public keys,
|
||||
* transport properties, Author IDs and timestamps of the accept message.
|
||||
*/
|
||||
byte[] mac(SecretKey macKey, IntroduceeSession s, AuthorId localAuthorId,
|
||||
boolean alice);
|
||||
byte[] authMac(SecretKey macKey, IntroduceeSession s,
|
||||
AuthorId localAuthorId, boolean alice);
|
||||
|
||||
/**
|
||||
* Verifies a received MAC
|
||||
*
|
||||
* @param mac The MAC to verify
|
||||
* as returned by {@link #deriveMasterKey(IntroduceeSession, boolean)}
|
||||
* as returned by {@link #deriveMasterKey(IntroduceeSession)}
|
||||
* @throws GeneralSecurityException if the verification fails
|
||||
*/
|
||||
void verifyMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId)
|
||||
void verifyAuthMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
@@ -82,4 +81,17 @@ interface IntroductionCrypto {
|
||||
void verifySignature(byte[] signature, IntroduceeSession s,
|
||||
AuthorId localAuthorId) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Generates a MAC using the local MAC key.
|
||||
*/
|
||||
byte[] activateMac(IntroduceeSession s);
|
||||
|
||||
/**
|
||||
* Verifies a MAC from an ACTIVATE message.
|
||||
*
|
||||
* @throws GeneralSecurityException if the verification fails
|
||||
*/
|
||||
void verifyActivateMac(byte[] mac, IntroduceeSession s)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_ACTIVATE_MAC;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_ALICE_MAC_KEY;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_MAC;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_NONCE;
|
||||
@@ -74,10 +75,14 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public SecretKey deriveMasterKey(IntroduceeSession s, boolean alice)
|
||||
public SecretKey deriveMasterKey(IntroduceeSession s)
|
||||
throws GeneralSecurityException {
|
||||
return deriveMasterKey(s.getEphemeralPublicKey(),
|
||||
s.getEphemeralPrivateKey(), s.getRemotePublicKey(), alice);
|
||||
return deriveMasterKey(
|
||||
s.getLocal().ephemeralPublicKey,
|
||||
s.getLocal().ephemeralPrivateKey,
|
||||
s.getRemote().ephemeralPublicKey,
|
||||
s.getLocal().alice
|
||||
);
|
||||
}
|
||||
|
||||
SecretKey deriveMasterKey(byte[] publicKey, byte[] privateKey,
|
||||
@@ -108,16 +113,17 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public byte[] mac(SecretKey macKey, IntroduceeSession s,
|
||||
public byte[] authMac(SecretKey macKey, IntroduceeSession s,
|
||||
AuthorId localAuthorId, boolean alice) {
|
||||
return mac(macKey, s.getIntroducer().getId(), localAuthorId,
|
||||
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
|
||||
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
|
||||
s.getRemotePublicKey(), s.getTransportProperties(),
|
||||
s.getRemoteTransportProperties(), alice);
|
||||
return authMac(macKey, s.getIntroducer().getId(), localAuthorId,
|
||||
s.getRemote().author.getId(), s.getLocal().acceptTimestamp,
|
||||
s.getRemote().acceptTimestamp, s.getLocal().ephemeralPublicKey,
|
||||
s.getRemote().ephemeralPublicKey,
|
||||
s.getLocal().transportProperties,
|
||||
s.getRemote().transportProperties, alice);
|
||||
}
|
||||
|
||||
byte[] mac(SecretKey macKey, AuthorId introducerId,
|
||||
byte[] authMac(SecretKey macKey, AuthorId introducerId,
|
||||
AuthorId localAuthorId, AuthorId remoteAuthorId,
|
||||
long acceptTimestamp, long remoteAcceptTimestamp,
|
||||
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
|
||||
@@ -125,7 +131,7 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
Map<TransportId, TransportProperties> remoteTransportProperties,
|
||||
boolean alice) {
|
||||
byte[] inputs =
|
||||
getMacInputs(introducerId, localAuthorId, remoteAuthorId,
|
||||
getAuthMacInputs(introducerId, localAuthorId, remoteAuthorId,
|
||||
acceptTimestamp, remoteAcceptTimestamp,
|
||||
ephemeralPublicKey, remoteEphemeralPublicKey,
|
||||
transportProperties, remoteTransportProperties, alice);
|
||||
@@ -138,19 +144,20 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public void verifyMac(byte[] mac, IntroduceeSession s,
|
||||
public void verifyAuthMac(byte[] mac, IntroduceeSession s,
|
||||
AuthorId localAuthorId)
|
||||
throws GeneralSecurityException {
|
||||
boolean alice = isAlice(localAuthorId, s.getRemoteAuthor().getId());
|
||||
verifyMac(mac, new SecretKey(s.getMasterKey()),
|
||||
boolean alice = isAlice(localAuthorId, s.getRemote().author.getId());
|
||||
verifyAuthMac(mac, new SecretKey(s.getRemote().macKey),
|
||||
s.getIntroducer().getId(), localAuthorId,
|
||||
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(),
|
||||
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(),
|
||||
s.getRemotePublicKey(), s.getTransportProperties(),
|
||||
s.getRemoteTransportProperties(), !alice);
|
||||
s.getRemote().author.getId(), s.getLocal().acceptTimestamp,
|
||||
s.getRemote().acceptTimestamp, s.getLocal().ephemeralPublicKey,
|
||||
s.getRemote().ephemeralPublicKey,
|
||||
s.getLocal().transportProperties,
|
||||
s.getRemote().transportProperties, !alice);
|
||||
}
|
||||
|
||||
void verifyMac(byte[] mac, SecretKey masterKey,
|
||||
void verifyAuthMac(byte[] mac, SecretKey macKey,
|
||||
AuthorId introducerId, AuthorId localAuthorId,
|
||||
AuthorId remoteAuthorId, long acceptTimestamp,
|
||||
long remoteAcceptTimestamp, byte[] ephemeralPublicKey,
|
||||
@@ -158,9 +165,8 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
Map<TransportId, TransportProperties> transportProperties,
|
||||
Map<TransportId, TransportProperties> remoteTransportProperties,
|
||||
boolean alice) throws GeneralSecurityException {
|
||||
SecretKey macKey = deriveMacKey(masterKey, alice);
|
||||
byte[] inputs =
|
||||
getMacInputs(introducerId, localAuthorId, remoteAuthorId,
|
||||
getAuthMacInputs(introducerId, localAuthorId, remoteAuthorId,
|
||||
acceptTimestamp, remoteAcceptTimestamp,
|
||||
ephemeralPublicKey, remoteEphemeralPublicKey,
|
||||
transportProperties, remoteTransportProperties, !alice);
|
||||
@@ -169,7 +175,7 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getMacInputs(AuthorId introducerId,
|
||||
private byte[] getAuthMacInputs(AuthorId introducerId,
|
||||
AuthorId localAuthorId, AuthorId remoteAuthorId,
|
||||
long acceptTimestamp, long remoteAcceptTimestamp,
|
||||
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
|
||||
@@ -214,9 +220,8 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public void verifySignature(byte[] signature, IntroduceeSession s,
|
||||
AuthorId localAuthorId) throws GeneralSecurityException {
|
||||
boolean alice = isAlice(s.getRemoteAuthor().getId(), localAuthorId);
|
||||
SecretKey macKey = deriveMacKey(new SecretKey(s.getMasterKey()), alice);
|
||||
verifySignature(macKey, s.getRemoteAuthor().getPublicKey(), signature);
|
||||
SecretKey macKey = new SecretKey(s.getRemote().macKey);
|
||||
verifySignature(macKey, s.getRemote().author.getPublicKey(), signature);
|
||||
}
|
||||
|
||||
void verifySignature(SecretKey macKey, byte[] publicKey,
|
||||
@@ -232,4 +237,33 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
|
||||
return crypto.mac(LABEL_AUTH_NONCE, macKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] activateMac(IntroduceeSession s) {
|
||||
if (s.getLocal().macKey == null)
|
||||
throw new AssertionError("Local MAC key is null");
|
||||
return activateMac(new SecretKey(s.getLocal().macKey));
|
||||
}
|
||||
|
||||
byte[] activateMac(SecretKey macKey) {
|
||||
return crypto.mac(
|
||||
LABEL_ACTIVATE_MAC,
|
||||
macKey
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyActivateMac(byte[] mac, IntroduceeSession s)
|
||||
throws GeneralSecurityException {
|
||||
if (s.getRemote().macKey == null)
|
||||
throw new AssertionError("Remote MAC key is null");
|
||||
verifyActivateMac(mac, new SecretKey(s.getRemote().macKey));
|
||||
}
|
||||
|
||||
void verifyActivateMac(byte[] mac, SecretKey macKey)
|
||||
throws GeneralSecurityException {
|
||||
if (!crypto.verifyMac(mac, LABEL_ACTIVATE_MAC, macKey)) {
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -190,8 +190,10 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
Author remote = messageParser.parseRequestMessage(m, body).getAuthor();
|
||||
if (local.equals(remote)) throw new FormatException();
|
||||
SessionId sessionId = crypto.getSessionId(introducer, local, remote);
|
||||
boolean alice = crypto.isAlice(local.getId(), remote.getId());
|
||||
return IntroduceeSession
|
||||
.getInitial(m.getGroupId(), sessionId, introducer, remote);
|
||||
.getInitial(m.getGroupId(), sessionId, introducer, alice,
|
||||
remote);
|
||||
}
|
||||
|
||||
private <S extends Session> S handleMessage(Transaction txn, Message m,
|
||||
@@ -441,7 +443,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
IntroduceeSession session = sessionParser
|
||||
.parseIntroduceeSession(contactGroupId, bdfSession);
|
||||
sessionId = session.getSessionId();
|
||||
author = session.getRemoteAuthor();
|
||||
author = session.getRemote().author;
|
||||
} else throw new AssertionError();
|
||||
Message msg = clientHelper.getMessage(txn, m);
|
||||
BdfList body = clientHelper.getMessageAsList(txn, m);
|
||||
@@ -481,7 +483,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
|
||||
IntroduceeSession session = sessionParser
|
||||
.parseIntroduceeSession(contactGroupId, bdfSession);
|
||||
sessionId = session.getSessionId();
|
||||
author = session.getRemoteAuthor();
|
||||
author = session.getRemote().author;
|
||||
} else throw new AssertionError();
|
||||
return new IntroductionResponse(sessionId, m, contactGroupId,
|
||||
role, meta.getTimestamp(), meta.isLocal(), status.isSent(),
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH;
|
||||
import static org.briarproject.briar.introduction.MessageType.ACCEPT;
|
||||
import static org.briarproject.briar.introduction.MessageType.ACTIVATE;
|
||||
import static org.briarproject.briar.introduction.MessageType.AUTH;
|
||||
|
||||
|
||||
@@ -55,8 +56,9 @@ class IntroductionValidator extends BdfMessageValidator {
|
||||
return validateAcceptMessage(m, body);
|
||||
case AUTH:
|
||||
return validateAuthMessage(m, body);
|
||||
case DECLINE:
|
||||
case ACTIVATE:
|
||||
return validateActivateMessage(m, body);
|
||||
case DECLINE:
|
||||
case ABORT:
|
||||
return validateOtherMessage(type, m, body);
|
||||
default:
|
||||
@@ -149,6 +151,32 @@ class IntroductionValidator extends BdfMessageValidator {
|
||||
Collections.singletonList(dependency));
|
||||
}
|
||||
|
||||
private BdfMessageContext validateActivateMessage(Message m, BdfList body)
|
||||
throws FormatException {
|
||||
checkSize(body, 4);
|
||||
|
||||
byte[] sessionIdBytes = body.getRaw(1);
|
||||
checkLength(sessionIdBytes, UniqueId.LENGTH);
|
||||
|
||||
byte[] previousMessageId = body.getOptionalRaw(2);
|
||||
checkLength(previousMessageId, UniqueId.LENGTH);
|
||||
|
||||
byte[] mac = body.getOptionalRaw(3);
|
||||
checkLength(mac, MAC_BYTES);
|
||||
|
||||
SessionId sessionId = new SessionId(sessionIdBytes);
|
||||
BdfDictionary meta = messageEncoder
|
||||
.encodeMetadata(ACTIVATE, sessionId, m.getTimestamp(), false,
|
||||
false, false);
|
||||
if (previousMessageId == null) {
|
||||
return new BdfMessageContext(meta);
|
||||
} else {
|
||||
MessageId dependency = new MessageId(previousMessageId);
|
||||
return new BdfMessageContext(meta,
|
||||
Collections.singletonList(dependency));
|
||||
}
|
||||
}
|
||||
|
||||
private BdfMessageContext validateOtherMessage(MessageType type,
|
||||
Message m, BdfList body) throws FormatException {
|
||||
checkSize(body, 3);
|
||||
|
||||
@@ -47,7 +47,8 @@ interface MessageEncoder {
|
||||
byte[] mac, byte[] signature);
|
||||
|
||||
Message encodeActivateMessage(GroupId contactGroupId, long timestamp,
|
||||
@Nullable MessageId previousMessageId, SessionId sessionId);
|
||||
@Nullable MessageId previousMessageId, SessionId sessionId,
|
||||
byte[] mac);
|
||||
|
||||
Message encodeAbortMessage(GroupId contactGroupId, long timestamp,
|
||||
@Nullable MessageId previousMessageId, SessionId sessionId);
|
||||
|
||||
@@ -100,12 +100,7 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
clientHelper.toList(author),
|
||||
message
|
||||
);
|
||||
try {
|
||||
return messageFactory.createMessage(contactGroupId, timestamp,
|
||||
clientHelper.toByteArray(body));
|
||||
} catch (FormatException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return createMessage(contactGroupId, timestamp, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,14 +114,9 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
previousMessageId,
|
||||
ephemeralPublicKey,
|
||||
acceptTimestamp,
|
||||
encodeTransportProperties(transportProperties)
|
||||
clientHelper.toDictionary(transportProperties)
|
||||
);
|
||||
try {
|
||||
return messageFactory.createMessage(contactGroupId, timestamp,
|
||||
clientHelper.toByteArray(body));
|
||||
} catch (FormatException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return createMessage(contactGroupId, timestamp, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,19 +137,20 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
mac,
|
||||
signature
|
||||
);
|
||||
try {
|
||||
return messageFactory.createMessage(contactGroupId, timestamp,
|
||||
clientHelper.toByteArray(body));
|
||||
} catch (FormatException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return createMessage(contactGroupId, timestamp, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message encodeActivateMessage(GroupId contactGroupId, long timestamp,
|
||||
@Nullable MessageId previousMessageId, SessionId sessionId) {
|
||||
return encodeMessage(ACTIVATE, contactGroupId, sessionId, timestamp,
|
||||
previousMessageId);
|
||||
@Nullable MessageId previousMessageId, SessionId sessionId,
|
||||
byte[] mac) {
|
||||
BdfList body = BdfList.of(
|
||||
ACTIVATE.getValue(),
|
||||
sessionId,
|
||||
previousMessageId,
|
||||
mac
|
||||
);
|
||||
return createMessage(contactGroupId, timestamp, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,6 +168,11 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
sessionId,
|
||||
previousMessageId
|
||||
);
|
||||
return createMessage(contactGroupId, timestamp, body);
|
||||
}
|
||||
|
||||
private Message createMessage(GroupId contactGroupId, long timestamp,
|
||||
BdfList body) {
|
||||
try {
|
||||
return messageFactory.createMessage(contactGroupId, timestamp,
|
||||
clientHelper.toByteArray(body));
|
||||
@@ -185,13 +181,4 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
private BdfDictionary encodeTransportProperties(
|
||||
Map<TransportId, TransportProperties> map) {
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
for (Map.Entry<TransportId, TransportProperties> e : map.entrySet()) {
|
||||
d.put(e.getKey().getString(), e.getValue());
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -124,8 +124,9 @@ class MessageParserImpl implements MessageParser {
|
||||
SessionId sessionId = new SessionId(body.getRaw(1));
|
||||
byte[] previousMsgBytes = body.getRaw(2);
|
||||
MessageId previousMessageId = new MessageId(previousMsgBytes);
|
||||
byte[] mac = body.getRaw(3);
|
||||
return new ActivateMessage(m.getId(), m.getGroupId(), m.getTimestamp(),
|
||||
previousMessageId, sessionId);
|
||||
previousMessageId, sessionId, mac);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,7 @@ abstract class Session<S extends State> {
|
||||
|
||||
private final SessionId sessionId;
|
||||
private final S state;
|
||||
private long requestTimestamp;
|
||||
private final long requestTimestamp;
|
||||
|
||||
Session(SessionId sessionId, S state, long requestTimestamp) {
|
||||
this.sessionId = sessionId;
|
||||
@@ -30,7 +30,7 @@ abstract class Session<S extends State> {
|
||||
return state;
|
||||
}
|
||||
|
||||
public long getRequestTimestamp() {
|
||||
long getRequestTimestamp() {
|
||||
return requestTimestamp;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.briar.introduction.IntroduceeSession.Common;
|
||||
import org.briarproject.briar.introduction.IntroduceeSession.Local;
|
||||
import org.briarproject.briar.introduction.IntroduceeSession.Remote;
|
||||
import org.briarproject.briar.introduction.IntroducerSession.Introducee;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -19,6 +22,7 @@ import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ALICE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY;
|
||||
@@ -28,12 +32,12 @@ import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MAC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID;
|
||||
@@ -91,34 +95,43 @@ class SessionEncoderImpl implements SessionEncoder {
|
||||
@Override
|
||||
public BdfDictionary encodeIntroduceeSession(IntroduceeSession s) {
|
||||
BdfDictionary d = encodeSession(s);
|
||||
d.put(SESSION_KEY_LOCAL_TIMESTAMP, s.getLocalTimestamp());
|
||||
putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID,
|
||||
s.getLastLocalMessageId());
|
||||
putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID,
|
||||
s.getLastRemoteMessageId());
|
||||
d.put(SESSION_KEY_INTRODUCER, clientHelper.toList(s.getIntroducer()));
|
||||
d.put(SESSION_KEY_REMOTE_AUTHOR,
|
||||
clientHelper.toList(s.getRemoteAuthor()));
|
||||
putNullable(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY,
|
||||
s.getEphemeralPublicKey());
|
||||
putNullable(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY,
|
||||
s.getEphemeralPrivateKey());
|
||||
putNullable(d, SESSION_KEY_TRANSPORT_PROPERTIES,
|
||||
s.getTransportProperties() == null ? null :
|
||||
clientHelper.toDictionary(s.getTransportProperties()));
|
||||
d.put(SESSION_KEY_ACCEPT_TIMESTAMP, s.getAcceptTimestamp());
|
||||
d.put(SESSION_KEY_LOCAL, encodeLocal(s.getLocal()));
|
||||
d.put(SESSION_KEY_REMOTE, encodeRemote(s.getRemote()));
|
||||
putNullable(d, SESSION_KEY_MASTER_KEY, s.getMasterKey());
|
||||
putNullable(d, SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY,
|
||||
s.getRemotePublicKey());
|
||||
putNullable(d, SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES,
|
||||
s.getRemoteTransportProperties() == null ? null : clientHelper
|
||||
.toDictionary(s.getRemoteTransportProperties()));
|
||||
d.put(SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP, s.getRemoteAcceptTimestamp());
|
||||
putNullable(d, SESSION_KEY_TRANSPORT_KEYS,
|
||||
encodeTransportKeys(s.getTransportKeys()));
|
||||
return d;
|
||||
}
|
||||
|
||||
private BdfDictionary encodeCommon(Common s) {
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(SESSION_KEY_ALICE, s.alice);
|
||||
putNullable(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY, s.ephemeralPublicKey);
|
||||
putNullable(d, SESSION_KEY_TRANSPORT_PROPERTIES,
|
||||
s.transportProperties == null ? null :
|
||||
clientHelper.toDictionary(s.transportProperties));
|
||||
d.put(SESSION_KEY_ACCEPT_TIMESTAMP, s.acceptTimestamp);
|
||||
putNullable(d, SESSION_KEY_MAC_KEY, s.macKey);
|
||||
return d;
|
||||
}
|
||||
|
||||
private BdfDictionary encodeLocal(Local s) {
|
||||
BdfDictionary d = encodeCommon(s);
|
||||
d.put(SESSION_KEY_LOCAL_TIMESTAMP, s.lastMessageTimestamp);
|
||||
putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, s.lastMessageId);
|
||||
putNullable(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY,
|
||||
s.ephemeralPrivateKey);
|
||||
return d;
|
||||
}
|
||||
|
||||
private BdfDictionary encodeRemote(Remote s) {
|
||||
BdfDictionary d = encodeCommon(s);
|
||||
d.put(SESSION_KEY_REMOTE_AUTHOR, clientHelper.toList(s.author));
|
||||
putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID, s.lastMessageId);
|
||||
return d;
|
||||
}
|
||||
|
||||
private BdfDictionary encodeSession(Session s) {
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(SESSION_KEY_SESSION_ID, s.getSessionId());
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.briar.api.client.SessionId;
|
||||
import org.briarproject.briar.api.introduction.Role;
|
||||
import org.briarproject.briar.introduction.IntroduceeSession.Local;
|
||||
import org.briarproject.briar.introduction.IntroduceeSession.Remote;
|
||||
import org.briarproject.briar.introduction.IntroducerSession.Introducee;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -22,7 +24,10 @@ import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ALICE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY;
|
||||
@@ -32,20 +37,18 @@ import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MAC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_STATE;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
@@ -103,42 +106,55 @@ class SessionParserImpl implements SessionParser {
|
||||
SessionId sessionId = getSessionId(d);
|
||||
IntroduceeState state = IntroduceeState.fromValue(getState(d));
|
||||
long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP);
|
||||
Author introducer = getAuthor(d, SESSION_KEY_INTRODUCER);
|
||||
Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL));
|
||||
Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE));
|
||||
byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY);
|
||||
Map<TransportId, KeySetId> transportKeys = parseTransportKeys(
|
||||
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS));
|
||||
return new IntroduceeSession(sessionId, state, requestTimestamp,
|
||||
introducerGroupId, introducer, local, remote,
|
||||
masterKey, transportKeys);
|
||||
}
|
||||
|
||||
private Local parseLocal(BdfDictionary d) throws FormatException {
|
||||
boolean alice = d.getBoolean(SESSION_KEY_ALICE);
|
||||
MessageId lastLocalMessageId =
|
||||
getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID);
|
||||
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP);
|
||||
MessageId lastRemoteMessageId =
|
||||
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
|
||||
Author introducer = getAuthor(d, SESSION_KEY_INTRODUCER);
|
||||
byte[] ephemeralPublicKey =
|
||||
d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
|
||||
BdfDictionary tpDict =
|
||||
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
|
||||
byte[] ephemeralPrivateKey =
|
||||
d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY);
|
||||
Map<TransportId, TransportProperties> transportProperties =
|
||||
tpDict == null ? null : clientHelper
|
||||
.parseAndValidateTransportPropertiesMap(tpDict);
|
||||
long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP);
|
||||
byte[] macKey = d.getOptionalRaw(SESSION_KEY_MAC_KEY);
|
||||
return new Local(alice, lastLocalMessageId, localTimestamp,
|
||||
ephemeralPublicKey, ephemeralPrivateKey, transportProperties,
|
||||
acceptTimestamp, macKey);
|
||||
}
|
||||
|
||||
private Remote parseRemote(BdfDictionary d) throws FormatException {
|
||||
boolean alice = d.getBoolean(SESSION_KEY_ALICE);
|
||||
Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR);
|
||||
MessageId lastRemoteMessageId =
|
||||
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
|
||||
byte[] ephemeralPublicKey =
|
||||
d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
|
||||
BdfDictionary tpDict =
|
||||
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
|
||||
Map<TransportId, TransportProperties> transportProperties =
|
||||
tpDict == null ? null : clientHelper
|
||||
.parseAndValidateTransportPropertiesMap(tpDict);
|
||||
long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP);
|
||||
byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY);
|
||||
Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR);
|
||||
byte[] remoteEphemeralPublicKey =
|
||||
d.getOptionalRaw(SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY);
|
||||
BdfDictionary rptDict = d.getOptionalDictionary(
|
||||
SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES);
|
||||
Map<TransportId, TransportProperties> remoteTransportProperties =
|
||||
rptDict == null ? null : clientHelper
|
||||
.parseAndValidateTransportPropertiesMap(rptDict);
|
||||
long remoteAcceptTimestamp =
|
||||
d.getLong(SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP);
|
||||
Map<TransportId, KeySetId> transportKeys = parseTransportKeys(
|
||||
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS));
|
||||
return new IntroduceeSession(sessionId, state, requestTimestamp,
|
||||
introducerGroupId, lastLocalMessageId, localTimestamp,
|
||||
lastRemoteMessageId, introducer, ephemeralPublicKey,
|
||||
ephemeralPrivateKey, transportProperties, acceptTimestamp,
|
||||
masterKey, remoteAuthor, remoteEphemeralPublicKey,
|
||||
remoteTransportProperties, remoteAcceptTimestamp,
|
||||
transportKeys);
|
||||
byte[] macKey = d.getOptionalRaw(SESSION_KEY_MAC_KEY);
|
||||
return new Remote(alice, remoteAuthor, lastRemoteMessageId,
|
||||
ephemeralPublicKey, transportProperties, acceptTimestamp,
|
||||
macKey);
|
||||
}
|
||||
|
||||
private int getState(BdfDictionary d) throws FormatException {
|
||||
|
||||
@@ -96,35 +96,35 @@ public class IntroductionCryptoImplTest extends BrambleTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliceMac() throws Exception {
|
||||
public void testAliceAuthMac() throws Exception {
|
||||
SecretKey aliceMacKey = crypto.deriveMacKey(masterKey, true);
|
||||
byte[] aliceMac =
|
||||
crypto.mac(aliceMacKey, introducer.getId(), alice.getId(),
|
||||
crypto.authMac(aliceMacKey, introducer.getId(), alice.getId(),
|
||||
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp,
|
||||
aliceEphemeral.getPublic().getEncoded(),
|
||||
bobEphemeral.getPublic().getEncoded(), aliceTransport,
|
||||
bobTransport, true);
|
||||
|
||||
crypto.verifyMac(aliceMac, masterKey, introducer.getId(), bob.getId(),
|
||||
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp,
|
||||
bobEphemeral.getPublic().getEncoded(),
|
||||
crypto.verifyAuthMac(aliceMac, aliceMacKey, introducer.getId(),
|
||||
bob.getId(), alice.getId(), bobAcceptTimestamp,
|
||||
aliceAcceptTimestamp, bobEphemeral.getPublic().getEncoded(),
|
||||
aliceEphemeral.getPublic().getEncoded(), bobTransport,
|
||||
aliceTransport, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBobMac() throws Exception {
|
||||
public void testBobAuthMac() throws Exception {
|
||||
SecretKey bobMacKey = crypto.deriveMacKey(masterKey, false);
|
||||
byte[] bobMac =
|
||||
crypto.mac(bobMacKey, introducer.getId(), bob.getId(),
|
||||
crypto.authMac(bobMacKey, introducer.getId(), bob.getId(),
|
||||
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp,
|
||||
bobEphemeral.getPublic().getEncoded(),
|
||||
aliceEphemeral.getPublic().getEncoded(), bobTransport,
|
||||
aliceTransport, false);
|
||||
|
||||
crypto.verifyMac(bobMac, masterKey, introducer.getId(), alice.getId(),
|
||||
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp,
|
||||
aliceEphemeral.getPublic().getEncoded(),
|
||||
crypto.verifyAuthMac(bobMac, bobMacKey, introducer.getId(),
|
||||
alice.getId(), bob.getId(), aliceAcceptTimestamp,
|
||||
bobAcceptTimestamp, aliceEphemeral.getPublic().getEncoded(),
|
||||
bobEphemeral.getPublic().getEncoded(), aliceTransport,
|
||||
bobTransport, false);
|
||||
}
|
||||
@@ -139,4 +139,20 @@ public class IntroductionCryptoImplTest extends BrambleTestCase {
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliceActivateMac() throws Exception {
|
||||
SecretKey aliceMacKey = crypto.deriveMacKey(masterKey, true);
|
||||
byte[] aliceMac = crypto.activateMac(aliceMacKey);
|
||||
|
||||
crypto.verifyActivateMac(aliceMac, aliceMacKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBobActivateMac() throws Exception {
|
||||
SecretKey bobMacKey = crypto.deriveMacKey(masterKey, false);
|
||||
byte[] bobMac = crypto.activateMac(bobMacKey);
|
||||
|
||||
crypto.verifyActivateMac(bobMac, bobMacKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -170,16 +170,6 @@ public class IntroductionIntegrationTest
|
||||
sync1To0(1, true);
|
||||
sync0To2(1, true);
|
||||
|
||||
// assert that introducee2 added introducee1
|
||||
Contact contact1From2 = c2.getContactManager()
|
||||
.getContact(author1.getId(), author2.getId());
|
||||
|
||||
// assert that introducee2 did add transport properties
|
||||
// TODO check when notion of inactive contacts has been removed
|
||||
// TransportProperties tp2 = c2.getTransportPropertyManager()
|
||||
// .getRemoteProperties(contact1From2.getId(), TRANSPORT_ID);
|
||||
// assertFalse(tp2.isEmpty());
|
||||
|
||||
// assert that introducee2 did add the transport keys
|
||||
IntroduceeSession session2 = getIntroduceeSession(c2.getClientHelper(),
|
||||
introductionManager2.getContactGroup(contact0From2).getId());
|
||||
@@ -194,7 +184,7 @@ public class IntroductionIntegrationTest
|
||||
IntroduceeSession session1 = getIntroduceeSession(c1.getClientHelper(),
|
||||
introductionManager1.getContactGroup(contact0From1).getId());
|
||||
assertNull(session1.getMasterKey());
|
||||
assertNull(session1.getEphemeralPrivateKey());
|
||||
assertNull(session1.getLocal().ephemeralPrivateKey);
|
||||
assertNull(session1.getTransportKeys());
|
||||
|
||||
// sync second ACTIVATE and its forward
|
||||
@@ -533,16 +523,6 @@ public class IntroductionIntegrationTest
|
||||
sync1To0(1, true);
|
||||
sync0To2(1, true);
|
||||
|
||||
// assert that introducee2 did not add any transport properties
|
||||
TransportProperties tp2 = c2.getTransportPropertyManager()
|
||||
.getRemoteProperties(contactId1From2, TRANSPORT_ID);
|
||||
assertTrue(tp2.isEmpty());
|
||||
|
||||
// assert that introducee2 did not add any transport keys
|
||||
IntroduceeSession session2 = getIntroduceeSession(c2.getClientHelper(),
|
||||
introductionManager2.getContactGroup(contact0From2).getId());
|
||||
assertNull(session2.getTransportKeys());
|
||||
|
||||
// sync second AUTH and its forward as well as the following ACTIVATE
|
||||
sync2To0(2, true);
|
||||
sync0To1(2, true);
|
||||
|
||||
@@ -312,7 +312,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
|
||||
@Test
|
||||
public void testAcceptsActivate() throws Exception {
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
|
||||
previousMsgId.getBytes());
|
||||
previousMsgId.getBytes(), mac);
|
||||
|
||||
expectEncodeMetadata(ACTIVATE);
|
||||
BdfMessageContext messageContext =
|
||||
@@ -323,27 +323,37 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testRejectsTooShortBodyForActivate() throws Exception {
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes());
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
|
||||
previousMsgId.getBytes());
|
||||
validator.validateMessage(message, group, body);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testRejectsTooLongBodyForActivate() throws Exception {
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
|
||||
previousMsgId.getBytes(), null);
|
||||
previousMsgId.getBytes(), mac, null);
|
||||
validator.validateMessage(message, group, body);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testRejectsInvalidSessionIdForActivate() throws Exception {
|
||||
BdfList body =
|
||||
BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes());
|
||||
BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes(),
|
||||
mac);
|
||||
validator.validateMessage(message, group, body);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testRejectsInvalidPreviousMsgIdForActivate() throws Exception {
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), 1);
|
||||
BdfList body =
|
||||
BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), 1, mac);
|
||||
validator.validateMessage(message, group, body);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testRejectsInvalidMacForActivate() throws Exception {
|
||||
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
|
||||
previousMsgId.getBytes(), getRandomBytes(MAC_BYTES - 1));
|
||||
validator.validateMessage(message, group, body);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,17 +165,17 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
sessionId, ephemeralPublicKey, acceptTimestamp,
|
||||
transportProperties);
|
||||
validator.validateMessage(m, group, clientHelper.toList(m));
|
||||
AcceptMessage rm =
|
||||
AcceptMessage am =
|
||||
messageParser.parseAcceptMessage(m, clientHelper.toList(m));
|
||||
|
||||
assertEquals(m.getId(), rm.getMessageId());
|
||||
assertEquals(m.getGroupId(), rm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), rm.getTimestamp());
|
||||
assertEquals(previousMsgId, rm.getPreviousMessageId());
|
||||
assertEquals(sessionId, rm.getSessionId());
|
||||
assertArrayEquals(ephemeralPublicKey, rm.getEphemeralPublicKey());
|
||||
assertEquals(acceptTimestamp, rm.getAcceptTimestamp());
|
||||
assertEquals(transportProperties, rm.getTransportProperties());
|
||||
assertEquals(m.getId(), am.getMessageId());
|
||||
assertEquals(m.getGroupId(), am.getGroupId());
|
||||
assertEquals(m.getTimestamp(), am.getTimestamp());
|
||||
assertEquals(previousMsgId, am.getPreviousMessageId());
|
||||
assertEquals(sessionId, am.getSessionId());
|
||||
assertArrayEquals(ephemeralPublicKey, am.getEphemeralPublicKey());
|
||||
assertEquals(acceptTimestamp, am.getAcceptTimestamp());
|
||||
assertEquals(transportProperties, am.getTransportProperties());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -184,14 +184,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
.encodeDeclineMessage(groupId, timestamp, previousMsgId,
|
||||
sessionId);
|
||||
validator.validateMessage(m, group, clientHelper.toList(m));
|
||||
DeclineMessage rm =
|
||||
DeclineMessage dm =
|
||||
messageParser.parseDeclineMessage(m, clientHelper.toList(m));
|
||||
|
||||
assertEquals(m.getId(), rm.getMessageId());
|
||||
assertEquals(m.getGroupId(), rm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), rm.getTimestamp());
|
||||
assertEquals(previousMsgId, rm.getPreviousMessageId());
|
||||
assertEquals(sessionId, rm.getSessionId());
|
||||
assertEquals(m.getId(), dm.getMessageId());
|
||||
assertEquals(m.getGroupId(), dm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), dm.getTimestamp());
|
||||
assertEquals(previousMsgId, dm.getPreviousMessageId());
|
||||
assertEquals(sessionId, dm.getSessionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,32 +200,33 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
.encodeAuthMessage(groupId, timestamp, previousMsgId,
|
||||
sessionId, mac, signature);
|
||||
validator.validateMessage(m, group, clientHelper.toList(m));
|
||||
AuthMessage rm =
|
||||
AuthMessage am =
|
||||
messageParser.parseAuthMessage(m, clientHelper.toList(m));
|
||||
|
||||
assertEquals(m.getId(), rm.getMessageId());
|
||||
assertEquals(m.getGroupId(), rm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), rm.getTimestamp());
|
||||
assertEquals(previousMsgId, rm.getPreviousMessageId());
|
||||
assertEquals(sessionId, rm.getSessionId());
|
||||
assertArrayEquals(mac, rm.getMac());
|
||||
assertArrayEquals(signature, rm.getSignature());
|
||||
assertEquals(m.getId(), am.getMessageId());
|
||||
assertEquals(m.getGroupId(), am.getGroupId());
|
||||
assertEquals(m.getTimestamp(), am.getTimestamp());
|
||||
assertEquals(previousMsgId, am.getPreviousMessageId());
|
||||
assertEquals(sessionId, am.getSessionId());
|
||||
assertArrayEquals(mac, am.getMac());
|
||||
assertArrayEquals(signature, am.getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivateMessage() throws Exception {
|
||||
Message m = messageEncoder
|
||||
.encodeActivateMessage(groupId, timestamp, previousMsgId,
|
||||
sessionId);
|
||||
sessionId, mac);
|
||||
validator.validateMessage(m, group, clientHelper.toList(m));
|
||||
ActivateMessage rm =
|
||||
ActivateMessage am =
|
||||
messageParser.parseActivateMessage(m, clientHelper.toList(m));
|
||||
|
||||
assertEquals(m.getId(), rm.getMessageId());
|
||||
assertEquals(m.getGroupId(), rm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), rm.getTimestamp());
|
||||
assertEquals(previousMsgId, rm.getPreviousMessageId());
|
||||
assertEquals(sessionId, rm.getSessionId());
|
||||
assertEquals(m.getId(), am.getMessageId());
|
||||
assertEquals(m.getGroupId(), am.getGroupId());
|
||||
assertEquals(m.getTimestamp(), am.getTimestamp());
|
||||
assertEquals(previousMsgId, am.getPreviousMessageId());
|
||||
assertEquals(sessionId, am.getSessionId());
|
||||
assertArrayEquals(mac, am.getMac());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -234,14 +235,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
.encodeAbortMessage(groupId, timestamp, previousMsgId,
|
||||
sessionId);
|
||||
validator.validateMessage(m, group, clientHelper.toList(m));
|
||||
AbortMessage rm =
|
||||
AbortMessage am =
|
||||
messageParser.parseAbortMessage(m, clientHelper.toList(m));
|
||||
|
||||
assertEquals(m.getId(), rm.getMessageId());
|
||||
assertEquals(m.getGroupId(), rm.getGroupId());
|
||||
assertEquals(m.getTimestamp(), rm.getTimestamp());
|
||||
assertEquals(previousMsgId, rm.getPreviousMessageId());
|
||||
assertEquals(sessionId, rm.getSessionId());
|
||||
assertEquals(m.getId(), am.getMessageId());
|
||||
assertEquals(m.getGroupId(), am.getGroupId());
|
||||
assertEquals(m.getTimestamp(), am.getTimestamp());
|
||||
assertEquals(previousMsgId, am.getPreviousMessageId());
|
||||
assertEquals(sessionId, am.getSessionId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,15 +28,19 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
import static org.briarproject.briar.introduction.IntroduceeSession.Local;
|
||||
import static org.briarproject.briar.introduction.IntroduceeSession.Remote;
|
||||
import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED;
|
||||
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTHS;
|
||||
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE;
|
||||
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
|
||||
import static org.briarproject.briar.test.BriarTestUtils.getRealAuthor;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
|
||||
@@ -74,6 +78,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
private final Map<TransportId, TransportProperties>
|
||||
remoteTransportProperties = getTransportPropertiesMap(3);
|
||||
private final Map<TransportId, KeySetId> transportKeys = new HashMap<>();
|
||||
private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH);
|
||||
private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH);
|
||||
|
||||
public SessionEncoderParserIntegrationTest() {
|
||||
BriarIntegrationTestComponent component =
|
||||
@@ -82,8 +88,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
|
||||
sessionEncoder = new SessionEncoderImpl(clientHelper);
|
||||
sessionParser = new SessionParserImpl(clientHelper);
|
||||
author1 = getRealAuthor();
|
||||
author2 = getRealAuthor();
|
||||
author1 = getRealAuthor(authorFactory);
|
||||
author2 = getRealAuthor(authorFactory);
|
||||
transportKeys.put(getTransportId(), new KeySetId(1));
|
||||
transportKeys.put(getTransportId(), new KeySetId(2));
|
||||
transportKeys.put(getTransportId(), new KeySetId(3));
|
||||
@@ -167,48 +173,70 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
assertEquals(s1.getSessionId(), s2.getSessionId());
|
||||
assertEquals(groupId1, s1.getContactGroupId());
|
||||
assertEquals(s1.getContactGroupId(), s2.getContactGroupId());
|
||||
assertEquals(author1, s1.getIntroducer());
|
||||
assertEquals(s1.getIntroducer(), s2.getIntroducer());
|
||||
assertArrayEquals(masterKey, s1.getMasterKey());
|
||||
assertArrayEquals(s1.getMasterKey(), s2.getMasterKey());
|
||||
assertEquals(transportKeys, s1.getTransportKeys());
|
||||
assertEquals(s1.getTransportKeys(), s2.getTransportKeys());
|
||||
assertEquals(localTimestamp, s1.getLocalTimestamp());
|
||||
assertEquals(s1.getLocalTimestamp(), s2.getLocalTimestamp());
|
||||
assertEquals(lastLocalMessageId, s1.getLastLocalMessageId());
|
||||
assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId());
|
||||
assertEquals(lastRemoteMessageId, s1.getLastRemoteMessageId());
|
||||
assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId());
|
||||
assertEquals(author1, s1.getIntroducer());
|
||||
assertEquals(s1.getIntroducer(), s2.getIntroducer());
|
||||
assertEquals(author2, s1.getRemoteAuthor());
|
||||
assertEquals(s1.getRemoteAuthor(), s2.getRemoteAuthor());
|
||||
assertArrayEquals(ephemeralPublicKey, s1.getEphemeralPublicKey());
|
||||
assertArrayEquals(s1.getEphemeralPublicKey(),
|
||||
s2.getEphemeralPublicKey());
|
||||
assertArrayEquals(ephemeralPrivateKey, s1.getEphemeralPrivateKey());
|
||||
assertArrayEquals(s1.getEphemeralPrivateKey(),
|
||||
s2.getEphemeralPrivateKey());
|
||||
assertEquals(acceptTimestamp, s1.getAcceptTimestamp());
|
||||
assertEquals(s1.getAcceptTimestamp(), s2.getAcceptTimestamp());
|
||||
assertArrayEquals(masterKey, s1.getMasterKey());
|
||||
assertArrayEquals(s1.getMasterKey(), s2.getMasterKey());
|
||||
assertArrayEquals(remoteEphemeralPublicKey, s1.getRemotePublicKey());
|
||||
assertArrayEquals(s1.getRemotePublicKey(),
|
||||
s2.getRemotePublicKey());
|
||||
assertEquals(transportProperties, s1.getTransportProperties());
|
||||
assertEquals(s1.getTransportProperties(), s2.getTransportProperties());
|
||||
|
||||
// check local
|
||||
assertTrue(s1.getLocal().alice);
|
||||
assertEquals(s1.getLocal().alice, s2.getLocal().alice);
|
||||
assertEquals(lastLocalMessageId, s1.getLocal().lastMessageId);
|
||||
assertEquals(s1.getLocal().lastMessageId, s2.getLocal().lastMessageId);
|
||||
assertEquals(localTimestamp, s1.getLocal().lastMessageTimestamp);
|
||||
assertEquals(s1.getLocal().lastMessageTimestamp,
|
||||
s2.getLocal().lastMessageTimestamp);
|
||||
assertArrayEquals(ephemeralPublicKey, s1.getLocal().ephemeralPublicKey);
|
||||
assertArrayEquals(s1.getLocal().ephemeralPublicKey,
|
||||
s2.getLocal().ephemeralPublicKey);
|
||||
assertArrayEquals(ephemeralPrivateKey,
|
||||
s1.getLocal().ephemeralPrivateKey);
|
||||
assertArrayEquals(s1.getLocal().ephemeralPrivateKey,
|
||||
s2.getLocal().ephemeralPrivateKey);
|
||||
assertEquals(transportProperties, s1.getLocal().transportProperties);
|
||||
assertEquals(s1.getLocal().transportProperties,
|
||||
s2.getLocal().transportProperties);
|
||||
assertEquals(acceptTimestamp, s1.getLocal().acceptTimestamp);
|
||||
assertEquals(s1.getLocal().acceptTimestamp,
|
||||
s2.getLocal().acceptTimestamp);
|
||||
assertArrayEquals(localMacKey, s1.getLocal().macKey);
|
||||
assertArrayEquals(s1.getLocal().macKey, s2.getLocal().macKey);
|
||||
|
||||
// check remote
|
||||
assertFalse(s1.getRemote().alice);
|
||||
assertEquals(s1.getRemote().alice, s2.getRemote().alice);
|
||||
assertEquals(author2, s1.getRemote().author);
|
||||
assertEquals(s1.getRemote().author, s2.getRemote().author);
|
||||
assertEquals(lastRemoteMessageId, s1.getRemote().lastMessageId);
|
||||
assertEquals(s1.getRemote().lastMessageId,
|
||||
s2.getRemote().lastMessageId);
|
||||
assertArrayEquals(remoteEphemeralPublicKey,
|
||||
s1.getRemote().ephemeralPublicKey);
|
||||
assertArrayEquals(s1.getRemote().ephemeralPublicKey,
|
||||
s2.getRemote().ephemeralPublicKey);
|
||||
assertEquals(remoteTransportProperties,
|
||||
s1.getRemoteTransportProperties());
|
||||
assertEquals(s1.getRemoteTransportProperties(),
|
||||
s2.getRemoteTransportProperties());
|
||||
assertEquals(remoteAcceptTimestamp, s1.getRemoteAcceptTimestamp());
|
||||
assertEquals(s1.getRemoteAcceptTimestamp(), s2.getRemoteAcceptTimestamp());
|
||||
assertEquals(transportKeys, s1.getTransportKeys());
|
||||
assertEquals(s1.getTransportKeys(), s2.getTransportKeys());
|
||||
s1.getRemote().transportProperties);
|
||||
assertEquals(s1.getRemote().transportProperties,
|
||||
s2.getRemote().transportProperties);
|
||||
assertEquals(remoteAcceptTimestamp, s1.getRemote().acceptTimestamp);
|
||||
assertEquals(s1.getRemote().acceptTimestamp,
|
||||
s2.getRemote().acceptTimestamp);
|
||||
assertArrayEquals(remoteMacKey, s1.getRemote().macKey);
|
||||
assertArrayEquals(s1.getRemote().macKey, s2.getRemote().macKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntroduceeSessionWithNulls() throws FormatException {
|
||||
IntroduceeSession s1 =
|
||||
new IntroduceeSession(sessionId, LOCAL_ACCEPTED,
|
||||
requestTimestamp, groupId1, null, localTimestamp, null,
|
||||
author1, null, null, null, acceptTimestamp, null,
|
||||
author2, null, null, remoteAcceptTimestamp, null);
|
||||
IntroduceeSession s1 = IntroduceeSession
|
||||
.getInitial(groupId1, sessionId, author1, false, author2);
|
||||
|
||||
BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s1);
|
||||
IntroduceeSession s2 =
|
||||
@@ -218,14 +246,38 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId());
|
||||
assertNull(s1.getLastRemoteMessageId());
|
||||
assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId());
|
||||
assertNull(s1.getEphemeralPublicKey());
|
||||
assertArrayEquals(s1.getEphemeralPublicKey(),
|
||||
s2.getEphemeralPublicKey());
|
||||
assertNull(s1.getEphemeralPrivateKey());
|
||||
assertArrayEquals(s1.getEphemeralPrivateKey(),
|
||||
s2.getEphemeralPrivateKey());
|
||||
assertNull(s1.getMasterKey());
|
||||
assertEquals(s1.getMasterKey(), s2.getMasterKey());
|
||||
assertNull(s1.getTransportKeys());
|
||||
assertEquals(s1.getTransportKeys(), s2.getTransportKeys());
|
||||
|
||||
// check local
|
||||
assertNull(s1.getLocal().lastMessageId);
|
||||
assertEquals(s1.getLocal().lastMessageId, s2.getLocal().lastMessageId);
|
||||
assertNull(s1.getLocal().ephemeralPublicKey);
|
||||
assertEquals(s1.getLocal().ephemeralPublicKey,
|
||||
s2.getLocal().ephemeralPublicKey);
|
||||
assertNull(s1.getLocal().ephemeralPrivateKey);
|
||||
assertEquals(s1.getLocal().ephemeralPrivateKey,
|
||||
s2.getLocal().ephemeralPrivateKey);
|
||||
assertNull(s1.getLocal().transportProperties);
|
||||
assertEquals(s1.getLocal().transportProperties,
|
||||
s2.getLocal().transportProperties);
|
||||
assertNull(s1.getLocal().macKey);
|
||||
assertEquals(s1.getLocal().macKey, s2.getLocal().macKey);
|
||||
|
||||
// check remote
|
||||
assertNull(s1.getRemote().lastMessageId);
|
||||
assertEquals(s1.getRemote().lastMessageId,
|
||||
s2.getRemote().lastMessageId);
|
||||
assertNull(s1.getRemote().ephemeralPublicKey);
|
||||
assertEquals(s1.getRemote().ephemeralPublicKey,
|
||||
s2.getRemote().ephemeralPublicKey);
|
||||
assertNull(s1.getRemote().transportProperties);
|
||||
assertEquals(s1.getRemote().transportProperties,
|
||||
s2.getRemote().transportProperties);
|
||||
assertNull(s1.getRemote().macKey);
|
||||
assertEquals(s1.getRemote().macKey, s2.getRemote().macKey);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
@@ -256,13 +308,15 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
}
|
||||
|
||||
private IntroduceeSession getIntroduceeSession() {
|
||||
Local local = new Local(true, lastLocalMessageId, localTimestamp,
|
||||
ephemeralPublicKey, ephemeralPrivateKey, transportProperties,
|
||||
acceptTimestamp, localMacKey);
|
||||
Remote remote = new Remote(false, author2, lastRemoteMessageId,
|
||||
remoteEphemeralPublicKey, remoteTransportProperties,
|
||||
remoteAcceptTimestamp, remoteMacKey);
|
||||
return new IntroduceeSession(sessionId, LOCAL_ACCEPTED,
|
||||
requestTimestamp, groupId1, lastLocalMessageId, localTimestamp,
|
||||
lastRemoteMessageId, author1, ephemeralPublicKey,
|
||||
ephemeralPrivateKey, transportProperties, acceptTimestamp,
|
||||
masterKey, author2, remoteEphemeralPublicKey,
|
||||
remoteTransportProperties, remoteAcceptTimestamp,
|
||||
transportKeys);
|
||||
requestTimestamp, groupId1, author1, local, remote,
|
||||
masterKey, transportKeys);
|
||||
}
|
||||
|
||||
private void assertIntroduceeEquals(Introducee i1, Introducee i2) {
|
||||
@@ -273,9 +327,4 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
|
||||
assertEquals(i1.lastRemoteMessageId, i2.lastRemoteMessageId);
|
||||
}
|
||||
|
||||
private Author getRealAuthor() {
|
||||
return authorFactory.createAuthor(getRandomString(5),
|
||||
getRandomBytes(MAX_PUBLIC_KEY_LENGTH));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user